2525
2626try :
2727 import brickschema
28+ import brickschema .persistent
2829 import urllib .parse
2930 from rdflib import Literal , URIRef , Namespace
3031 from rdflib .namespace import RDF
3132except :
3233 # See #1860
3334 print ("Warning: brickschema not available." )
3435
36+ # silence known rdflib_sqlalchemy TypeError warning
37+ # see https://github.com/BrickSchema/Brick/issues/513#issuecomment-1558493675
38+ import logging
39+ logger = logging .getLogger ("rdflib" )
40+ logger .setLevel (logging .ERROR )
3541
3642class Brick (blenderbim .core .tool .Brick ):
3743 @classmethod
3844 def add_brick (cls , namespace , brick_class ):
3945 ns = Namespace (namespace )
4046 brick = ns [ifcopenshell .guid .expand (ifcopenshell .guid .new ())]
41- BrickStore .graph .add ((brick , RDF .type , URIRef (brick_class )))
42- BrickStore .graph .add ((brick , URIRef ("http://www.w3.org/2000/01/rdf-schema#label" ), Literal ("Unnamed" )))
47+ with BrickStore .graph .new_changeset ("PROJECT" ) as cs :
48+ cs .add ((brick , RDF .type , URIRef (brick_class )))
49+ cs .add ((brick , URIRef ("http://www.w3.org/2000/01/rdf-schema#label" ), Literal ("Unnamed" )))
4350 return str (brick )
4451
4552 @classmethod
@@ -100,7 +107,7 @@ def clear_brick_browser(cls):
100107
101108 @classmethod
102109 def clear_project (cls ):
103- BrickStore .graph = None
110+ BrickStore .purge ()
104111 bpy .context .scene .BIMBrickProperties .active_brick_class == ""
105112 bpy .context .scene .BIMBrickProperties .brick_breadcrumbs .clear ()
106113
@@ -249,24 +256,24 @@ def import_brick_items(cls, brick_class):
249256
250257 @classmethod
251258 def load_brick_file (cls , filepath ):
252- if not BrickStore .schema :
253- BrickStore .schema = brickschema .Graph ()
259+ if not BrickStore .schema : # important check for running under test cases
254260 cwd = os .path .dirname (os .path .realpath (__file__ ))
255- schema_path = os .path .join (cwd , ".." , "bim" , "schema" , "Brick.ttl" )
256- BrickStore .schema .load_file (schema_path )
257- BrickStore .graph = brickschema .Graph ().load_file (filepath ) + BrickStore .schema
261+ BrickStore .schema = os .path .join (cwd , ".." , "bim" , "schema" , "Brick.ttl" )
262+ BrickStore .graph = brickschema .persistent .VersionedGraphCollection ("sqlite://" )
263+ with BrickStore .graph .new_changeset ("SCHEMA" ) as cs :
264+ cs .load_file (BrickStore .schema )
265+ with BrickStore .graph .new_changeset ("PROJECT" ) as cs :
266+ cs .load_file (filepath )
258267 BrickStore .path = filepath
259268
260269 @classmethod
261270 def new_brick_file (cls ):
262- if not BrickStore .schema :
263- BrickStore .schema = brickschema .Graph ()
264- #BrickStore.schema = brickschema.persistent.VersionedGraphCollection("sqlite://")
271+ if not BrickStore .schema : # important check for running under test cases
265272 cwd = os .path .dirname (os .path .realpath (__file__ ))
266- schema_path = os .path .join (cwd , ".." , "bim" , "schema" , "Brick.ttl" )
267- BrickStore . schema . load_file ( schema_path )
268- # BrickStore.schema.load_graph(schema_path)
269- BrickStore . graph = brickschema . Graph () + BrickStore .schema
273+ BrickStore . schema = os .path .join (cwd , ".." , "bim" , "schema" , "Brick.ttl" )
274+ BrickStore . graph = brickschema . persistent . VersionedGraphCollection ( "sqlite://" )
275+ with BrickStore .graph . new_changeset ( "SCHEMA" ) as cs :
276+ cs . load_file ( BrickStore .schema )
270277 BrickStore .graph .bind ("digitaltwin" , Namespace ("https://example.org/digitaltwin#" ))
271278 BrickStore .graph .bind ("brick" , Namespace ("https://brickschema.org/schema/Brick#" ))
272279 BrickStore .graph .bind ("rdfs" , Namespace ("http://www.w3.org/2000/01/rdf-schema#" ))
@@ -281,8 +288,10 @@ def pop_brick_breadcrumb(cls):
281288
282289 @classmethod
283290 def remove_brick (cls , brick_uri ):
284- for triple in BrickStore .graph .triples ((URIRef (brick_uri ), None , None )):
285- BrickStore .graph .remove (triple )
291+ if (BrickStore .graph .triples ((URIRef (brick_uri ), None , None ))):
292+ with BrickStore .graph .new_changeset ("PROJECT" ) as cs :
293+ for triple in BrickStore .graph .triples ((URIRef (brick_uri ), None , None )):
294+ cs .remove (triple )
286295
287296 @classmethod
288297 def run_assign_brick_reference (cls , element = None , library = None , brick_uri = None ):
@@ -308,14 +317,39 @@ def select_browser_item(cls, item):
308317 def set_active_brick_class (cls , brick_class ):
309318 bpy .context .scene .BIMBrickProperties .active_brick_class = brick_class
310319
320+ @classmethod
321+ def undo_brick (cls ):
322+ if (len (BrickStore .graph .versions ()) > 1 ):
323+ BrickStore .graph .undo ()
311324
312- class BrickStore :
313- schema = None
314- graph = None
315- path = None
325+ @classmethod
326+ def redo_brick (cls ):
327+ with BrickStore .graph .conn () as conn :
328+ redo_record = conn .execute (
329+ "SELECT * from redos " "ORDER BY timestamp ASC LIMIT 1"
330+ ).fetchone ()
331+ if redo_record is not None :
332+ BrickStore .graph .redo ()
316333
334+ @classmethod
335+ def serialize_brick (cls , file_name ):
336+ #temporary file path, could either be user selected for "save as" or use the BrickStore.path for simply "save"
337+ cwd = os .path .dirname (os .path .realpath (__file__ ))
338+ dest = os .path .join (cwd , ".." , "bim" , "schema" , file_name )
339+ BrickStore .get_project ().serialize (destination = dest , format = "turtle" )
340+
341+ class BrickStore :
342+ schema = None # this is now a os path
343+ path = None # file path if the project was loaded in
344+ graph = None # this is the VersionedGraphCollection with 2 arbitrarily named graphs: "schema" and "project"
345+ # "SCHEMA" holds the Brick.ttl metadata; "PROJECT" holds all the authored entities
346+
317347 @staticmethod
318348 def purge ():
319349 BrickStore .schema = None
320350 BrickStore .graph = None
321- BrickStore .path = None
351+ BrickStore .path = None
352+
353+ @classmethod
354+ def get_project (cls ):
355+ return BrickStore .graph .graph_at (graph = "PROJECT" )
0 commit comments