From a3572f3372c985403701bda82182983a6c7cabc5 Mon Sep 17 00:00:00 2001 From: Trashman247 Date: Mon, 19 Jun 2023 21:54:28 -0700 Subject: [PATCH 01/14] Implement VersionedGraphCollection to Brick module - Reworked `load_brick_file` and `new_brick_file` to fit under the VersionedGraphCollection implementation. (Other methods may have broken). - Added `undo_brick` and `redo_brick`. - Kept BrickStore.graph the same as to generally still work with the rest of the code. This was done by parsing the VersionedGraphCollection with the new `reload_brick_graph` method. --- src/blenderbim/blenderbim/tool/brick.py | 54 ++++++++++++++++--------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/src/blenderbim/blenderbim/tool/brick.py b/src/blenderbim/blenderbim/tool/brick.py index 61e498d861..4d4449865a 100644 --- a/src/blenderbim/blenderbim/tool/brick.py +++ b/src/blenderbim/blenderbim/tool/brick.py @@ -25,6 +25,7 @@ import blenderbim.tool as tool try: import brickschema + import brickschema.persistent import urllib.parse from rdflib import Literal, URIRef, Namespace from rdflib.namespace import RDF @@ -32,7 +33,6 @@ except: # See #1860 print("Warning: brickschema not available.") - class Brick(blenderbim.core.tool.Brick): @classmethod def add_brick(cls, namespace, brick_class): @@ -249,27 +249,29 @@ class Brick(blenderbim.core.tool.Brick): @classmethod def load_brick_file(cls, filepath): - if not BrickStore.schema: - BrickStore.schema = brickschema.Graph() + if not BrickStore.schema: # important check for running under test cases cwd = os.path.dirname(os.path.realpath(__file__)) - schema_path = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl") - BrickStore.schema.load_file(schema_path) - BrickStore.graph = brickschema.Graph().load_file(filepath) + BrickStore.schema + BrickStore.schema = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl") + BrickStore.VersionedGraphCollection = brickschema.persistent.VersionedGraphCollection("sqlite://") + with BrickStore.VersionedGraphCollection.new_changeset("schema") as cs: + cs.load_file(BrickStore.schema) + with BrickStore.VersionedGraphCollection.new_changeset("project") as cs: + cs.load_file(filepath) + BrickStore.reload_brick_graph() BrickStore.path = filepath @classmethod def new_brick_file(cls): - if not BrickStore.schema: - BrickStore.schema = brickschema.Graph() - #BrickStore.schema = brickschema.persistent.VersionedGraphCollection("sqlite://") + if not BrickStore.schema: # important check for running under test cases cwd = os.path.dirname(os.path.realpath(__file__)) - schema_path = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl") - BrickStore.schema.load_file(schema_path) - #BrickStore.schema.load_graph(schema_path) - BrickStore.graph = brickschema.Graph() + BrickStore.schema - BrickStore.graph.bind("digitaltwin", Namespace("https://example.org/digitaltwin#")) - BrickStore.graph.bind("brick", Namespace("https://brickschema.org/schema/Brick#")) - BrickStore.graph.bind("rdfs", Namespace("http://www.w3.org/2000/01/rdf-schema#")) + BrickStore.schema = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl") + BrickStore.VersionedGraphCollection = brickschema.persistent.VersionedGraphCollection("sqlite://") + with BrickStore.VersionedGraphCollection.new_changeset("schema") as cs: + cs.load_file(BrickStore.schema) + BrickStore.VersionedGraphCollection.bind("digitaltwin", Namespace("https://example.org/digitaltwin#")) + BrickStore.VersionedGraphCollection.bind("brick", Namespace("https://brickschema.org/schema/Brick#")) + BrickStore.VersionedGraphCollection.bind("rdfs", Namespace("http://www.w3.org/2000/01/rdf-schema#")) + BrickStore.reload_brick_graph() @classmethod def pop_brick_breadcrumb(cls): @@ -308,10 +310,22 @@ class Brick(blenderbim.core.tool.Brick): def set_active_brick_class(cls, brick_class): bpy.context.scene.BIMBrickProperties.active_brick_class = brick_class + @classmethod + def undo_brick(cls): + BrickStore.VersionedGraphCollection.undo() + BrickStore.reload_brick_graph() + + @classmethod + def redo_brick(cls): + BrickStore.VersionedGraphCollection.redo() + BrickStore.reload_brick_graph() class BrickStore: - schema = None - graph = None + schema = None # this is now a path + # I've decided to arbitrarily split th VersionedGraphCollection into two graph names: "schema" and "project" + # "schema" holds the Brick.ttl metadata; "project" holds all the authored entities + VersionedGraphCollection = None + graph = None # this is the graph named "project" from the VersionedGraphCollection path = None @staticmethod @@ -319,3 +333,7 @@ class BrickStore: BrickStore.schema = None BrickStore.graph = None BrickStore.path = None + + @classmethod + def reload_brick_graph(cls): + BrickStore.graph = BrickStore.VersionedGraphCollection.graph_at("project") \ No newline at end of file From bcf5f07718ee418d989feb65cadd61c1289bc0ce Mon Sep 17 00:00:00 2001 From: Trashman247 Date: Mon, 19 Jun 2023 21:59:17 -0700 Subject: [PATCH 02/14] Rework NewBrick and LoadBrick in test_brick.py to fit with new VGC format - VGC means VersionedGraphCollection. - BrickStore.schema is now a filepath, so make that the case in the testing also. --- src/blenderbim/test/tool/test_brick.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/blenderbim/test/tool/test_brick.py b/src/blenderbim/test/tool/test_brick.py index 1fc2a9b962..14687ce694 100644 --- a/src/blenderbim/test/tool/test_brick.py +++ b/src/blenderbim/test/tool/test_brick.py @@ -307,10 +307,8 @@ class TestImportBrickItems(NewFile): class TestLoadBrickFile(NewFile): def test_run(self): # We stub the schema to make tests run faster - BrickStore.schema = brickschema.Graph() cwd = os.path.dirname(os.path.realpath(__file__)) - schema_path = os.path.join(cwd, "..", "files", "BrickStub.ttl") - BrickStore.schema.load_file(schema_path) + BrickStore.schema = os.path.join(cwd, "..", "files", "BrickStub.ttl") # This is the actual test cwd = os.path.dirname(os.path.realpath(__file__)) @@ -322,10 +320,8 @@ class TestLoadBrickFile(NewFile): class TestNewBrickFile(NewFile): def test_run(self): # We stub the schema to make tests run faster - BrickStore.schema = brickschema.Graph() cwd = os.path.dirname(os.path.realpath(__file__)) - schema_path = os.path.join(cwd, "..", "files", "BrickStub.ttl") - BrickStore.schema.load_file(schema_path) + BrickStore.schema = os.path.join(cwd, "..", "files", "BrickStub.ttl") # This is the actual test subject.new_brick_file() From 046ce2b8e7cd4efd5d2b9f7f0bd996a23481ebfb Mon Sep 17 00:00:00 2001 From: Trashman247 Date: Fri, 23 Jun 2023 16:55:34 -0700 Subject: [PATCH 03/14] Update BrickStore.purge() I wanted to just have a BrickStore.clear() which would so this: BrickStore.VersionedGraphCollection = None BrickStore.graph = None BrickStore.path = None (aka not also set BrickStore.schema = None, since it should theoretically just load in the same path anyway) but for some reason Blender crashes when clearing a project and loading one again this way. --- src/blenderbim/blenderbim/tool/brick.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/blenderbim/blenderbim/tool/brick.py b/src/blenderbim/blenderbim/tool/brick.py index 4d4449865a..fb7d645dd7 100644 --- a/src/blenderbim/blenderbim/tool/brick.py +++ b/src/blenderbim/blenderbim/tool/brick.py @@ -100,7 +100,7 @@ class Brick(blenderbim.core.tool.Brick): @classmethod def clear_project(cls): - BrickStore.graph = None + BrickStore.purge() bpy.context.scene.BIMBrickProperties.active_brick_class == "" bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.clear() @@ -331,8 +331,9 @@ class BrickStore: @staticmethod def purge(): BrickStore.schema = None + BrickStore.VersionedGraphCollection = None BrickStore.graph = None - BrickStore.path = None + BrickStore.path = None @classmethod def reload_brick_graph(cls): From e177f5f0511801f65822fd122e76af053c78f4ac Mon Sep 17 00:00:00 2001 From: Trashman247 Date: Sun, 25 Jun 2023 23:20:56 -0700 Subject: [PATCH 04/14] Add Brick.ttl to .gitignore --- src/blenderbim/blenderbim/bim/.gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/blenderbim/blenderbim/bim/.gitignore b/src/blenderbim/blenderbim/bim/.gitignore index 4b1304fd48..bc8a4d8df1 100644 --- a/src/blenderbim/blenderbim/bim/.gitignore +++ b/src/blenderbim/blenderbim/bim/.gitignore @@ -1,2 +1,3 @@ # addon writes tmp stuff directly to its dir -/data/ \ No newline at end of file +/data/ +/schema/Brick.ttl \ No newline at end of file From 580f8f6218ff45a78c497a8c3a67fadde02f809d Mon Sep 17 00:00:00 2001 From: Trashman247 Date: Sun, 25 Jun 2023 23:21:27 -0700 Subject: [PATCH 05/14] Change graph naming to all caps --- src/blenderbim/blenderbim/tool/brick.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/blenderbim/blenderbim/tool/brick.py b/src/blenderbim/blenderbim/tool/brick.py index fb7d645dd7..8df69726a4 100644 --- a/src/blenderbim/blenderbim/tool/brick.py +++ b/src/blenderbim/blenderbim/tool/brick.py @@ -253,9 +253,9 @@ class Brick(blenderbim.core.tool.Brick): cwd = os.path.dirname(os.path.realpath(__file__)) BrickStore.schema = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl") BrickStore.VersionedGraphCollection = brickschema.persistent.VersionedGraphCollection("sqlite://") - with BrickStore.VersionedGraphCollection.new_changeset("schema") as cs: + with BrickStore.VersionedGraphCollection.new_changeset("SCHEMA") as cs: cs.load_file(BrickStore.schema) - with BrickStore.VersionedGraphCollection.new_changeset("project") as cs: + with BrickStore.VersionedGraphCollection.new_changeset("PROJECT") as cs: cs.load_file(filepath) BrickStore.reload_brick_graph() BrickStore.path = filepath @@ -266,7 +266,7 @@ class Brick(blenderbim.core.tool.Brick): cwd = os.path.dirname(os.path.realpath(__file__)) BrickStore.schema = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl") BrickStore.VersionedGraphCollection = brickschema.persistent.VersionedGraphCollection("sqlite://") - with BrickStore.VersionedGraphCollection.new_changeset("schema") as cs: + with BrickStore.VersionedGraphCollection.new_changeset("SCHEMA") as cs: cs.load_file(BrickStore.schema) BrickStore.VersionedGraphCollection.bind("digitaltwin", Namespace("https://example.org/digitaltwin#")) BrickStore.VersionedGraphCollection.bind("brick", Namespace("https://brickschema.org/schema/Brick#")) @@ -320,6 +320,7 @@ class Brick(blenderbim.core.tool.Brick): BrickStore.VersionedGraphCollection.redo() BrickStore.reload_brick_graph() + class BrickStore: schema = None # this is now a path # I've decided to arbitrarily split th VersionedGraphCollection into two graph names: "schema" and "project" @@ -337,4 +338,4 @@ class BrickStore: @classmethod def reload_brick_graph(cls): - BrickStore.graph = BrickStore.VersionedGraphCollection.graph_at("project") \ No newline at end of file + BrickStore.graph = BrickStore.VersionedGraphCollection.graph_at("PROJECT") \ No newline at end of file From d9196882dcc9efafe5edefade5eeef6a39e930a2 Mon Sep 17 00:00:00 2001 From: Trashman247 Date: Sun, 25 Jun 2023 23:56:15 -0700 Subject: [PATCH 06/14] Implement early testing for serialize operator (not functional) All the right code seems to be in place, but it seems the package won't go through with the serialize function because of read/write permissions (ERRNO 13) --- src/blenderbim/blenderbim/bim/module/brick/__init__.py | 1 + src/blenderbim/blenderbim/bim/module/brick/operator.py | 7 +++++++ src/blenderbim/blenderbim/bim/module/brick/ui.py | 3 +++ src/blenderbim/blenderbim/core/brick.py | 3 +++ src/blenderbim/blenderbim/tool/brick.py | 6 ++++++ 5 files changed, 20 insertions(+) diff --git a/src/blenderbim/blenderbim/bim/module/brick/__init__.py b/src/blenderbim/blenderbim/bim/module/brick/__init__.py index 5e0afa989a..0bff9e01e6 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/brick/__init__.py @@ -33,6 +33,7 @@ classes = ( operator.RewindBrickClass, operator.ViewBrickClass, operator.ViewBrickItem, + operator.SerializeBrick, prop.Brick, prop.BIMBrickProperties, ui.BIM_PT_brickschema, diff --git a/src/blenderbim/blenderbim/bim/module/brick/operator.py b/src/blenderbim/blenderbim/bim/module/brick/operator.py index 33d877ebd1..1aa40303a2 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/operator.py +++ b/src/blenderbim/blenderbim/bim/module/brick/operator.py @@ -189,3 +189,10 @@ class RemoveBrick(bpy.types.Operator, Operator): library=tool.Ifc.get().by_id(int(props.libraries)) if props.libraries else None, brick_uri=props.bricks[props.active_brick_index].uri, ) + +class SerializeBrick(bpy.types.Operator, Operator): + bl_idname = "bim.serialize_brick" + bl_label = "Serialize Brick" + + def _execute(self, context): + core.serialize_brick(tool.Brick) \ No newline at end of file diff --git a/src/blenderbim/blenderbim/bim/module/brick/ui.py b/src/blenderbim/blenderbim/bim/module/brick/ui.py index 568c5a4ab5..2d58de6758 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/ui.py +++ b/src/blenderbim/blenderbim/bim/module/brick/ui.py @@ -58,6 +58,9 @@ class BIM_PT_brickschema(Panel): row.operator("bim.add_brick_feed", text="", icon="PLUGIN") row.operator("bim.remove_brick", text="", icon="X") + row = self.layout.row(align=True) + row.operator("bim.serialize_brick") + self.layout.template_list("BIM_UL_bricks", "", self.props, "bricks", self.props, "active_brick_index") for attribute in BrickschemaData.data["attributes"]: diff --git a/src/blenderbim/blenderbim/core/brick.py b/src/blenderbim/blenderbim/core/brick.py index d4df98654e..93fe475bb2 100644 --- a/src/blenderbim/blenderbim/core/brick.py +++ b/src/blenderbim/blenderbim/core/brick.py @@ -109,3 +109,6 @@ def remove_brick(ifc, brick, library=None, brick_uri=None): ifc.run("library.remove_reference", reference=reference) brick.remove_brick(brick_uri) brick.run_refresh_brick_viewer() + +def serialize_brick(brick, file_name="BlenderBIMSerializeTest.ttl"): + brick.serialize_brick(file_name) \ No newline at end of file diff --git a/src/blenderbim/blenderbim/tool/brick.py b/src/blenderbim/blenderbim/tool/brick.py index 8df69726a4..2ccc5433cc 100644 --- a/src/blenderbim/blenderbim/tool/brick.py +++ b/src/blenderbim/blenderbim/tool/brick.py @@ -320,6 +320,12 @@ class Brick(blenderbim.core.tool.Brick): BrickStore.VersionedGraphCollection.redo() BrickStore.reload_brick_graph() + @classmethod + def serialize_brick(cls, file_name): + BrickStore.reload_brick_graph() + print("Serializing: \"" + file_name + "\" ... ") + BrickStore.graph.serialize(file_name) + print("finished!") class BrickStore: schema = None # this is now a path From 81a4ff711cb9cfd4b3ab313ac87532391c56f560 Mon Sep 17 00:00:00 2001 From: Trashman247 Date: Mon, 26 Jun 2023 13:59:28 -0700 Subject: [PATCH 07/14] Implement fully serialize operator - Turns out, you need the keyword "graph=" in graph_at() to actually select a graph of that name from the collection, otherwise it just returns the entire collection, so I changed that, which correctly isolates the project from the collection for serialization now. - With this same change, I opted turn BrickStore.VersionedGraphCollection simply into BrickStore.graph and create a new BrickStore.get_project() to return the isolated graph. - This meant I should remove the reload_graph() function because I was actually just loading the entire collection into it still, and its functionality breaks when it isn't the entire collection --- src/blenderbim/blenderbim/tool/brick.py | 45 ++++++++++++------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/blenderbim/blenderbim/tool/brick.py b/src/blenderbim/blenderbim/tool/brick.py index 2ccc5433cc..d09d5fd84d 100644 --- a/src/blenderbim/blenderbim/tool/brick.py +++ b/src/blenderbim/blenderbim/tool/brick.py @@ -252,12 +252,11 @@ class Brick(blenderbim.core.tool.Brick): if not BrickStore.schema: # important check for running under test cases cwd = os.path.dirname(os.path.realpath(__file__)) BrickStore.schema = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl") - BrickStore.VersionedGraphCollection = brickschema.persistent.VersionedGraphCollection("sqlite://") - with BrickStore.VersionedGraphCollection.new_changeset("SCHEMA") as cs: + BrickStore.graph = brickschema.persistent.VersionedGraphCollection("sqlite://") + with BrickStore.graph.new_changeset("SCHEMA") as cs: cs.load_file(BrickStore.schema) - with BrickStore.VersionedGraphCollection.new_changeset("PROJECT") as cs: + with BrickStore.graph.new_changeset("PROJECT") as cs: cs.load_file(filepath) - BrickStore.reload_brick_graph() BrickStore.path = filepath @classmethod @@ -265,13 +264,12 @@ class Brick(blenderbim.core.tool.Brick): if not BrickStore.schema: # important check for running under test cases cwd = os.path.dirname(os.path.realpath(__file__)) BrickStore.schema = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl") - BrickStore.VersionedGraphCollection = brickschema.persistent.VersionedGraphCollection("sqlite://") - with BrickStore.VersionedGraphCollection.new_changeset("SCHEMA") as cs: + BrickStore.graph = brickschema.persistent.VersionedGraphCollection("sqlite://") + with BrickStore.graph.new_changeset("SCHEMA") as cs: cs.load_file(BrickStore.schema) - BrickStore.VersionedGraphCollection.bind("digitaltwin", Namespace("https://example.org/digitaltwin#")) - BrickStore.VersionedGraphCollection.bind("brick", Namespace("https://brickschema.org/schema/Brick#")) - BrickStore.VersionedGraphCollection.bind("rdfs", Namespace("http://www.w3.org/2000/01/rdf-schema#")) - BrickStore.reload_brick_graph() + BrickStore.graph.bind("digitaltwin", Namespace("https://example.org/digitaltwin#")) + BrickStore.graph.bind("brick", Namespace("https://brickschema.org/schema/Brick#")) + BrickStore.graph.bind("rdfs", Namespace("http://www.w3.org/2000/01/rdf-schema#")) @classmethod def pop_brick_breadcrumb(cls): @@ -312,36 +310,35 @@ class Brick(blenderbim.core.tool.Brick): @classmethod def undo_brick(cls): - BrickStore.VersionedGraphCollection.undo() - BrickStore.reload_brick_graph() + BrickStore.graph.undo() @classmethod def redo_brick(cls): - BrickStore.VersionedGraphCollection.redo() - BrickStore.reload_brick_graph() + BrickStore.graph.redo() @classmethod def serialize_brick(cls, file_name): - BrickStore.reload_brick_graph() + #temporary file path, could either be user selected for "save as" or use the BrickStore.path for simply "save" print("Serializing: \"" + file_name + "\" ... ") - BrickStore.graph.serialize(file_name) + cwd = os.path.dirname(os.path.realpath(__file__)) + dest = os.path.join(cwd, "..", "bim", "schema", file_name) + BrickStore.get_project().serialize(destination=dest, format="turtle") print("finished!") class BrickStore: - schema = None # this is now a path - # I've decided to arbitrarily split th VersionedGraphCollection into two graph names: "schema" and "project" - # "schema" holds the Brick.ttl metadata; "project" holds all the authored entities - VersionedGraphCollection = None - graph = None # this is the graph named "project" from the VersionedGraphCollection + schema = None # this is now a os path + graph = None # this is the VersionedGraphCollection with 2 arbitrarily named graphs: "schema" and "project" + # "schema" holds the Brick.ttl metadata; "project" holds all the authored entities + project = None # this is the graph named "project" from the VersionedGraphCollection path = None @staticmethod def purge(): BrickStore.schema = None - BrickStore.VersionedGraphCollection = None BrickStore.graph = None + BrickStore.project = None BrickStore.path = None @classmethod - def reload_brick_graph(cls): - BrickStore.graph = BrickStore.VersionedGraphCollection.graph_at("PROJECT") \ No newline at end of file + def get_project(cls): + return BrickStore.graph.graph_at(graph="PROJECT") \ No newline at end of file From 8341931a62156c85ff6719e1dfd25a7cf95b04d6 Mon Sep 17 00:00:00 2001 From: Trashman247 Date: Mon, 26 Jun 2023 16:01:26 -0700 Subject: [PATCH 08/14] Reformat commenting, remove prints, and remove BrickStore.project --- src/blenderbim/blenderbim/tool/brick.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/blenderbim/blenderbim/tool/brick.py b/src/blenderbim/blenderbim/tool/brick.py index d09d5fd84d..348fb33467 100644 --- a/src/blenderbim/blenderbim/tool/brick.py +++ b/src/blenderbim/blenderbim/tool/brick.py @@ -319,24 +319,21 @@ class Brick(blenderbim.core.tool.Brick): @classmethod def serialize_brick(cls, file_name): #temporary file path, could either be user selected for "save as" or use the BrickStore.path for simply "save" - print("Serializing: \"" + file_name + "\" ... ") cwd = os.path.dirname(os.path.realpath(__file__)) dest = os.path.join(cwd, "..", "bim", "schema", file_name) BrickStore.get_project().serialize(destination=dest, format="turtle") - print("finished!") class BrickStore: schema = None # this is now a os path - graph = None # this is the VersionedGraphCollection with 2 arbitrarily named graphs: "schema" and "project" - # "schema" holds the Brick.ttl metadata; "project" holds all the authored entities - project = None # this is the graph named "project" from the VersionedGraphCollection - path = None + path = None # file path if the project was loaded in + graph = None # this is the VersionedGraphCollection with 2 arbitrarily named graphs: "schema" and "project" + # "SCHEMA" holds the Brick.ttl metadata; "PROJECT" holds all the authored entities + @staticmethod def purge(): BrickStore.schema = None BrickStore.graph = None - BrickStore.project = None BrickStore.path = None @classmethod From 9d84172f15538cc16a8e6b82a691253c89769cc6 Mon Sep 17 00:00:00 2001 From: Trashman247 Date: Mon, 26 Jun 2023 23:16:52 -0700 Subject: [PATCH 09/14] Add changeset versioning to Brick add/remove --- src/blenderbim/blenderbim/tool/brick.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/blenderbim/blenderbim/tool/brick.py b/src/blenderbim/blenderbim/tool/brick.py index 348fb33467..ea95ab8eff 100644 --- a/src/blenderbim/blenderbim/tool/brick.py +++ b/src/blenderbim/blenderbim/tool/brick.py @@ -38,8 +38,9 @@ class Brick(blenderbim.core.tool.Brick): def add_brick(cls, namespace, brick_class): ns = Namespace(namespace) brick = ns[ifcopenshell.guid.expand(ifcopenshell.guid.new())] - BrickStore.graph.add((brick, RDF.type, URIRef(brick_class))) - BrickStore.graph.add((brick, URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal("Unnamed"))) + with BrickStore.graph.new_changeset("PROJECT") as cs: + cs.add((brick, RDF.type, URIRef(brick_class))) + cs.add((brick, URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal("Unnamed"))) return str(brick) @classmethod @@ -281,8 +282,9 @@ class Brick(blenderbim.core.tool.Brick): @classmethod def remove_brick(cls, brick_uri): - for triple in BrickStore.graph.triples((URIRef(brick_uri), None, None)): - BrickStore.graph.remove(triple) + with BrickStore.graph.new_changeset("PROJECT") as cs: + for triple in BrickStore.graph.triples((URIRef(brick_uri), None, None)): + cs.remove(triple) @classmethod def run_assign_brick_reference(cls, element=None, library=None, brick_uri=None): @@ -329,7 +331,6 @@ class BrickStore: graph = None # this is the VersionedGraphCollection with 2 arbitrarily named graphs: "schema" and "project" # "SCHEMA" holds the Brick.ttl metadata; "PROJECT" holds all the authored entities - @staticmethod def purge(): BrickStore.schema = None From 2ce32c6521c88ec60769a72a52e1fc73ec3f7d98 Mon Sep 17 00:00:00 2001 From: Trashman247 Date: Mon, 26 Jun 2023 23:17:11 -0700 Subject: [PATCH 10/14] Change namespace selector to only show alias --- src/blenderbim/blenderbim/bim/module/brick/data.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/blenderbim/blenderbim/bim/module/brick/data.py b/src/blenderbim/blenderbim/bim/module/brick/data.py index 072f9b2f70..bb8ba06089 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/data.py +++ b/src/blenderbim/blenderbim/bim/module/brick/data.py @@ -110,7 +110,8 @@ class BrickschemaData: return [] results = [] for alias, uri in BrickStore.graph.namespaces(): - results.append((uri, f"{alias}: {uri}", "")) + # results.append((uri, f"{alias}: {uri}", "")) + results.append((uri, f"{alias}", "")) return results @classmethod From 37e4f988574fb90f0cce5448bef5504af0203864 Mon Sep 17 00:00:00 2001 From: Trashman247 Date: Tue, 27 Jun 2023 13:21:44 -0700 Subject: [PATCH 11/14] Implement fully undo/redo with checks While these actions are short in the backend--taking about 0.01 seconds to run--the Blender UI lags a lot leading to 2-3 second pauses because of the "refresh_brick_viewer" function being slow. This should be investigated. --- .../blenderbim/bim/module/brick/__init__.py | 2 ++ .../blenderbim/bim/module/brick/operator.py | 14 ++++++++++++++ .../blenderbim/bim/module/brick/ui.py | 4 ++++ src/blenderbim/blenderbim/core/brick.py | 8 ++++++++ src/blenderbim/blenderbim/tool/brick.py | 17 ++++++++++++----- 5 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/brick/__init__.py b/src/blenderbim/blenderbim/bim/module/brick/__init__.py index 0bff9e01e6..744e679dab 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/brick/__init__.py @@ -33,6 +33,8 @@ classes = ( operator.RewindBrickClass, operator.ViewBrickClass, operator.ViewBrickItem, + operator.UndoBrick, + operator.RedoBrick, operator.SerializeBrick, prop.Brick, prop.BIMBrickProperties, diff --git a/src/blenderbim/blenderbim/bim/module/brick/operator.py b/src/blenderbim/blenderbim/bim/module/brick/operator.py index 1aa40303a2..72ef846c87 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/operator.py +++ b/src/blenderbim/blenderbim/bim/module/brick/operator.py @@ -190,6 +190,20 @@ class RemoveBrick(bpy.types.Operator, Operator): brick_uri=props.bricks[props.active_brick_index].uri, ) +class UndoBrick(bpy.types.Operator, Operator): + bl_idname = "bim.undo_brick" + bl_label = "Undo Brick" + + def _execute(self, context): + core.undo_brick(tool.Brick) + +class RedoBrick(bpy.types.Operator, Operator): + bl_idname = "bim.redo_brick" + bl_label = "Redo Brick" + + def _execute(self, context): + core.redo_brick(tool.Brick) + class SerializeBrick(bpy.types.Operator, Operator): bl_idname = "bim.serialize_brick" bl_label = "Serialize Brick" diff --git a/src/blenderbim/blenderbim/bim/module/brick/ui.py b/src/blenderbim/blenderbim/bim/module/brick/ui.py index 2d58de6758..717ee3eb12 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/ui.py +++ b/src/blenderbim/blenderbim/bim/module/brick/ui.py @@ -58,6 +58,10 @@ class BIM_PT_brickschema(Panel): row.operator("bim.add_brick_feed", text="", icon="PLUGIN") row.operator("bim.remove_brick", text="", icon="X") + row = self.layout.row(align=True) + row.operator("bim.undo_brick", icon="LOOP_BACK") + row.operator("bim.redo_brick", icon="LOOP_FORWARDS") + row = self.layout.row(align=True) row.operator("bim.serialize_brick") diff --git a/src/blenderbim/blenderbim/core/brick.py b/src/blenderbim/blenderbim/core/brick.py index 93fe475bb2..cd7fafaed0 100644 --- a/src/blenderbim/blenderbim/core/brick.py +++ b/src/blenderbim/blenderbim/core/brick.py @@ -110,5 +110,13 @@ def remove_brick(ifc, brick, library=None, brick_uri=None): brick.remove_brick(brick_uri) brick.run_refresh_brick_viewer() +def undo_brick(brick): + brick.undo_brick() + brick.run_refresh_brick_viewer() + +def redo_brick(brick): + brick.redo_brick() + brick.run_refresh_brick_viewer() + def serialize_brick(brick, file_name="BlenderBIMSerializeTest.ttl"): brick.serialize_brick(file_name) \ No newline at end of file diff --git a/src/blenderbim/blenderbim/tool/brick.py b/src/blenderbim/blenderbim/tool/brick.py index ea95ab8eff..608a87ddb1 100644 --- a/src/blenderbim/blenderbim/tool/brick.py +++ b/src/blenderbim/blenderbim/tool/brick.py @@ -282,9 +282,10 @@ class Brick(blenderbim.core.tool.Brick): @classmethod def remove_brick(cls, brick_uri): - with BrickStore.graph.new_changeset("PROJECT") as cs: - for triple in BrickStore.graph.triples((URIRef(brick_uri), None, None)): - cs.remove(triple) + if(BrickStore.graph.triples((URIRef(brick_uri), None, None))): + with BrickStore.graph.new_changeset("PROJECT") as cs: + for triple in BrickStore.graph.triples((URIRef(brick_uri), None, None)): + cs.remove(triple) @classmethod def run_assign_brick_reference(cls, element=None, library=None, brick_uri=None): @@ -312,11 +313,17 @@ class Brick(blenderbim.core.tool.Brick): @classmethod def undo_brick(cls): - BrickStore.graph.undo() + if(len(BrickStore.graph.versions()) > 1): + BrickStore.graph.undo() @classmethod def redo_brick(cls): - BrickStore.graph.redo() + with BrickStore.graph.conn() as conn: + redo_record = conn.execute( + "SELECT * from redos " "ORDER BY timestamp ASC LIMIT 1" + ).fetchone() + if redo_record is not None: + BrickStore.graph.redo() @classmethod def serialize_brick(cls, file_name): From a34b8d06ec21a467585f10665a39c9274c152fca Mon Sep 17 00:00:00 2001 From: Trashman247 Date: Thu, 29 Jun 2023 23:42:00 -0700 Subject: [PATCH 12/14] Silence known rdflib_sqlalchemy TypeError warning --- src/blenderbim/blenderbim/tool/brick.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/blenderbim/blenderbim/tool/brick.py b/src/blenderbim/blenderbim/tool/brick.py index 608a87ddb1..b4539c64aa 100644 --- a/src/blenderbim/blenderbim/tool/brick.py +++ b/src/blenderbim/blenderbim/tool/brick.py @@ -33,6 +33,12 @@ except: # See #1860 print("Warning: brickschema not available.") +# silence known rdflib_sqlalchemy TypeError warning +# see https://github.com/BrickSchema/Brick/issues/513#issuecomment-1558493675 +import logging +logger = logging.getLogger("rdflib") +logger.setLevel(logging.ERROR) + class Brick(blenderbim.core.tool.Brick): @classmethod def add_brick(cls, namespace, brick_class): From 01da8498f289c003f75c43d53fcfccfd483783c0 Mon Sep 17 00:00:00 2001 From: Trashman247 Date: Thu, 29 Jun 2023 23:56:20 -0700 Subject: [PATCH 13/14] Move Brick.ttl ignore to main git-ignore file --- .gitignore | 3 +++ src/blenderbim/blenderbim/bim/.gitignore | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 806fbe7bfd..2a4cd8f419 100644 --- a/.gitignore +++ b/.gitignore @@ -92,3 +92,6 @@ src/blenderbim/layouts # ifcopenshell swig and compiled files src/ifcopenshell-python/ifcopenshell/_ifcopenshell_wrapper.so src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py + +# Brickschema +src/blenderbim/blenderbim/bim/schema/Brick.ttl \ No newline at end of file diff --git a/src/blenderbim/blenderbim/bim/.gitignore b/src/blenderbim/blenderbim/bim/.gitignore index bc8a4d8df1..4b1304fd48 100644 --- a/src/blenderbim/blenderbim/bim/.gitignore +++ b/src/blenderbim/blenderbim/bim/.gitignore @@ -1,3 +1,2 @@ # addon writes tmp stuff directly to its dir -/data/ -/schema/Brick.ttl \ No newline at end of file +/data/ \ No newline at end of file From bd8afabce3dc117bcc50af32b0952a4212d41942 Mon Sep 17 00:00:00 2001 From: Trashman247 Date: Fri, 30 Jun 2023 00:03:46 -0700 Subject: [PATCH 14/14] Resolve .git-ignore file conflict --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 2a4cd8f419..247d590e6f 100644 --- a/.gitignore +++ b/.gitignore @@ -93,5 +93,8 @@ src/blenderbim/layouts src/ifcopenshell-python/ifcopenshell/_ifcopenshell_wrapper.so src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py +# apple +.DS_Store + # Brickschema src/blenderbim/blenderbim/bim/schema/Brick.ttl \ No newline at end of file