diff --git a/.gitignore b/.gitignore
index 4677eaf..3230d7c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,4 +21,6 @@ CMakeFiles/
XCBuildData/
**/*.xcsettings
*.log
-.idea
\ No newline at end of file
+.idea
+*.mui
+*.aps
\ No newline at end of file
diff --git a/SpeckleConnector/Connector.vcxproj b/SpeckleConnector/Connector.vcxproj
index 355ea9f..ce15579 100644
--- a/SpeckleConnector/Connector.vcxproj
+++ b/SpeckleConnector/Connector.vcxproj
@@ -93,9 +93,10 @@
-
+
+
@@ -103,12 +104,13 @@
+
+
-
@@ -120,14 +122,25 @@
+
+
+
+
+
+
+
+
+
-
+
+
+
@@ -135,12 +148,13 @@
+
+
-
@@ -152,6 +166,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SpeckleConnector/Connector.vcxproj.filters b/SpeckleConnector/Connector.vcxproj.filters
index 2303713..8eb6949 100644
--- a/SpeckleConnector/Connector.vcxproj.filters
+++ b/SpeckleConnector/Connector.vcxproj.filters
@@ -32,12 +32,6 @@
{2f459f56-86f0-4794-b4b7-1bd7b8ee5617}
-
- {2820ad4f-60d9-436e-a7a2-d019d7e0ce0c}
-
-
- {85935d00-16ac-466a-a614-ad9ea802bffa}
-
{6a2f1f18-a554-4546-bba3-314d5f2ec9f9}
@@ -53,8 +47,17 @@
{2b87cf11-87cd-435f-ab24-42170c2e657e}
-
- {3bc97363-0091-4f84-a5f7-085193bad850}
+
+ {41395ee2-50f3-49c0-8859-23a3ad19a2fa}
+
+
+ {a915e7ee-849f-48a9-aa7b-0ef6e358bee7}
+
+
+ {2b16c188-1d80-4d4d-830e-5c1e56ecf46e}
+
+
+ {b6d6326c-77f4-414a-bda6-e3e587c7ded2}
@@ -122,9 +125,6 @@
Connector\Interface\Browser\Bridge\Base
-
- Connector\Database\Model\Card
-
Connector\Interface\Browser\Bridge\Config\Arg
@@ -159,8 +159,44 @@
Connector\Interface\Browser\Bridge\Send
-
- Connector\Interface\Browser\Bridge\Send\Arg
+
+ Connector\Database
+
+
+ Connector\Record\Model
+
+
+ Connector\Record\Model
+
+
+ Connector\Record\Model
+
+
+ Connector\Record\Model
+
+
+ Connector\Record\Model
+
+
+ Connector\Record\Model\Filter
+
+
+ Connector\Record\Model\Filter
+
+
+ Connector\Record\Model\Filter
+
+
+ Connector\Record\Model\Filter
+
+
+ Connector\Interface\Browser\Bridge\Base
+
+
+ Connector\Interface\Browser\Bridge\Base
+
+
+ Connector\Interface\Browser\Bridge\Base
@@ -215,9 +251,6 @@
Connector
-
- Connector\Database\Model\Card
-
Connector\Interface\Browser\Bridge\Config\Arg
@@ -252,8 +285,53 @@
Connector\Interface\Browser\Bridge\Send
-
- Connector\Interface\Browser\Bridge\Send\Arg
+
+ Connector\Database
+
+
+ Connector\Database\Identity
+
+
+ Connector\Record\Model
+
+
+ Connector\Record\Model
+
+
+ Connector\Record\Model
+
+
+ Connector\Record\Model
+
+
+ Connector\Record\Model
+
+
+ Connector\Record\Model\Filter
+
+
+ Connector\Record\Model\Filter
+
+
+ Connector\Record\Model\Filter
+
+
+ Connector\Record\Model\Filter
+
+
+ Connector\Record\Model\Filter
+
+
+ Connector\Record\Model\Filter
+
+
+ Connector\Interface\Browser\Bridge\Base
+
+
+ Connector\Interface\Browser\Bridge\Base
+
+
+ Connector\Interface\Browser\Bridge\Base
\ No newline at end of file
diff --git a/SpeckleConnector/Connector.xcodeproj/project.pbxproj b/SpeckleConnector/Connector.xcodeproj/project.pbxproj
index 028a510..11398cd 100644
--- a/SpeckleConnector/Connector.xcodeproj/project.pbxproj
+++ b/SpeckleConnector/Connector.xcodeproj/project.pbxproj
@@ -25,6 +25,10 @@
210CC8832C80E6A300610F58 /* TriggerEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 210CC8812C80E6A300610F58 /* TriggerEvent.cpp */; };
213CC39C2B1101F500088049 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2151077C2AEDB9070022CD24 /* Cocoa.framework */; };
214B7A372C764BCD00D586C1 /* UpdateConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21F69FBD2C7630B3008B6A06 /* UpdateConfig.cpp */; };
+ 215F082A2C947F4400CD343B /* CardMover.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08262C947F4400CD343B /* CardMover.cpp */; };
+ 215F082E2C94C5C000CD343B /* FilterMover.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F082C2C94C5C000CD343B /* FilterMover.cpp */; };
+ 215F08372C95808B00CD343B /* ReceiverModelCard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08362C95808B00CD343B /* ReceiverModelCard.cpp */; };
+ 215F08462C9633A800CD343B /* EverythingSendFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08452C9633A800CD343B /* EverythingSendFilter.cpp */; };
219F30422C769283009834E9 /* ConfigTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219F30402C769282009834E9 /* ConfigTests.cpp */; };
21B67CA32C769CB400FD64FC /* libActiveLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21F69EF52C64FE91008B6A06 /* libActiveLib.a */; };
21B67CA42C769CB400FD64FC /* libArchicad27.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21F69ECD2C64C035008B6A06 /* libArchicad27.a */; };
@@ -47,7 +51,14 @@
21D0BD6A2C8A0DB40077E104 /* GetIsDevMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BD682C8A0DB40077E104 /* GetIsDevMode.cpp */; };
21D0BD8E2C8EE4490077E104 /* Send.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BD8D2C8EE4490077E104 /* Send.cpp */; };
21D0BD972C8F13F30077E104 /* GetSendFilters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BD962C8F13F30077E104 /* GetSendFilters.cpp */; };
- 21D0BD9B2C8F154B0077E104 /* SendFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BD982C8F154B0077E104 /* SendFilter.cpp */; };
+ 21D0BDA82C8F33AC0077E104 /* ModelCard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BDA72C8F33AC0077E104 /* ModelCard.cpp */; };
+ 21D0BDAB2C8F363E0077E104 /* CardSetting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BDAA2C8F363E0077E104 /* CardSetting.cpp */; };
+ 21D0BDCF2C92DAC60077E104 /* AddModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BDCB2C92DAC60077E104 /* AddModel.cpp */; };
+ 21D0BDD42C935D1A0077E104 /* UpdateModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BDD22C935D1A0077E104 /* UpdateModel.cpp */; };
+ 21D0BDD72C935DAE0077E104 /* RemoveModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BDD52C935DAE0077E104 /* RemoveModel.cpp */; };
+ 21D0BDDC2C93897B0077E104 /* SenderModelCard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BDDA2C93897B0077E104 /* SenderModelCard.cpp */; };
+ 21D0BDE02C9393980077E104 /* SendFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BDDD2C9393980077E104 /* SendFilter.cpp */; };
+ 21D0BDE32C943C630077E104 /* DirectSelectionSendFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BDE12C943C630077E104 /* DirectSelectionSendFilter.cpp */; };
21D1E9AD2BF14AF200957EAA /* BIMData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21D1E9152BF14AEC00957EAA /* BIMData.framework */; };
21D1E9AE2BF14AF200957EAA /* TeamworkPortalServerClient.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21D1E9162BF14AEC00957EAA /* TeamworkPortalServerClient.framework */; };
21D1E9AF2BF14AF200957EAA /* GDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21D1E9172BF14AEC00957EAA /* GDL.framework */; };
@@ -275,6 +286,17 @@
210CC8822C80E6A300610F58 /* TriggerEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TriggerEvent.h; sourceTree = ""; };
213CC3A52B1101F500088049 /* Speckle Connector.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Speckle Connector.bundle"; sourceTree = BUILT_PRODUCTS_DIR; };
2151077C2AEDB9070022CD24 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
+ 215F08262C947F4400CD343B /* CardMover.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CardMover.cpp; sourceTree = ""; };
+ 215F08292C947F4400CD343B /* CardMover.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CardMover.h; sourceTree = ""; };
+ 215F082C2C94C5C000CD343B /* FilterMover.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FilterMover.cpp; sourceTree = ""; };
+ 215F082D2C94C5C000CD343B /* FilterMover.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FilterMover.h; sourceTree = ""; };
+ 215F08332C95808B00CD343B /* ReceiverModelCard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReceiverModelCard.h; sourceTree = ""; };
+ 215F08362C95808B00CD343B /* ReceiverModelCard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReceiverModelCard.cpp; sourceTree = ""; };
+ 215F083D2C96270100CD343B /* RecordID.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RecordID.h; sourceTree = ""; };
+ 215F08412C962F5E00CD343B /* ArchicadSelectionFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchicadSelectionFilter.h; sourceTree = ""; };
+ 215F08442C9633A800CD343B /* EverythingSendFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EverythingSendFilter.h; sourceTree = ""; };
+ 215F08452C9633A800CD343B /* EverythingSendFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EverythingSendFilter.cpp; sourceTree = ""; };
+ 215F084A2C9782F100CD343B /* ArchicadEverythingFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ArchicadEverythingFilter.h; sourceTree = ""; };
2161FD902BF2600C006D9527 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
219388682C4E5DE2002A0180 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; };
219F30352C768F0A009834E9 /* Connector-AC27-Test.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Connector-AC27-Test.bundle"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -319,8 +341,22 @@
21D0BD8D2C8EE4490077E104 /* Send.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Send.cpp; sourceTree = ""; };
21D0BD952C8F13F30077E104 /* GetSendFilters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetSendFilters.h; sourceTree = ""; };
21D0BD962C8F13F30077E104 /* GetSendFilters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetSendFilters.cpp; sourceTree = ""; };
- 21D0BD982C8F154B0077E104 /* SendFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendFilter.cpp; sourceTree = ""; };
- 21D0BD992C8F154B0077E104 /* SendFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendFilter.h; sourceTree = ""; };
+ 21D0BDA42C8F33AC0077E104 /* ModelCard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModelCard.h; sourceTree = ""; };
+ 21D0BDA72C8F33AC0077E104 /* ModelCard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ModelCard.cpp; sourceTree = ""; };
+ 21D0BDA92C8F363E0077E104 /* CardSetting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CardSetting.h; sourceTree = ""; };
+ 21D0BDAA2C8F363E0077E104 /* CardSetting.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CardSetting.cpp; sourceTree = ""; };
+ 21D0BDCB2C92DAC60077E104 /* AddModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AddModel.cpp; sourceTree = ""; };
+ 21D0BDCE2C92DAC60077E104 /* AddModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddModel.h; sourceTree = ""; };
+ 21D0BDD22C935D1A0077E104 /* UpdateModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UpdateModel.cpp; sourceTree = ""; };
+ 21D0BDD32C935D1A0077E104 /* UpdateModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UpdateModel.h; sourceTree = ""; };
+ 21D0BDD52C935DAE0077E104 /* RemoveModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RemoveModel.cpp; sourceTree = ""; };
+ 21D0BDD62C935DAE0077E104 /* RemoveModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoveModel.h; sourceTree = ""; };
+ 21D0BDDA2C93897B0077E104 /* SenderModelCard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SenderModelCard.cpp; sourceTree = ""; };
+ 21D0BDDB2C93897B0077E104 /* SenderModelCard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SenderModelCard.h; sourceTree = ""; };
+ 21D0BDDD2C9393980077E104 /* SendFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendFilter.cpp; sourceTree = ""; };
+ 21D0BDDE2C9393980077E104 /* SendFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendFilter.h; sourceTree = ""; };
+ 21D0BDE12C943C630077E104 /* DirectSelectionSendFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DirectSelectionSendFilter.cpp; sourceTree = ""; };
+ 21D0BDE22C943C630077E104 /* DirectSelectionSendFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectSelectionSendFilter.h; sourceTree = ""; };
21D1E9152BF14AEC00957EAA /* BIMData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BIMData.framework; path = "../Archicad 27/Support/Frameworks/BIMData.framework"; sourceTree = ""; };
21D1E9162BF14AEC00957EAA /* TeamworkPortalServerClient.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TeamworkPortalServerClient.framework; path = "../Archicad 27/Support/Frameworks/TeamworkPortalServerClient.framework"; sourceTree = ""; };
21D1E9172BF14AEC00957EAA /* GDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GDL.framework; path = "../Archicad 27/Support/Frameworks/GDL.framework"; sourceTree = ""; };
@@ -885,6 +921,14 @@
name = Frameworks;
sourceTree = "";
};
+ 215F083E2C96270100CD343B /* Identity */ = {
+ isa = PBXGroup;
+ children = (
+ 215F083D2C96270100CD343B /* RecordID.h */,
+ );
+ path = Identity;
+ sourceTree = "";
+ };
219F30412C769282009834E9 /* ConnectorTests */ = {
isa = PBXGroup;
children = (
@@ -898,6 +942,8 @@
21B67CAB2C77329800FD64FC /* Base */ = {
isa = PBXGroup;
children = (
+ 21D0BDCB2C92DAC60077E104 /* AddModel.cpp */,
+ 21D0BDCE2C92DAC60077E104 /* AddModel.h */,
21B67CEA2C78D27200FD64FC /* Arg */,
21B67CA52C77329800FD64FC /* BaseBridge.cpp */,
21B67CA62C77329800FD64FC /* BaseBridge.h */,
@@ -911,31 +957,20 @@
21B67CA82C77329800FD64FC /* GetSourceApplicationName.h */,
21B67CA92C77329800FD64FC /* GetSourceApplicationVersion.cpp */,
21B67CAA2C77329800FD64FC /* GetSourceApplicationVersion.h */,
+ 21D0BDD52C935DAE0077E104 /* RemoveModel.cpp */,
+ 21D0BDD62C935DAE0077E104 /* RemoveModel.h */,
+ 21D0BDD22C935D1A0077E104 /* UpdateModel.cpp */,
+ 21D0BDD32C935D1A0077E104 /* UpdateModel.h */,
);
path = Base;
sourceTree = "";
};
- 21B67CC92C77670400FD64FC /* Card */ = {
- isa = PBXGroup;
- children = (
- 21B67CC72C77670400FD64FC /* ModelCardDatabase.cpp */,
- 21B67CC82C77670400FD64FC /* ModelCardDatabase.h */,
- );
- path = Card;
- sourceTree = "";
- };
- 21B67CCA2C77670400FD64FC /* Model */ = {
- isa = PBXGroup;
- children = (
- 21B67CC92C77670400FD64FC /* Card */,
- );
- path = Model;
- sourceTree = "";
- };
21B67CCB2C77670400FD64FC /* Database */ = {
isa = PBXGroup;
children = (
- 21B67CCA2C77670400FD64FC /* Model */,
+ 215F083E2C96270100CD343B /* Identity */,
+ 21B67CC72C77670400FD64FC /* ModelCardDatabase.cpp */,
+ 21B67CC82C77670400FD64FC /* ModelCardDatabase.h */,
);
path = Database;
sourceTree = "";
@@ -988,7 +1023,6 @@
21D0BD5D2C89BFEA0077E104 /* Send */ = {
isa = PBXGroup;
children = (
- 21D0BD9A2C8F154B0077E104 /* Arg */,
21D0BD962C8F13F30077E104 /* GetSendFilters.cpp */,
21D0BD952C8F13F30077E104 /* GetSendFilters.h */,
21D0BD8D2C8EE4490077E104 /* Send.cpp */,
@@ -999,13 +1033,47 @@
path = Send;
sourceTree = "";
};
- 21D0BD9A2C8F154B0077E104 /* Arg */ = {
+ 21D0BDD82C9387E60077E104 /* Record */ = {
isa = PBXGroup;
children = (
- 21D0BD982C8F154B0077E104 /* SendFilter.cpp */,
- 21D0BD992C8F154B0077E104 /* SendFilter.h */,
+ 21D0BDD92C9387F70077E104 /* Model */,
);
- path = Arg;
+ path = Record;
+ sourceTree = "";
+ };
+ 21D0BDD92C9387F70077E104 /* Model */ = {
+ isa = PBXGroup;
+ children = (
+ 215F08262C947F4400CD343B /* CardMover.cpp */,
+ 215F08292C947F4400CD343B /* CardMover.h */,
+ 21D0BDAA2C8F363E0077E104 /* CardSetting.cpp */,
+ 21D0BDA92C8F363E0077E104 /* CardSetting.h */,
+ 21D0BDDF2C9393980077E104 /* Filter */,
+ 21D0BDA72C8F33AC0077E104 /* ModelCard.cpp */,
+ 21D0BDA42C8F33AC0077E104 /* ModelCard.h */,
+ 215F08362C95808B00CD343B /* ReceiverModelCard.cpp */,
+ 215F08332C95808B00CD343B /* ReceiverModelCard.h */,
+ 21D0BDDA2C93897B0077E104 /* SenderModelCard.cpp */,
+ 21D0BDDB2C93897B0077E104 /* SenderModelCard.h */,
+ );
+ path = Model;
+ sourceTree = "";
+ };
+ 21D0BDDF2C9393980077E104 /* Filter */ = {
+ isa = PBXGroup;
+ children = (
+ 215F084A2C9782F100CD343B /* ArchicadEverythingFilter.h */,
+ 215F08412C962F5E00CD343B /* ArchicadSelectionFilter.h */,
+ 21D0BDE12C943C630077E104 /* DirectSelectionSendFilter.cpp */,
+ 21D0BDE22C943C630077E104 /* DirectSelectionSendFilter.h */,
+ 215F08452C9633A800CD343B /* EverythingSendFilter.cpp */,
+ 215F08442C9633A800CD343B /* EverythingSendFilter.h */,
+ 215F082C2C94C5C000CD343B /* FilterMover.cpp */,
+ 215F082D2C94C5C000CD343B /* FilterMover.h */,
+ 21D0BDDD2C9393980077E104 /* SendFilter.cpp */,
+ 21D0BDDE2C9393980077E104 /* SendFilter.h */,
+ );
+ path = Filter;
sourceTree = "";
};
21D1EA472BF14B6C00957EAA /* Archicad */ = {
@@ -1067,6 +1135,7 @@
21B67CCB2C77670400FD64FC /* Database */,
21F69F092C677BC0008B6A06 /* Event */,
21F69F0E2C677BC0008B6A06 /* Interface */,
+ 21D0BDD82C9387E60077E104 /* Record */,
21B67CBA2C774C6500FD64FC /* Version.h */,
);
path = Connector;
@@ -1324,12 +1393,15 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 21D0BDAB2C8F363E0077E104 /* CardSetting.cpp in Sources */,
21B67CE32C78D1FB00FD64FC /* SayHiArg.cpp in Sources */,
+ 215F08462C9633A800CD343B /* EverythingSendFilter.cpp in Sources */,
21F69FBB2C762EF0008B6A06 /* ConfigBridge.cpp in Sources */,
21F69F8A2C70D2C4008B6A06 /* AccountBridge.cpp in Sources */,
- 21D0BD9B2C8F154B0077E104 /* SendFilter.cpp in Sources */,
21D0BD8E2C8EE4490077E104 /* Send.cpp in Sources */,
+ 21D0BDCF2C92DAC60077E104 /* AddModel.cpp in Sources */,
21B67CF72C78D4DE00FD64FC /* GetComplexType.cpp in Sources */,
+ 21D0BDDC2C93897B0077E104 /* SenderModelCard.cpp in Sources */,
21B67CAE2C77329800FD64FC /* GetSourceApplicationVersion.cpp in Sources */,
21B67CC32C77649F00FD64FC /* GetDocumentState.cpp in Sources */,
21D0BD602C89BFEA0077E104 /* SendBridge.cpp in Sources */,
@@ -1342,14 +1414,22 @@
21B67CD92C78C83800FD64FC /* TestBridge.cpp in Sources */,
214B7A372C764BCD00D586C1 /* UpdateConfig.cpp in Sources */,
21B67CC02C775A0D00FD64FC /* GetDocumentInfo.cpp in Sources */,
+ 21D0BDD42C935D1A0077E104 /* UpdateModel.cpp in Sources */,
21B67CE72C78D23B00FD64FC /* ConnectorConfig.cpp in Sources */,
21B67CAD2C77329800FD64FC /* GetSourceApplicationName.cpp in Sources */,
+ 21D0BDE02C9393980077E104 /* SendFilter.cpp in Sources */,
+ 21D0BDA82C8F33AC0077E104 /* ModelCard.cpp in Sources */,
+ 215F082A2C947F4400CD343B /* CardMover.cpp in Sources */,
+ 215F08372C95808B00CD343B /* ReceiverModelCard.cpp in Sources */,
+ 21D0BDD72C935DAE0077E104 /* RemoveModel.cpp in Sources */,
21B67CDC2C78C88000FD64FC /* SayHi.cpp in Sources */,
+ 215F082E2C94C5C000CD343B /* FilterMover.cpp in Sources */,
21F69F122C677BC0008B6A06 /* ConnectorMenu.cpp in Sources */,
21F69F8D2C70D7EE008B6A06 /* GetAccounts.cpp in Sources */,
21B67CCC2C77670400FD64FC /* ModelCardDatabase.cpp in Sources */,
21F69F132C677BC0008B6A06 /* ConnectorPalette.cpp in Sources */,
21F69FBC2C762EF0008B6A06 /* GetConfig.cpp in Sources */,
+ 21D0BDE32C943C630077E104 /* DirectSelectionSendFilter.cpp in Sources */,
21B67CF12C78D38000FD64FC /* GoAway.cpp in Sources */,
21F69F142C677BC0008B6A06 /* Connector.cpp in Sources */,
);
diff --git a/SpeckleConnector/Connector/Connector.cpp b/SpeckleConnector/Connector/Connector.cpp
index 89ce861..4306b0b 100755
--- a/SpeckleConnector/Connector/Connector.cpp
+++ b/SpeckleConnector/Connector/Connector.cpp
@@ -1,7 +1,7 @@
#include "Active/File/Directory.h"
#include "ConnectorResource.h"
#include "Connector/Connector.h"
-#include "Connector/Database/Model/Card/ModelCardDatabase.h"
+#include "Connector/Database/ModelCardDatabase.h"
#include "Interface/ConnectorMenu.h"
#include "Interface/ConnectorPalette.h"
#include "Speckle/Database/AccountDatabase.h"
@@ -29,6 +29,7 @@ namespace {
ConnectorInstance(const String& name) : ConnectorAddon{name} {
add();
add();
+ addWeak(m_modelCards.getSubscription());
}
// MARK: Functions (const)
diff --git a/SpeckleConnector/Connector/Database/Identity/RecordID.h b/SpeckleConnector/Connector/Database/Identity/RecordID.h
new file mode 100644
index 0000000..ad36268
--- /dev/null
+++ b/SpeckleConnector/Connector/Database/Identity/RecordID.h
@@ -0,0 +1,16 @@
+#ifndef CONNECTOR_DATABASE_ID
+#define CONNECTOR_DATABASE_ID
+
+#include "Speckle/Utility/Guid.h"
+
+namespace connector::database {
+
+ //BIM element record identifier
+ using ElementID = speckle::utility::Guid;
+
+ //A list of element IDs
+ using ElementIDList = std::vector;
+
+}
+
+#endif //CONNECTOR_DATABASE_ID
diff --git a/SpeckleConnector/Connector/Database/Model/Card/ModelCardDatabase.h b/SpeckleConnector/Connector/Database/Model/Card/ModelCardDatabase.h
deleted file mode 100644
index 8ff7d31..0000000
--- a/SpeckleConnector/Connector/Database/Model/Card/ModelCardDatabase.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef CONNECTOR_DATABASE_MODEL_CARD_DATABASE
-#define CONNECTOR_DATABASE_MODEL_CARD_DATABASE
-
-#include "Active/Serialise/Package/Package.h"
-#include "Speckle/Utility/String.h"
-
-namespace connector::database {
-
- /*!
- Database of model cards relating to a specific project
- */
- class ModelCardDatabase : public active::serialise::Package {
- public:
-
- // MARK: - Types
-
- using base = active::serialise::Package;
-
- // MARK: - Constructors
-
- /*!
- Default constructor
- */
- ModelCardDatabase() {}
-
- // MARK: - Public variables (NB: Assuming to class invariants or overrides for this data, so making public for simplicity)
-
-
- // MARK: Functions (const)
-
- //Implement card access when necessary
-
- // MARK: - Serialisation
-
- /*!
- Fill an inventory with the package items
- @param inventory The inventory to receive the package items
- @return True if the package has added items to the inventory
- */
- bool fillInventory(active::serialise::Inventory& inventory) const override;
- /*!
- Get the specified cargo
- @param item The inventory item to retrieve
- @return The requested cargo (nullptr on failure)
- */
- Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
- /*!
- Set to the default package content
- */
- void setDefault() override;
- private:
- //TODO: Model card array here - implement when necessary
- };
-
-}
-
-#endif //CONNECTOR_DATABASE_MODEL_CARD_DATABASE
diff --git a/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp b/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp
new file mode 100644
index 0000000..761d8fc
--- /dev/null
+++ b/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp
@@ -0,0 +1,121 @@
+#include "Connector/Database/ModelCardDatabase.h"
+
+#include "Active/Database/Storage/Storage.h"
+#include "Active/Serialise/JSON/JSONTransport.h"
+#include "Connector/Record/Model/CardMover.h"
+#include "Speckle/Database/Identity/RecordID.h"
+#include "Speckle/Database/Storage/DocumentStore/DocumentStoreEngine.h"
+
+#include
+
+using namespace active::container;
+using namespace active::database;
+using namespace active::event;
+using namespace active::serialise;
+using namespace active::serialise::json;
+using namespace connector::database;
+using namespace connector::record;
+using namespace speckle::database;
+using namespace speckle::utility;
+
+namespace connector::database {
+
+ ///ModelCard database engine declaration
+ class ModelCardDatabase::Engine : public DocumentStoreEngine {
+ using base = DocumentStoreEngine;
+ using base::base;
+ };
+
+ ///ModelCard database storage declaration
+ class ModelCardDatabase::Store : public Storage {
+ using base = Storage;
+ using base::base;
+ };
+
+}
+
+namespace {
+
+ ///The document storage identifier for model cards
+ const char* modelCardDBaseName = "connector::database::ModelModelCardDatabase";
+ ///The document storage identifier for model cards
+ const char* modelCardTableName = "models";
+
+}
+
+/*--------------------------------------------------------------------
+ Constructor
+ --------------------------------------------------------------------*/
+ModelCardDatabase::ModelCardDatabase() {
+ m_engine = std::make_shared(modelCardDBaseName,
+ //Schema
+ DBaseSchema{active::utility::String{modelCardDBaseName},
+ //Tables
+ {
+ //Model card table
+ {
+ modelCardTableName, 0, 0, {} //The table specifics aren't relevant in this context
+ }
+ }
+ }
+ );
+ m_store = std::make_shared(m_engine);
+} //ModelCardDatabase::ModelCardDatabase
+
+
+/*--------------------------------------------------------------------
+ Destructor
+ --------------------------------------------------------------------*/
+ModelCardDatabase::~ModelCardDatabase() {}
+
+
+/*--------------------------------------------------------------------
+ Get all model cards
+
+ return: All the cards
+ --------------------------------------------------------------------*/
+Vector ModelCardDatabase::getCards() const {
+ return m_store->getObjects();
+} //ModelCardDatabase::getCards
+
+
+/*--------------------------------------------------------------------
+ Write a card to storage
+
+ card: The card to write
+ --------------------------------------------------------------------*/
+void ModelCardDatabase::write(const ModelCard& card) const {
+ m_store->write(card);
+} //ModelCardDatabase::write
+
+
+/*--------------------------------------------------------------------
+ Erase a card
+
+ cardID: The ID of the card to erase
+ --------------------------------------------------------------------*/
+void ModelCardDatabase::erase(const String& cardID) const {
+ m_store->erase(cardID);
+} //ModelCardDatabase::erase
+
+
+/*--------------------------------------------------------------------
+ Get a serialisation wrapper for the database
+
+ return: A database wrapper
+ --------------------------------------------------------------------*/
+std::unique_ptr ModelCardDatabase::wrapper() const {
+ return m_store->wrapper();
+} //ModelCardDatabase::wrapper
+
+
+/*--------------------------------------------------------------------
+ Get the database subscription (the content is document-based, and must react to document operations)
+
+ return: The database subscription (add weakly to publisher)
+ --------------------------------------------------------------------*/
+std::shared_ptr ModelCardDatabase::getSubscription() {
+ return std::dynamic_pointer_cast(m_engine);
+} //ModelCardDatabase::getSubscription
diff --git a/SpeckleConnector/Connector/Database/ModelCardDatabase.h b/SpeckleConnector/Connector/Database/ModelCardDatabase.h
new file mode 100644
index 0000000..d2e7db6
--- /dev/null
+++ b/SpeckleConnector/Connector/Database/ModelCardDatabase.h
@@ -0,0 +1,71 @@
+#ifndef CONNECTOR_DATABASE_MODEL_CARD_DATABASE
+#define CONNECTOR_DATABASE_MODEL_CARD_DATABASE
+
+#include "Connector/Record/Model/ModelCard.h"
+
+namespace active::event {
+ class Subscriber;
+}
+
+namespace connector::database {
+
+ /*!
+ Database of model cards relating to a specific project
+ */
+ class ModelCardDatabase {
+ public:
+
+ // MARK: - Constructors
+
+ /*!
+ Constructor
+ */
+ ModelCardDatabase();
+ ModelCardDatabase(const ModelCardDatabase&) = delete;
+ /*!
+ Destructor
+ */
+ ~ModelCardDatabase();
+
+ // MARK: - Functions (const)
+
+ /*!
+ Get all model cards
+ @return All the cards
+ */
+ active::container::Vector getCards() const;
+ /*!
+ Write a card to storage
+ @param card The card to write
+ */
+ void write(const record::ModelCard& card) const;
+ /*!
+ Erase a card
+ @param cardID The ID of the card to erase
+ */
+ void erase(const speckle::utility::String& cardID) const;
+ /*!
+ Get a serialisation wrapper for the database
+ @return A database wrapper
+ */
+ std::unique_ptr wrapper() const;
+
+ // MARK: - Functions (mutating)
+
+ /*!
+ Get the database subscription (the content is document-based, and must react to document operations)
+ @return The database subscription (add weakly to publisher)
+ */
+ std::shared_ptr getSubscription();
+
+ private:
+ class Engine;
+ class Store;
+ ///Model card database storage
+ std::shared_ptr m_engine;
+ std::shared_ptr m_store;
+ };
+
+}
+
+#endif //CONNECTOR_DATABASE_MODEL_CARD_DATABASE
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Account/GetAccounts.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Account/GetAccounts.cpp
index b32c6a4..ecf0f99 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Account/GetAccounts.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Account/GetAccounts.cpp
@@ -14,7 +14,7 @@ using namespace speckle::utility;
namespace {
- using WrappedValue = active::serialise::CargoHold, Vector>;
+ using WrappedValue = active::serialise::CargoHold>, Vector>;
}
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.cpp
new file mode 100644
index 0000000..6c08025
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.cpp
@@ -0,0 +1,35 @@
+#include "Connector/Interface/Browser/Bridge/Base/AddModel.h"
+
+#include "Connector/Connector.h"
+#include "Connector/Database/ModelCardDatabase.h"
+#include "Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h"
+
+using namespace active::container;
+using namespace active::serialise;
+using namespace connector::record;
+using namespace connector::interfac::browser::bridge;
+using namespace speckle::utility;
+
+namespace {
+
+ using WrappedValue = active::serialise::CargoHold;
+
+}
+
+/*--------------------------------------------------------------------
+ Default constructor
+ --------------------------------------------------------------------*/
+AddModel::AddModel() : BridgeMethod{"AddModel", [&](const ModelCardEventWrapper& card) {
+ return run(card.get());
+}} {}
+
+
+/*--------------------------------------------------------------------
+ Add a model card to document storage
+
+ card: The card to add
+ --------------------------------------------------------------------*/
+void AddModel::run(const ModelCard& card) const {
+ if (auto modelCardDBase = connector()->getModelCardDatabase(); modelCardDBase != nullptr)
+ modelCardDBase->write(card);
+} //AddModel::run
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.h
new file mode 100644
index 0000000..bca8410
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.h
@@ -0,0 +1,40 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_ADD_MODEL
+#define CONNECTOR_INTERFACE_BRIDGE_ADD_MODEL
+
+#include "Active/Serialise/CargoHold.h"
+#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
+#include "Connector/Record/Model/ModelCard.h"
+#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h"
+
+namespace connector::interfac::browser::bridge {
+
+ ///Argument parameter for a string
+ using CardHold = active::serialise::CargoHold;
+ ///Argument type for this method
+ using ModelCardEventWrapper = speckle::interfac::browser::bridge::JSArgType;
+
+ /*!
+ JS Function class to add a model card to the document storage
+ */
+ class AddModel : public speckle::interfac::browser::bridge::BridgeMethod {
+ public:
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ */
+ AddModel();
+
+ // MARK: - Functions (const)
+
+ /*!
+ Add a model card to document storage
+ @param card The card to add
+ */
+ void run(const connector::record::ModelCard& card) const;
+ };
+
+}
+
+#endif //CONNECTOR_INTERFACE_BRIDGE_ADD_MODEL
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp
index 94c5127..f40155f 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp
@@ -1,10 +1,13 @@
#include "Connector/Interface/Browser/Bridge/Base/BaseBridge.h"
+#include "Connector/Interface/Browser/Bridge/Base/AddModel.h"
#include "Connector/Interface/Browser/Bridge/Base/GetConnectorVersion.h"
#include "Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.h"
#include "Connector/Interface/Browser/Bridge/Base/GetDocumentState.h"
#include "Connector/Interface/Browser/Bridge/Base/GetSourceApplicationName.h"
#include "Connector/Interface/Browser/Bridge/Base/GetSourceApplicationVersion.h"
+#include "Connector/Interface/Browser/Bridge/Base/RemoveModel.h"
+#include "Connector/Interface/Browser/Bridge/Base/UpdateModel.h"
using namespace connector::interfac::browser::bridge;
@@ -13,9 +16,12 @@ using namespace connector::interfac::browser::bridge;
--------------------------------------------------------------------*/
BaseBridge::BaseBridge() : BrowserBridge{"baseBinding"} {
//Add bridge methods
+ addMethod();
addMethod();
addMethod();
addMethod();
addMethod();
addMethod();
+ addMethod();
+ addMethod();
} //BaseBridge::BaseBridge
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp
index 5353a37..04d0f6c 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp
@@ -1,17 +1,21 @@
#include "Connector/Interface/Browser/Bridge/Base/GetDocumentState.h"
#include "Active/Serialise/CargoHold.h"
-#include "Connector/Database/Model/Card/ModelCardDatabase.h"
+#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
+#include "Connector/Connector.h"
+#include "Connector/Record/Model/ModelCard.h"
+#include "Connector/Database/ModelCardDatabase.h"
using namespace active::container;
using namespace active::serialise;
using namespace connector::interfac::browser::bridge;
using namespace connector::database;
+using namespace connector::record;
using namespace speckle::utility;
namespace {
- using WrappedValue = active::serialise::CargoHold;
+ using WrappedValue = active::serialise::CargoHold>, Vector>;
}
@@ -29,7 +33,8 @@ GetDocumentState::GetDocumentState() : BridgeMethod{"GetDocumentState", [&]() {
return: The document info
--------------------------------------------------------------------*/
std::unique_ptr GetDocumentState::run() const {
- ///TODO: Retrieve the model card database from connector()->getModelCards() in future (when implemented)
- ModelCardDatabase modelCards; //This is just a temp so something can be sent back to the JS for the interim
- return std::make_unique(modelCards);
+ if (auto modelCardDBase = connector()->getModelCardDatabase(); modelCardDBase != nullptr) {
+ return modelCardDBase->wrapper();
+ }
+ return nullptr;
} //GetDocumentState::run
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/RemoveModel.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/RemoveModel.cpp
new file mode 100644
index 0000000..722d2fa
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/RemoveModel.cpp
@@ -0,0 +1,36 @@
+#include "Connector/Interface/Browser/Bridge/Base/RemoveModel.h"
+
+#include "Connector/Connector.h"
+#include "Connector/Database/ModelCardDatabase.h"
+#include "Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h"
+
+using namespace active::container;
+using namespace active::serialise;
+using namespace connector::database;
+using namespace connector::record;
+using namespace connector::interfac::browser::bridge;
+using namespace speckle::utility;
+
+namespace {
+
+ using WrappedValue = active::serialise::CargoHold;
+
+}
+
+/*--------------------------------------------------------------------
+ Default constructor
+ --------------------------------------------------------------------*/
+RemoveModel::RemoveModel() : BridgeMethod{"RemoveModel", [&](const ModelCardEventWrapper& card) {
+ return run(card.get());
+}} {}
+
+
+/*--------------------------------------------------------------------
+ Add a model card to document storage
+
+ card: The card to add
+ --------------------------------------------------------------------*/
+void RemoveModel::run(const ModelCard& card) const {
+ if (auto modelCardDBase = connector()->getModelCardDatabase(); modelCardDBase != nullptr)
+ modelCardDBase->erase(card.getID());
+} //RemoveModel::run
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/RemoveModel.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/RemoveModel.h
new file mode 100644
index 0000000..50c6d00
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/RemoveModel.h
@@ -0,0 +1,40 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_REMOVE_MODEL
+#define CONNECTOR_INTERFACE_BRIDGE_REMOVE_MODEL
+
+#include "Active/Serialise/CargoHold.h"
+#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
+#include "Connector/Record/Model/ModelCard.h"
+#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h"
+
+namespace connector::interfac::browser::bridge {
+
+ ///Argument parameter for a string
+ using CardHold = active::serialise::CargoHold;
+ ///Argument type for this method
+ using ModelCardEventWrapper = speckle::interfac::browser::bridge::JSArgType;
+
+ /*!
+ JS Function class to add a model card to the document storage
+ */
+ class RemoveModel : public speckle::interfac::browser::bridge::BridgeMethod {
+ public:
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ */
+ RemoveModel();
+
+ // MARK: - Functions (const)
+
+ /*!
+ Add a model card to document storage
+ @param card The card to add
+ */
+ void run(const connector::record::ModelCard& card) const;
+ };
+
+}
+
+#endif //CONNECTOR_INTERFACE_BRIDGE_REMOVE_MODEL
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.cpp
new file mode 100644
index 0000000..cd845dc
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.cpp
@@ -0,0 +1,36 @@
+#include "Connector/Interface/Browser/Bridge/Base/UpdateModel.h"
+
+#include "Connector/Connector.h"
+#include "Connector/Database/ModelCardDatabase.h"
+#include "Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h"
+
+using namespace active::container;
+using namespace active::serialise;
+using namespace connector::database;
+using namespace connector::record;
+using namespace connector::interfac::browser::bridge;
+using namespace speckle::utility;
+
+namespace {
+
+ using WrappedValue = active::serialise::CargoHold;
+
+}
+
+/*--------------------------------------------------------------------
+ Default constructor
+ --------------------------------------------------------------------*/
+UpdateModel::UpdateModel() : BridgeMethod{"UpdateModel", [&](const ModelCardEventWrapper& card) {
+ return run(card.get());
+}} {}
+
+
+/*--------------------------------------------------------------------
+ Add a model card to document storage
+
+ card: The card to add
+ --------------------------------------------------------------------*/
+void UpdateModel::run(const ModelCard& card) const {
+ if (auto modelCardDBase = connector()->getModelCardDatabase(); modelCardDBase != nullptr)
+ modelCardDBase->write(card);
+} //UpdateModel::run
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.h
new file mode 100644
index 0000000..e4263fe
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.h
@@ -0,0 +1,40 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_UPDATE_MODEL
+#define CONNECTOR_INTERFACE_BRIDGE_UPDATE_MODEL
+
+#include "Active/Serialise/CargoHold.h"
+#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
+#include "Connector/Record/Model/ModelCard.h"
+#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h"
+
+namespace connector::interfac::browser::bridge {
+
+ ///Argument parameter for a string
+ using CardHold = active::serialise::CargoHold;
+ ///Argument type for this method
+ using ModelCardEventWrapper = speckle::interfac::browser::bridge::JSArgType;
+
+ /*!
+ JS Function class to add a model card to the document storage
+ */
+ class UpdateModel : public speckle::interfac::browser::bridge::BridgeMethod {
+ public:
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ */
+ UpdateModel();
+
+ // MARK: - Functions (const)
+
+ /*!
+ Add a model card to document storage
+ @param card The card to add
+ */
+ void run(const connector::record::ModelCard& card) const;
+ };
+
+}
+
+#endif //CONNECTOR_INTERFACE_BRIDGE_UPDATE_MODEL
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/UpdateConfig.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/UpdateConfig.cpp
index 1977dc6..515f127 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/UpdateConfig.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/UpdateConfig.cpp
@@ -10,7 +10,7 @@ using namespace speckle::utility;
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
-UpdateConfig::UpdateConfig() : BridgeMethod{"UpdateConfig", [&](UpdateArgs args) {
+UpdateConfig::UpdateConfig() : BridgeMethod{"UpdateConfig", [&](const UpdateArgs& args) {
run(args);
}} {}
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendFilter.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendFilter.h
deleted file mode 100644
index d86abc6..0000000
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendFilter.h
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef CONNECTOR_INTERFACE_BRIDGE_SEND_FILTER
-#define CONNECTOR_INTERFACE_BRIDGE_SEND_FILTER
-
-#include "Active/Serialise/Package/Package.h"
-#include "Active/Utility/Cloner.h"
-#include "Speckle/Utility/String.h"
-
-namespace connector::interfac::browser::bridge {
-
- /*!
- A connector send filter
- */
- class SendFilter : public active::serialise::Package, public active::utility::Cloner {
- public:
-
- // MARK: - Types
-
- using base = active::serialise::Package;
-
- // MARK: - Constructors
-
- /*!
- Default constructor
- @param nm The filter name
- @param sum A summary
- @param isDef True if this is the default filter
- */
- SendFilter(const speckle::utility::String& nm = {}, const speckle::utility::String& sum = {}, bool isDef = false) :
- name{nm}, summary{sum}, isDefault{isDef} {}
- /*!
- Record cloning
- @return A clone of this record
- */
- virtual SendFilter* clonePtr() const override { return new SendFilter(*this); };
-
- // MARK: - Public variables (NB: Assuming to class invariants or overrides for this data, so making public for simplicity)
-
- ///The filter name
- speckle::utility::String name;
- ///A summary
- speckle::utility::String summary;
- ///True if this is the default filter
- bool isDefault = false;
-
- // MARK: - Serialisation
-
- /*!
- Fill an inventory with the package items
- @param inventory The inventory to receive the package items
- @return True if the package has added items to the inventory
- */
- bool fillInventory(active::serialise::Inventory& inventory) const override;
- /*!
- Get the specified cargo
- @param item The inventory item to retrieve
- @return The requested cargo (nullptr on failure)
- */
- Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
- /*!
- Set to the default package content
- */
- void setDefault() override;
- };
-
-}
-
-#endif //CONNECTOR_INTERFACE_BRIDGE_SEND_FILTER
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendFilters.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendFilters.cpp
index 6897267..efddd60 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendFilters.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendFilters.cpp
@@ -4,16 +4,18 @@
#include "Active/Serialise/CargoHold.h"
#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
-#include "Connector/Interface/Browser/Bridge/Send/Arg/SendFilter.h"
+#include "Connector/Record/Model/Filter/ArchicadEverythingFilter.h"
+#include "Connector/Record/Model/Filter/ArchicadSelectionFilter.h"
using namespace active::container;
using namespace active::serialise;
+using namespace connector::record;
using namespace connector::interfac::browser::bridge;
using namespace speckle::utility;
namespace {
- using WrappedValue = active::serialise::CargoHold, Vector>;
+ using WrappedValue = active::serialise::CargoHold>, Vector>;
}
@@ -32,6 +34,7 @@ GetSendFilters::GetSendFilters() : BridgeMethod{"GetSendFilters", [&]() {
--------------------------------------------------------------------*/
std::unique_ptr GetSendFilters::run() const {
Vector filters;
- ///TODO: Get real filters
+ //filters.emplace_back(ArchicadEverythingFilter{}); //TODO: Implement as required
+ filters.emplace_back(ArchicadSelectionFilter{});
return std::make_unique(filters);
} //GetSendFilters::run
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/TriggerEvent.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/TriggerEvent.cpp
index 1981c3f..a6dd5bf 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/TriggerEvent.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/TriggerEvent.cpp
@@ -85,7 +85,7 @@ namespace {
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
-TriggerEvent::TriggerEvent() : BridgeMethod{"TriggerEvent", [&](TriggerEventWrapper arg) {
+TriggerEvent::TriggerEvent() : BridgeMethod{"TriggerEvent", [&](const TriggerEventWrapper& arg) {
return run(arg);
}} {}
@@ -95,7 +95,7 @@ TriggerEvent::TriggerEvent() : BridgeMethod{"TriggerEvent", [&](TriggerEventWrap
eventName: The event name
--------------------------------------------------------------------*/
-void TriggerEvent::run(speckle::utility::String eventName) const {
+void TriggerEvent::run(const speckle::utility::String& eventName) const {
if (!hasBridge())
return;
if (eventName == "emptyTestEvent")
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/TriggerEvent.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/TriggerEvent.h
index 323087a..a38c80a 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/TriggerEvent.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/TriggerEvent.h
@@ -31,7 +31,7 @@ namespace connector::interfac::browser::bridge {
Trigger an event based on a specified name
@param eventName The event name
*/
- void run(speckle::utility::String eventName) const;
+ void run(const speckle::utility::String& eventName) const;
};
}
diff --git a/SpeckleConnector/Connector/Record/Model/CardMover.cpp b/SpeckleConnector/Connector/Record/Model/CardMover.cpp
new file mode 100644
index 0000000..48e9c94
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/CardMover.cpp
@@ -0,0 +1,60 @@
+/*!
+Copyright 2024 Ralph Wessel and Hugh Wessel
+Distributed under the MIT License (See accompanying file LICENSE.txt or copy at https://opensource.org/license/mit/)
+*/
+
+#include "Connector/Record/Model/CardMover.h"
+
+#include "Connector/Record/Model/ReceiverModelCard.h"
+#include "Connector/Record/Model/SenderModelCard.h"
+
+using namespace active::serialise;
+using namespace active::utility;
+using namespace connector::record;
+
+namespace {
+
+ ///The tag used to identify a Speckle type name value
+ const char* attributeTag = "typeDiscriminator";
+ ///Identity for a ReceiverModelCard
+ const char* receiverCardTypeName = "ReceiverModelCard";
+ ///Identity for a SenderModelCard
+ const char* senderCardTypeName = "SenderModelCard";
+
+ /*--------------------------------------------------------------------
+ Ensure the handler is populated
+
+ handler: The card handler to validate
+
+ return: A reference to the handler
+ --------------------------------------------------------------------*/
+ std::shared_ptr& validateHandler(std::shared_ptr& handler) {
+ if (!handler->empty())
+ return handler;
+ handler->add(receiverCardTypeName);
+ handler->add(senderCardTypeName);
+ return handler;
+ } //CardMover::validateHandler
+
+}
+
+ ///The handler for model card packages
+std::shared_ptr CardMover::m_handler = std::make_shared(attributeTag);
+
+
+/*--------------------------------------------------------------------
+ Constructor (for deserialisation)
+
+ handler: A package handler to reconstruct incoming packages
+ --------------------------------------------------------------------*/
+CardMover::CardMover() : Mover{validateHandler(m_handler)} {
+} //CardMover::CardMover
+
+
+/*--------------------------------------------------------------------
+ Constructor (for serialisation)
+
+ outgoing: An outgoing package
+ --------------------------------------------------------------------*/
+CardMover::CardMover(const active::serialise::Package& outgoing) : Mover{outgoing, validateHandler(m_handler)} {
+} //CardMover::CardMover
diff --git a/SpeckleConnector/Connector/Record/Model/CardMover.h b/SpeckleConnector/Connector/Record/Model/CardMover.h
new file mode 100644
index 0000000..62bfe7c
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/CardMover.h
@@ -0,0 +1,36 @@
+#ifndef CONNECTOR_MODEL_CARD_MOVER
+#define CONNECTOR_MODEL_CARD_MOVER
+
+#include "Active/Serialise/Package/Wrapper/Mover.h"
+
+namespace connector::record {
+
+ /*!
+ Wrapper to box/unbox objects during (de)serialisation, including reading/writing a specified attribute to determine object type
+
+ Note that a derived class could also define the package handler, allowing the wrapper to be created via a default constructor that is
+ automatically bound to a set of internally defined object types
+ */
+ class CardMover : public active::serialise::Mover {
+ public:
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ */
+ CardMover();
+ /*!
+ Constructor (for serialisation)
+ @param outgoing An outgoing package
+ */
+ CardMover(const active::serialise::Package& outgoing);
+
+ private:
+ ///The handler for model card packages
+ static std::shared_ptr m_handler;
+ };
+
+}
+
+#endif //CONNECTOR_MODEL_CARD_MOVER
diff --git a/SpeckleConnector/Connector/Record/Model/CardSetting.cpp b/SpeckleConnector/Connector/Record/Model/CardSetting.cpp
new file mode 100644
index 0000000..abfb10a
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/CardSetting.cpp
@@ -0,0 +1,94 @@
+#include "Connector/Record/Model/CardSetting.h"
+
+#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
+#include "Active/Serialise/Item/Wrapper/AnyValueWrap.h"
+#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
+
+#include
+
+using namespace active::serialise;
+using namespace connector::record;
+using namespace speckle::utility;
+
+namespace {
+
+ ///Serialisation fields
+ enum FieldIndex {
+ idID,
+ titleID,
+ typeID,
+ valueID,
+ enumID,
+ };
+
+ ///Serialisation field IDs
+ static std::array fieldID = {
+ Identity{"id"},
+ Identity{"title"},
+ Identity{"type"},
+ Identity{"value"},
+ Identity{"enum"},
+ };
+
+}
+
+/*--------------------------------------------------------------------
+ Fill an inventory with the package items
+
+ inventory: The inventory to receive the package items
+
+ return: True if the package has added items to the inventory
+ --------------------------------------------------------------------*/
+bool CardSetting::fillInventory(Inventory& inventory) const {
+ using enum Entry::Type;
+ inventory.merge(Inventory{
+ {
+ { fieldID[idID], idID, element },
+ { fieldID[titleID], titleID, element },
+ { fieldID[typeID], typeID, element },
+ { fieldID[valueID], valueID, element },
+ { fieldID[enumID], enumID, element },
+ },
+ }.withType(&typeid(CardSetting)));
+ return true;
+} //CardSetting::fillInventory
+
+
+/*--------------------------------------------------------------------
+ Get the specified cargo
+
+ item: The inventory item to retrieve
+
+ return: The requested cargo (nullptr on failure)
+ --------------------------------------------------------------------*/
+Cargo::Unique CardSetting::getCargo(const Inventory::Item& item) const {
+ if (item.ownerType != &typeid(CardSetting))
+ return nullptr;
+ using namespace active::serialise;
+ switch (item.index) {
+ case idID:
+ return std::make_unique>(m_ID);
+ case titleID:
+ return std::make_unique>(m_title);
+ case typeID:
+ return std::make_unique>(m_type);
+ case valueID:
+ return std::make_unique(*m_value);
+ case enumID:
+ return std::make_unique>>(m_enum);
+ default:
+ return nullptr; //Requested an unknown index
+ }
+} //CardSetting::getCargo
+
+
+/*--------------------------------------------------------------------
+ Set to the default package content
+ --------------------------------------------------------------------*/
+void CardSetting::setDefault() {
+ m_ID.clear();
+ m_title.clear();
+ m_type.clear();
+ m_value->setDefault();
+ m_enum.clear();
+} //CardSetting::setDefault
diff --git a/SpeckleConnector/Connector/Record/Model/CardSetting.h b/SpeckleConnector/Connector/Record/Model/CardSetting.h
new file mode 100644
index 0000000..281528b
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/CardSetting.h
@@ -0,0 +1,107 @@
+#ifndef CONNECTOR_RECORD_CARD_SETTING
+#define CONNECTOR_RECORD_CARD_SETTING
+
+#include "Active/Serialise/Package/Package.h"
+#include "Active/Setting/ValueSetting.h"
+#include "Active/Setting/Values/StringValue.h"
+#include "Active/Utility/Cloner.h"
+#include "Speckle/Utility/Guid.h"
+#include "Speckle/Utility/String.h"
+
+namespace connector::record {
+
+ /*!
+ A setting attached to a model card, capturing rendering/view states of the model at the time of sending, e.g. level of detail (LoD)
+ */
+ class CardSetting : public active::serialise::Package, public active::utility::Cloner {
+ public:
+
+ // MARK: - Types
+
+ using base = active::serialise::Package;
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ */
+ CardSetting() {}
+ /*!
+ Copy constructor
+ @param source The object to copy
+ */
+ CardSetting(const CardSetting& source) :
+ m_title{source.m_title}, m_type{source.m_type}, m_value{clone(*source.m_value)}, m_enum{source.m_enum} {}
+ /*!
+ Destructor
+ */
+ ~CardSetting() {}
+ /*!
+ Record cloning
+ @return A clone of this record
+ */
+ virtual CardSetting* clonePtr() const override { return new CardSetting(*this); };
+
+ // MARK: - Functions (const)
+
+ /*!
+ Get the setting ID
+ @return The setting ID
+ */
+ const speckle::utility::String& getID() const { return m_ID; }
+ /*!
+ Get the setting title
+ @return The setting title
+ */
+ const speckle::utility::String& getTitle() const { return m_title; }
+ /*!
+ Get the setting type
+ @return The setting type
+ */
+ const speckle::utility::String& getType() const { return m_type; }
+ /*!
+ Get the setting value
+ @return The setting value
+ */
+ const active::setting::Value& getValue() const { return *m_value; }
+ /*!
+ Get the options for the value, i.e. possible values it can hold
+ @return Possible setting values
+ */
+ std::vector getEnum() const { return m_enum; }
+
+ // MARK: - Serialisation
+
+ /*!
+ Fill an inventory with the package items
+ @param inventory The inventory to receive the package items
+ @return True if the package has added items to the inventory
+ */
+ bool fillInventory(active::serialise::Inventory& inventory) const override;
+ /*!
+ Get the specified cargo
+ @param item The inventory item to retrieve
+ @return The requested cargo (nullptr on failure)
+ */
+ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
+ /*!
+ Set to the default package content
+ */
+ void setDefault() override;
+
+ private:
+ ///A unique ID for the setting
+ speckle::utility::String m_ID = {active::utility::Guid{true}.operator active::utility::String()};
+ ///The model ID
+ speckle::utility::String m_title;
+ ///The project ID
+ speckle::utility::String m_type;
+ ///The setting value
+ active::setting::Value::Unique m_value = std::make_unique();
+ ///Possible values for the setting (as strings)
+ std::vector m_enum;
+ };
+
+}
+
+#endif //CONNECTOR_RECORD_CARD_SETTING
diff --git a/SpeckleConnector/Connector/Record/Model/Filter/ArchicadEverythingFilter.h b/SpeckleConnector/Connector/Record/Model/Filter/ArchicadEverythingFilter.h
new file mode 100644
index 0000000..19f2af6
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/Filter/ArchicadEverythingFilter.h
@@ -0,0 +1,38 @@
+#ifndef CONNECTOR_RECORD_ARCHICAD_EVERYTHING_FILTER
+#define CONNECTOR_RECORD_ARCHICAD_EVERYTHING_FILTER
+
+#include "Connector/Database/Identity/RecordID.h"
+#include "Connector/Record/Model/Filter/EverythingSendFilter.h"
+
+namespace connector::record {
+
+ /*!
+ A send filter consisting of a list of selected Archicad element IDs
+ */
+ class ArchicadEverythingFilter : public EverythingSendFilter {
+ public:
+
+ // MARK: - Types
+
+ using base = EverythingSendFilter;
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ @param sum A summary
+ @param isDef True if this is the default filter
+ */
+ ArchicadEverythingFilter(const speckle::utility::String& sum = {}, bool isDef = false) : base{sum, isDef} {}
+ /*!
+ Record cloning
+ @return A clone of this record
+ */
+ ArchicadEverythingFilter* clonePtr() const override { return new ArchicadEverythingFilter(*this); };
+
+ // MARK: - Functions (const)
+ };
+
+}
+
+#endif //CONNECTOR_RECORD_ARCHICAD_EVERYTHING_FILTER
diff --git a/SpeckleConnector/Connector/Record/Model/Filter/ArchicadSelectionFilter.h b/SpeckleConnector/Connector/Record/Model/Filter/ArchicadSelectionFilter.h
new file mode 100644
index 0000000..231e3b4
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/Filter/ArchicadSelectionFilter.h
@@ -0,0 +1,38 @@
+#ifndef CONNECTOR_RECORD_ARCHICAD_SELECTION_FILTER
+#define CONNECTOR_RECORD_ARCHICAD_SELECTION_FILTER
+
+#include "Connector/Database/Identity/RecordID.h"
+#include "Connector/Record/Model/Filter/DirectSelectionSendFilter.h"
+
+namespace connector::record {
+
+ /*!
+ A send filter consisting of a list of selected Archicad element IDs
+ */
+ class ArchicadSelectionFilter : public DirectSelectionSendFilter {
+ public:
+
+ // MARK: - Types
+
+ using base = DirectSelectionSendFilter;
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ @param sum A summary
+ @param isDef True if this is the default filter
+ */
+ ArchicadSelectionFilter(const speckle::utility::String& sum = {}, bool isDef = false) : base{sum, isDef} {}
+ /*!
+ Record cloning
+ @return A clone of this record
+ */
+ ArchicadSelectionFilter* clonePtr() const override { return new ArchicadSelectionFilter(*this); };
+
+ // MARK: - Functions (const)
+ };
+
+}
+
+#endif //CONNECTOR_RECORD_ARCHICAD_SELECTION_FILTER
diff --git a/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.cpp b/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.cpp
new file mode 100644
index 0000000..4463b06
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.cpp
@@ -0,0 +1,71 @@
+#include "Connector/Record/Model/Filter/DirectSelectionSendFilter.h"
+
+#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
+#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
+
+#include
+#include
+
+using namespace active::serialise;
+using namespace connector::database;
+using namespace connector::record;
+using namespace speckle::utility;
+
+namespace {
+
+ ///Serialisation fields
+ enum FieldIndex {
+ selectedElemID,
+ };
+
+ ///Serialisation field IDs
+ static std::array fieldID = {
+ Identity{"selectedObjectIds"},
+ };
+
+}
+
+/*--------------------------------------------------------------------
+ Fill an inventory with the package items
+
+ inventory: The inventory to receive the package items
+
+ return: True if the package has added items to the inventory
+ --------------------------------------------------------------------*/
+bool DirectSelectionSendFilter::fillInventory(Inventory& inventory) const {
+ using enum Entry::Type;
+ inventory.merge(Inventory{
+ {
+ { fieldID[selectedElemID], selectedElemID, element },
+ },
+ }.withType(&typeid(DirectSelectionSendFilter)));
+ return base::fillInventory(inventory);
+} //DirectSelectionSendFilter::fillInventory
+
+
+/*--------------------------------------------------------------------
+ Get the specified cargo
+
+ item: The inventory item to retrieve
+
+ return: The requested cargo (nullptr on failure)
+ --------------------------------------------------------------------*/
+Cargo::Unique DirectSelectionSendFilter::getCargo(const Inventory::Item& item) const {
+ if (item.ownerType != &typeid(DirectSelectionSendFilter))
+ return base::getCargo(item);
+ using namespace active::serialise;
+ switch (item.index) {
+ case selectedElemID:
+ return std::make_unique>(m_selectedElements);
+ default:
+ return nullptr; //Requested an unknown index
+ }
+} //DirectSelectionSendFilter::getCargo
+
+
+/*--------------------------------------------------------------------
+ Set to the default package content
+ --------------------------------------------------------------------*/
+void DirectSelectionSendFilter::setDefault() {
+ m_selectedElements.clear();
+} //DirectSelectionSendFilter::setDefault
diff --git a/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.h b/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.h
new file mode 100644
index 0000000..b4ae701
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.h
@@ -0,0 +1,67 @@
+#ifndef CONNECTOR_RECORD_DIRECT_SELECT_SEND_FILTER
+#define CONNECTOR_RECORD_DIRECT_SELECT_SEND_FILTER
+
+#include "Connector/Database/Identity/RecordID.h"
+#include "Connector/Record/Model/Filter/SendFilter.h"
+
+namespace connector::record {
+
+ /*!
+ A send filter consisting of a list of selected element IDs
+ */
+ class DirectSelectionSendFilter : public SendFilter {
+ public:
+
+ // MARK: - Types
+
+ using base = SendFilter;
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ @param sum A summary
+ @param isDef True if this is the default filter
+ */
+ DirectSelectionSendFilter(const speckle::utility::String& sum = {}, bool isDef = false) : base{"Selection", sum, isDef} {}
+ /*!
+ Record cloning
+ @return A clone of this record
+ */
+ DirectSelectionSendFilter* clonePtr() const override { return new DirectSelectionSendFilter(*this); };
+
+ // MARK: - Functions (const)
+
+ /*!
+ Get the filtered element IDs
+ @return The filter elements
+ */
+ const database::ElementIDList& getElementIDs() const override { return m_selectedElements; }
+
+ // MARK: - Serialisation
+
+ /*!
+ Fill an inventory with the package items
+ @param inventory The inventory to receive the package items
+ @return True if the package has added items to the inventory
+ */
+ bool fillInventory(active::serialise::Inventory& inventory) const override;
+ /*!
+ Get the specified cargo
+ @param item The inventory item to retrieve
+ @return The requested cargo (nullptr on failure)
+ */
+ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
+ /*!
+ Set to the default package content
+ */
+ void setDefault() override;
+
+ private:
+ ///A list of selected element IDs
+ database::ElementIDList m_selectedElements;
+ };
+
+}
+
+#endif //CONNECTOR_RECORD_DIRECT_SELECT_SEND_FILTER
diff --git a/SpeckleConnector/Connector/Database/Model/Card/ModelCardDatabase.cpp b/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.cpp
similarity index 55%
rename from SpeckleConnector/Connector/Database/Model/Card/ModelCardDatabase.cpp
rename to SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.cpp
index 701a473..9dce303 100644
--- a/SpeckleConnector/Connector/Database/Model/Card/ModelCardDatabase.cpp
+++ b/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.cpp
@@ -1,27 +1,28 @@
-#include "Connector/Database/Model/Card/ModelCardDatabase.h"
+#include "Connector/Record/Model/Filter/EverythingSendFilter.h"
-#include "Active/Serialise/CargoHold.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
-#include "Active/Serialise/Package/Wrapper/ValueSettingWrap.h"
-#include "Active/Setting/ValueSetting.h"
+#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
+#include "Active/Utility/Concepts.h"
+
+#include
#include
using namespace active::serialise;
-using namespace active::setting;
using namespace connector::database;
+using namespace connector::record;
using namespace speckle::utility;
namespace {
///Serialisation fields
enum FieldIndex {
- model,
+ selectedElemID,
};
///Serialisation field IDs
static std::array fieldID = {
- Identity{"models"},
+ Identity{"selectedObjectIds"},
};
}
@@ -33,15 +34,15 @@ namespace {
return: True if the package has added items to the inventory
--------------------------------------------------------------------*/
-bool ModelCardDatabase::fillInventory(Inventory& inventory) const {
+bool EverythingSendFilter::fillInventory(Inventory& inventory) const {
using enum Entry::Type;
inventory.merge(Inventory{
{
- { fieldID[model], model, element },
+ { fieldID[selectedElemID], selectedElemID, element },
},
- }.withType(&typeid(ModelCardDatabase)));
- return true;
-} //ModelCardDatabase::fillInventory
+ }.withType(&typeid(EverythingSendFilter)));
+ return base::fillInventory(inventory);
+} //EverythingSendFilter::fillInventory
/*--------------------------------------------------------------------
@@ -51,21 +52,22 @@ bool ModelCardDatabase::fillInventory(Inventory& inventory) const {
return: The requested cargo (nullptr on failure)
--------------------------------------------------------------------*/
-Cargo::Unique ModelCardDatabase::getCargo(const Inventory::Item& item) const {
- if (item.ownerType != &typeid(ModelCardDatabase))
- return nullptr;
+Cargo::Unique EverythingSendFilter::getCargo(const Inventory::Item& item) const {
+ if (item.ownerType != &typeid(EverythingSendFilter))
+ return base::getCargo(item);
using namespace active::serialise;
switch (item.index) {
- case model:
- return std::make_unique>(); //NB: This is a placeholder until we define the content
+ case selectedElemID:
+ return std::make_unique>(m_emptyList);
default:
return nullptr; //Requested an unknown index
}
-} //ModelCardDatabase::getCargo
+} //EverythingSendFilter::getCargo
/*--------------------------------------------------------------------
Set to the default package content
--------------------------------------------------------------------*/
-void ModelCardDatabase::setDefault() {
-} //ModelCardDatabase::setDefault
+void EverythingSendFilter::setDefault() {
+ m_emptyList.clear();
+} //EverythingSendFilter::setDefault
diff --git a/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.h b/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.h
new file mode 100644
index 0000000..94e2303
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.h
@@ -0,0 +1,73 @@
+#ifndef CONNECTOR_RECORD_EVERYTHING_SEND_FILTER
+#define CONNECTOR_RECORD_EVERYTHING_SEND_FILTER
+
+#include "Connector/Database/Identity/RecordID.h"
+#include "Connector/Record/Model/Filter/SendFilter.h"
+
+namespace connector::record {
+
+ /*!
+ A send filter consisting of a list of selected element IDs
+ */
+ class EverythingSendFilter : public SendFilter {
+ public:
+
+ // MARK: - Types
+
+ using base = SendFilter;
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ @param sum A summary
+ @param isDef True if this is the default filter
+ */
+ EverythingSendFilter(const speckle::utility::String& sum = {}, bool isDef = false) : base{"Everything", sum, isDef} {}
+ /*!
+ Record cloning
+ @return A clone of this record
+ */
+ EverythingSendFilter* clonePtr() const override { return new EverythingSendFilter(*this); };
+
+ // MARK: - Functions (const)
+
+ /*!
+ Get the filtered element IDs
+ @return The filter elements
+ */
+ const database::ElementIDList& getElementIDs() const override { return m_emptyList; }
+ /*!
+ Determine if the filter has expired because an element in the selection has changed
+ @param changed The list of changed element IDs
+ @return True if the one of the changed elements is in the selection
+ */
+ virtual bool checkExpiry(const database::ElementIDList& changed) const override { return true; }
+
+ // MARK: - Serialisation
+
+ /*!
+ Fill an inventory with the package items
+ @param inventory The inventory to receive the package items
+ @return True if the package has added items to the inventory
+ */
+ bool fillInventory(active::serialise::Inventory& inventory) const override;
+ /*!
+ Get the specified cargo
+ @param item The inventory item to retrieve
+ @return The requested cargo (nullptr on failure)
+ */
+ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
+ /*!
+ Set to the default package content
+ */
+ void setDefault() override;
+
+ private:
+ ///Enables a const empty list to be returned
+ database::ElementIDList m_emptyList;
+ };
+
+}
+
+#endif //CONNECTOR_RECORD_EVERYTHING_SEND_FILTER
diff --git a/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.cpp b/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.cpp
new file mode 100644
index 0000000..a4f5c32
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.cpp
@@ -0,0 +1,68 @@
+/*!
+Copyright 2024 Ralph Wessel and Hugh Wessel
+Distributed under the MIT License (See accompanying file LICENSE.txt or copy at https://opensource.org/license/mit/)
+*/
+
+#include "Connector/Record/Model/Filter/FilterMover.h"
+
+#include "Connector/Record/Model/Filter/ArchicadEverythingFilter.h"
+#include "Connector/Record/Model/Filter/ArchicadSelectionFilter.h"
+
+using namespace active::serialise;
+using namespace active::utility;
+using namespace connector::record;
+
+namespace {
+
+ ///The tag used to identify a Speckle type name value
+ const char* attributeTag = "typeDiscriminator";
+ ///Identity for a SenderModelCard
+ const char* ArchicadSelectionTypeName = "ArchicadSelectionFilter";
+ ///Identity for a SenderModelCard
+ const char* ArchicadEverythingTypeName = "ArchicadEverythingFilter";
+
+}
+
+ ///The handler for model card packages
+std::shared_ptr FilterMover::m_handler = std::make_shared(attributeTag);
+
+
+/*--------------------------------------------------------------------
+ Constructor (for deserialisation)
+
+ handler: A package handler to reconstruct incoming packages
+ --------------------------------------------------------------------*/
+FilterMover::FilterMover() : Mover{m_handler} {
+ validateHandler();
+} //FilterMover::FilterMover
+
+
+/*--------------------------------------------------------------------
+ Constructor (for serialisation)
+
+ outgoing: An outgoing package
+ --------------------------------------------------------------------*/
+FilterMover::FilterMover(const active::serialise::Package& outgoing) : Mover{outgoing, m_handler} {
+ validateHandler();
+} //FilterMover::FilterMover
+
+
+/*--------------------------------------------------------------------
+ Constructor (when it will be used for serialisation only on an existing object)
+
+ package: A reference to the member variable
+ --------------------------------------------------------------------*/
+FilterMover::FilterMover(active::serialise::PackageUniqueWrap&& package) : Mover{std::move(package), m_handler} {
+
+} //FilterMover::FilterMover
+
+
+/*--------------------------------------------------------------------
+ Ensure the handler is populated
+ --------------------------------------------------------------------*/
+void FilterMover::validateHandler() {
+ if (!m_handler->empty())
+ return;
+ m_handler->add(ArchicadEverythingTypeName);
+ m_handler->add(ArchicadSelectionTypeName);
+} //FilterMover::validateHandler
diff --git a/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.h b/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.h
new file mode 100644
index 0000000..dc326a1
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.h
@@ -0,0 +1,51 @@
+#ifndef CONNECTOR_MODEL_SEND_FILTER_MOVER
+#define CONNECTOR_MODEL_SEND_FILTER_MOVER
+
+#include "Active/Serialise/Package/Wrapper/Mover.h"
+
+namespace connector::record {
+
+ /*!
+ Wrapper to box/unbox objects during (de)serialisation, including reading/writing a specified attribute to determine object type
+
+ Note that a derived class could also define the package handler, allowing the wrapper to be created via a default constructor that is
+ automatically bound to a set of internally defined object types
+ */
+ class FilterMover : public active::serialise::Mover {
+ public:
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor (primarily for a list of polymorphic objects)
+ */
+ FilterMover();
+ /*!
+ Constructor (when it will be used for serialisation only on an existing object)
+ @param package A reference to the member variable
+ */
+ FilterMover(const Package& package);
+ /*!
+ Constructor (for serialisation or deserialisation of a polymorphic member variable held in a unique pointer)
+ @param package A reference to the member variable
+ */
+ FilterMover(const Package::Unique& package);
+ /*!
+ Constructor (when it will be used for serialisation only on an existing object)
+ @param package A reference to the member variable
+ */
+ FilterMover(active::serialise::PackageUniqueWrap&& package);
+
+ private:
+ /*!
+ Ensure the handler is populated
+ */
+ static void validateHandler();
+
+ ///The handler for model card packages
+ static std::shared_ptr m_handler;
+ };
+
+}
+
+#endif //CONNECTOR_MODEL_SEND_FILTER_MOVER
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendFilter.cpp b/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.cpp
similarity index 60%
rename from SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendFilter.cpp
rename to SpeckleConnector/Connector/Record/Model/Filter/SendFilter.cpp
index 8abef93..c624d96 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendFilter.cpp
+++ b/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.cpp
@@ -1,11 +1,12 @@
-#include "Connector/Interface/Browser/Bridge/Send/Arg/SendFilter.h"
+#include "Connector/Record/Model/Filter/SendFilter.h"
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include
using namespace active::serialise;
-using namespace connector::interfac::browser::bridge;
+using namespace connector::database;
+using namespace connector::record;
using namespace speckle::utility;
namespace {
@@ -26,6 +27,23 @@ namespace {
}
+/*--------------------------------------------------------------------
+ Determine if the filter has expired because an element in the selection has changed
+
+ changed: The list of changed element IDs
+
+ return: True if the one of the changed elements is in the selection
+ --------------------------------------------------------------------*/
+bool SendFilter::checkExpiry(const ElementIDList& changed) const {
+ ElementIDList intersect;
+ ElementIDList mine{getElementIDs()}, theirs{changed};
+ std::sort(mine.begin(), mine.end());
+ std::sort(theirs.begin(), theirs.end());
+ std::set_intersection (mine.begin(), mine.end(), theirs.begin(), theirs.end(), std::back_inserter(intersect));
+ return !intersect.empty();
+} //SendFilter::checkExpiry
+
+
/*--------------------------------------------------------------------
Fill an inventory with the package items
@@ -59,11 +77,11 @@ Cargo::Unique SendFilter::getCargo(const Inventory::Item& item) const {
using namespace active::serialise;
switch (item.index) {
case nameID:
- return std::make_unique>(name);
+ return std::make_unique>(m_name);
case summaryID:
- return std::make_unique>(summary);
+ return std::make_unique>(m_summary);
case defaultID:
- return std::make_unique>(isDefault);
+ return std::make_unique>(m_isDefault);
default:
return nullptr; //Requested an unknown index
}
@@ -74,7 +92,7 @@ Cargo::Unique SendFilter::getCargo(const Inventory::Item& item) const {
Set to the default package content
--------------------------------------------------------------------*/
void SendFilter::setDefault() {
- name.clear();
- summary.clear();
- isDefault = false;
+ m_name.clear();
+ m_summary.clear();
+ m_isDefault = false;
} //SendFilter::setDefault
diff --git a/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.h b/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.h
new file mode 100644
index 0000000..999d5fd
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.h
@@ -0,0 +1,100 @@
+#ifndef CONNECTOR_RECORD_SEND_FILTER
+#define CONNECTOR_RECORD_SEND_FILTER
+
+#include "Active/Serialise/Package/Package.h"
+#include "Active/Utility/Cloner.h"
+#include "Connector/Database/Identity/RecordID.h"
+#include "Speckle/Utility/String.h"
+
+namespace connector::record {
+
+ /*!
+ Base class for element filters applied when a model is sent to a Speckle server
+ */
+ class SendFilter : public active::serialise::Package, public active::utility::Cloner {
+ public:
+
+ // MARK: - Types
+
+ using base = active::serialise::Package;
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ @param nm The filter name
+ @param sum A summary
+ @param isDef True if this is the default filter
+ */
+ SendFilter(const speckle::utility::String& nm = {}, const speckle::utility::String& sum = {}, bool isDef = false) :
+ m_name{nm}, m_summary{sum}, m_isDefault{isDef} {}
+ /*!
+ Destructor
+ */
+ virtual ~SendFilter() {}
+ /*!
+ Object cloning
+ @return A clone of this object
+ */
+ virtual SendFilter* clonePtr() const override = 0;
+
+ // MARK: - Functions (const)
+
+ /*!
+ Get the filter name
+ @return The filter name
+ */
+ const speckle::utility::String& getName() const { return m_name; };
+ /*!
+ Get a summary description of the filter function, e.g. "All selected elements"
+ @return The filter summary description
+ */
+ const speckle::utility::String& getSummary() const { return m_name; };
+ /*!
+ Determine if this is the default filter for model sends
+ @return True if this is the default filter
+ */
+ bool isDefault() const { return m_isDefault; };
+ /*!
+ Get the filtered element IDs
+ @return The filter elements
+ */
+ virtual const database::ElementIDList& getElementIDs() const = 0;
+ /*!
+ Determine if the filter has expired because an element in the selection has changed
+ @param changed The list of changed element IDs
+ @return True if the one of the changed elements is in the selection
+ */
+ virtual bool checkExpiry(const database::ElementIDList& changed) const;
+
+ // MARK: - Serialisation
+
+ /*!
+ Fill an inventory with the package items
+ @param inventory The inventory to receive the package items
+ @return True if the package has added items to the inventory
+ */
+ bool fillInventory(active::serialise::Inventory& inventory) const override;
+ /*!
+ Get the specified cargo
+ @param item The inventory item to retrieve
+ @return The requested cargo (nullptr on failure)
+ */
+ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
+ /*!
+ Set to the default package content
+ */
+ void setDefault() override;
+
+ private:
+ ///The filter name
+ speckle::utility::String m_name;
+ ///A summary
+ speckle::utility::String m_summary;
+ ///True if this is the default filter
+ bool m_isDefault = false;
+ };
+
+}
+
+#endif //CONNECTOR_RECORD_SEND_FILTER
diff --git a/SpeckleConnector/Connector/Record/Model/ModelCard.cpp b/SpeckleConnector/Connector/Record/Model/ModelCard.cpp
new file mode 100644
index 0000000..ec29cd7
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/ModelCard.cpp
@@ -0,0 +1,95 @@
+#include "Connector/Record/Model/ModelCard.h"
+
+#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
+#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
+
+#include
+
+using namespace active::container;
+using namespace active::serialise;
+using namespace connector::record;
+using namespace speckle::utility;
+
+namespace {
+
+ ///Serialisation fields
+ enum FieldIndex {
+ modelID,
+ projectID,
+ accountID,
+ serverURLID,
+ settingsID,
+ };
+
+ ///Serialisation field IDs
+ static std::array fieldID = {
+ Identity{"modelId"},
+ Identity{"projectId"},
+ Identity{"accountId"},
+ Identity{"serverURL"},
+ Identity{"settings"},
+ };
+
+}
+
+/*--------------------------------------------------------------------
+ Fill an inventory with the package items
+
+ inventory: The inventory to receive the package items
+
+ return: True if the package has added items to the inventory
+ --------------------------------------------------------------------*/
+bool ModelCard::fillInventory(Inventory& inventory) const {
+ using enum Entry::Type;
+ inventory.merge(Inventory{
+ {
+ { fieldID[modelID], modelID, element },
+ { fieldID[projectID], projectID, element },
+ { fieldID[accountID], accountID, element },
+ { fieldID[serverURLID], serverURLID, element },
+ { fieldID[settingsID], settingsID, element },
+ },
+ }.withType(&typeid(ModelCard)));
+ return base::fillInventory(inventory);
+} //ModelCard::fillInventory
+
+
+/*--------------------------------------------------------------------
+ Get the specified cargo
+
+ item: The inventory item to retrieve
+
+ return: The requested cargo (nullptr on failure)
+ --------------------------------------------------------------------*/
+Cargo::Unique ModelCard::getCargo(const Inventory::Item& item) const {
+ if (item.ownerType != &typeid(ModelCard))
+ return base::getCargo(item);
+ using namespace active::serialise;
+ switch (item.index) {
+ case modelID:
+ return std::make_unique>(m_modelID);
+ case projectID:
+ return std::make_unique>(m_projectID);
+ case accountID:
+ return std::make_unique>(m_accountID);
+ case serverURLID:
+ return std::make_unique>(m_serverURL);
+ case settingsID:
+ return std::make_unique>>(m_settings);
+ default:
+ return nullptr; //Requested an unknown index
+ }
+} //ModelCard::getCargo
+
+
+/*--------------------------------------------------------------------
+ Set to the default package content
+ --------------------------------------------------------------------*/
+void ModelCard::setDefault() {
+ base::setDefault();
+ m_modelID.clear();
+ m_projectID.clear();
+ m_accountID.clear();
+ m_serverURL.clear();
+ m_settings.clear();
+} //ModelCard::setDefault
diff --git a/SpeckleConnector/Connector/Record/Model/ModelCard.h b/SpeckleConnector/Connector/Record/Model/ModelCard.h
new file mode 100644
index 0000000..6db4ec5
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/ModelCard.h
@@ -0,0 +1,115 @@
+#ifndef CONNECTOR_RECORD_MODEL_CARD
+#define CONNECTOR_RECORD_MODEL_CARD
+
+#include "Active/Container/Vector.h"
+#include "Active/Serialise/Package/Package.h"
+#include "Active/Utility/Cloner.h"
+#include "Connector/Record/Model/CardSetting.h"
+#include "Speckle/Utility/String.h"
+#include "Speckle/Database/Content/Record.h"
+
+namespace connector::record {
+
+ /*!
+ A connector send filter
+ */
+ class ModelCard : public speckle::database::Record {
+ public:
+
+ // MARK: - Types
+
+ using base = speckle::database::Record;
+ //List of card settings
+ using SettingList = active::container::Vector;
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ */
+ ModelCard() {}
+ /*!
+ Constructor
+ @param modelID The model ID
+ @param projectID The project ID
+ @param accountID The account ID
+ @param serverURL The server URL
+ @param settings Any BIM host-related settings relevant to the appearance/rendering of the model, e.g. LoD, if properties included etc
+ */
+ ModelCard(const speckle::database::RecordID& modelID, const speckle::database::RecordID& projectID,
+ const speckle::database::RecordID& accountID, const speckle::utility::String& serverURL,
+ const SettingList& settings) :
+ m_modelID(modelID), m_projectID(projectID), m_accountID(accountID), m_serverURL(serverURL), m_settings(settings) {}
+ /*!
+ Destructor
+ */
+ virtual ~ModelCard() {}
+ /*!
+ Record cloning
+ @return A clone of this record
+ */
+ virtual ModelCard* clonePtr() const override { return new ModelCard(*this); };
+
+ // MARK: - Functions (const)
+
+ /*!
+ Get the model ID
+ @return The model ID
+ */
+ const speckle::utility::String& getModelID() const { return m_modelID; }
+ /*!
+ Get the setting type
+ @return The setting type
+ */
+ const speckle::utility::String& getProjectID() const { return m_projectID; }
+ /*!
+ Get the setting type
+ @return The setting type
+ */
+ const speckle::utility::String& getAccountID() const { return m_accountID; }
+ /*!
+ Get the setting type
+ @return The setting type
+ */
+ const speckle::utility::String& getServerURL() const { return m_serverURL; }
+ /*!
+ Get the card settings
+ @return The card settings
+ */
+ const SettingList& getSettings() const { return m_settings; }
+
+ // MARK: - Serialisation
+
+ /*!
+ Fill an inventory with the package items
+ @param inventory The inventory to receive the package items
+ @return True if the package has added items to the inventory
+ */
+ bool fillInventory(active::serialise::Inventory& inventory) const override;
+ /*!
+ Get the specified cargo
+ @param item The inventory item to retrieve
+ @return The requested cargo (nullptr on failure)
+ */
+ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
+ /*!
+ Set to the default package content
+ */
+ void setDefault() override;
+
+ private:
+ ///The model ID
+ speckle::database::RecordID m_modelID;
+ ///The project ID
+ speckle::database::RecordID m_projectID;
+ ///The user account ID
+ speckle::database::RecordID m_accountID;
+ ///The server URL
+ speckle::utility::String m_serverURL;
+ ///Settings for the model rendering, e.g. level of detail (LoD)
+ SettingList m_settings;
+ };
+
+}
+
+#endif //CONNECTOR_RECORD_MODEL_CARD
diff --git a/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.cpp b/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.cpp
new file mode 100644
index 0000000..3877f7c
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.cpp
@@ -0,0 +1,102 @@
+#include "Connector/Record/Model/ReceiverModelCard.h"
+
+#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
+#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
+
+#include
+
+using namespace active::serialise;
+using namespace connector::database;
+using namespace connector::record;
+using namespace speckle::database;
+using namespace speckle::utility;
+
+namespace {
+
+ ///Serialisation fields
+ enum FieldIndex {
+ projectNameID,
+ modelNameID,
+ selectedVersionID,
+ latestVersionID,
+ warningDismissedID,
+ bakedObjectsID,
+ };
+
+ ///Serialisation field IDs
+ static std::array fieldID = {
+ Identity{"projectName"},
+ Identity{"modelName"},
+ Identity{"selectedVersionID"},
+ Identity{"latestVersionID"},
+ Identity{"hasDismissedUpdateWarning"},
+ Identity{"bakedObjectIds"},
+ };
+
+}
+
+/*--------------------------------------------------------------------
+ Fill an inventory with the package items
+
+ inventory: The inventory to receive the package items
+
+ return: True if the package has added items to the inventory
+ --------------------------------------------------------------------*/
+bool ReceiverModelCard::fillInventory(Inventory& inventory) const {
+ using enum Entry::Type;
+ inventory.merge(Inventory{
+ {
+ { fieldID[projectNameID], projectNameID, element },
+ { fieldID[modelNameID], modelNameID, element },
+ { fieldID[selectedVersionID], selectedVersionID, element },
+ { fieldID[latestVersionID], latestVersionID, element },
+ { fieldID[warningDismissedID], warningDismissedID, element },
+ { fieldID[bakedObjectsID], bakedObjectsID, element },
+ },
+ }.withType(&typeid(ReceiverModelCard)));
+ return base::fillInventory(inventory);
+} //ReceiverModelCard::fillInventory
+
+
+/*--------------------------------------------------------------------
+ Get the specified cargo
+
+ item: The inventory item to retrieve
+
+ return: The requested cargo (nullptr on failure)
+ --------------------------------------------------------------------*/
+Cargo::Unique ReceiverModelCard::getCargo(const Inventory::Item& item) const {
+ if (item.ownerType != &typeid(ReceiverModelCard))
+ return base::getCargo(item);
+ using namespace active::serialise;
+ switch (item.index) {
+ case projectNameID:
+ return std::make_unique(m_projectName);
+ case modelNameID:
+ return std::make_unique(m_modelName);
+ case selectedVersionID:
+ return std::make_unique>(m_selectedVersionID);
+ case latestVersionID:
+ return std::make_unique>(m_latestVersionID);
+ case warningDismissedID:
+ return std::make_unique(m_hasDismissedUpdateWarning);
+ case bakedObjectsID:
+ return std::make_unique>(m_bakedObjectIDs);
+ default:
+ return nullptr; //Requested an unknown index
+ }
+} //ReceiverModelCard::getCargo
+
+
+/*--------------------------------------------------------------------
+ Set to the default package content
+ --------------------------------------------------------------------*/
+void ReceiverModelCard::setDefault() {
+ base::setDefault();
+ m_projectName.clear();
+ m_modelName.clear();
+ m_selectedVersionID.clear();
+ m_latestVersionID.clear();
+ m_hasDismissedUpdateWarning = false;
+ m_bakedObjectIDs.clear();
+} //ReceiverModelCard::setDefault
diff --git a/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.h b/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.h
new file mode 100644
index 0000000..95c4217
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.h
@@ -0,0 +1,119 @@
+#ifndef CONNECTOR_RECORD_RECEIVER_MODEL_CARD
+#define CONNECTOR_RECORD_RECEIVER_MODEL_CARD
+
+#include "Connector/Database/Identity/RecordID.h"
+#include "Connector/Record/Model/ModelCard.h"
+
+namespace connector::record {
+
+ class SendFilter;
+
+ /*!
+ A connector model send card - carries information about what was sent with the model
+ */
+ class ReceiverModelCard : public connector::record::ModelCard {
+ public:
+
+ // MARK: - Types
+
+ using base = connector::record::ModelCard;
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ */
+ ReceiverModelCard() {}
+ /*!
+ Constructor
+ @param projectName The project name
+ @param modelName The model name
+ @param selectedVersion The selected version ID
+ @param latestVersion The latest version ID
+ @param hasDimissedWarning True if the user has already dismissed an alert to update
+ @param bakedObjects The IDs of objects accepted in the receive
+ */
+ ReceiverModelCard(const speckle::database::RecordID& projectID, const speckle::utility::String& projectName,
+ const speckle::database::RecordID& modelID, const speckle::utility::String& modelName,
+ const speckle::database::RecordID& selectedVersion, const speckle::database::RecordID& latestVersion,
+ const speckle::database::RecordID& accountID, const speckle::utility::String& serverURL,
+ bool hasDimissedWarning, database::ElementIDList&& bakedObjects, const SettingList& settings) :
+ ModelCard{modelID, projectID, accountID, serverURL, settings},
+ m_projectName{projectName}, m_modelName{modelName}, m_selectedVersionID{selectedVersion}, m_latestVersionID{latestVersion},
+ m_hasDismissedUpdateWarning{hasDimissedWarning}, m_bakedObjectIDs{bakedObjects} {}
+ /*!
+ Record cloning
+ @return A clone of this record
+ */
+ virtual ReceiverModelCard* clonePtr() const override { return new ReceiverModelCard(*this); };
+
+ // MARK: - Functions (const)
+
+ /*!
+ Get the project name
+ @return The project name
+ */
+ const speckle::utility::String& getProjectName() const { return m_projectName; }
+ /*!
+ Get the model name
+ @return The model name
+ */
+ const speckle::utility::String& getModelName() const { return m_modelName; }
+ /*!
+ Get the selected version ID
+ @return The selected version ID
+ */
+ const speckle::database::RecordID& getSelectedVersionID() const { return m_selectedVersionID; }
+ /*!
+ Get the latest version ID
+ @return The latest version ID
+ */
+ const speckle::database::RecordID& getLatestVersionID() const { return m_latestVersionID; }
+ /*!
+ Determine if the user has already dismissed an alert to update
+ @return True if the user has already dismissed an alert to update
+ */
+ bool hasDismissedUpdateWarning() const { return m_hasDismissedUpdateWarning; }
+ /*!
+ Get the IDs of objects accepted in the receive
+ @return The accepted object IDs
+ */
+ const database::ElementIDList& getBakedObjectIDs() const { return m_bakedObjectIDs; }
+
+ // MARK: - Serialisation
+
+ /*!
+ Fill an inventory with the package items
+ @param inventory The inventory to receive the package items
+ @return True if the package has added items to the inventory
+ */
+ bool fillInventory(active::serialise::Inventory& inventory) const override;
+ /*!
+ Get the specified cargo
+ @param item The inventory item to retrieve
+ @return The requested cargo (nullptr on failure)
+ */
+ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
+ /*!
+ Set to the default package content
+ */
+ void setDefault() override;
+
+ private:
+ ///The received project name
+ speckle::utility::String m_projectName;
+ ///The received model name
+ speckle::utility::String m_modelName;
+ ///The ID of the version selected in the receive
+ speckle::database::RecordID m_selectedVersionID;
+ ///The ID of the latest version
+ speckle::database::RecordID m_latestVersionID;
+ ///True if the user has already dismissed an alert to update
+ bool m_hasDismissedUpdateWarning = false;
+ ///IDs of objects accepted in the receive
+ database::ElementIDList m_bakedObjectIDs;
+ };
+
+}
+
+#endif //CONNECTOR_RECORD_RECEIVER_MODEL_CARD
diff --git a/SpeckleConnector/Connector/Record/Model/SenderModelCard.cpp b/SpeckleConnector/Connector/Record/Model/SenderModelCard.cpp
new file mode 100644
index 0000000..e122cc3
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/SenderModelCard.cpp
@@ -0,0 +1,108 @@
+#include "Connector/Record/Model/SenderModelCard.h"
+
+#include "Active/Serialise/Package/Wrapper/PackageUniqueWrap.h"
+#include "Connector/Record/Model/Filter/FilterMover.h"
+#include "Connector/Record/Model/Filter/SendFilter.h"
+
+#include
+
+using namespace active::serialise;
+using namespace connector::record;
+using namespace speckle::utility;
+
+namespace {
+
+ ///Serialisation fields
+ enum FieldIndex {
+ sendFilterID,
+ };
+
+ ///Serialisation field IDs
+ static std::array fieldID = {
+ Identity{"sendFilter"},
+ };
+
+}
+
+/*--------------------------------------------------------------------
+ Default constructor
+ --------------------------------------------------------------------*/
+SenderModelCard::SenderModelCard() {
+
+} //SenderModelCard::SenderModelCard
+
+
+/*--------------------------------------------------------------------
+ Constructor
+
+ filter: The filter applied when the model was sent
+ --------------------------------------------------------------------*/
+SenderModelCard::SenderModelCard(const SendFilter& filter, const speckle::database::RecordID& modelID, const speckle::database::RecordID& projectID,
+ const speckle::database::RecordID& accountID, const speckle::utility::String& serverURL, const SettingList& settings) :
+ ModelCard{modelID, projectID, accountID, serverURL, settings}, m_filter(clone(filter))
+{
+} //SenderModelCard::SenderModelCard
+
+
+/*--------------------------------------------------------------------
+ Copy constructor
+
+ source: The object to copy
+ --------------------------------------------------------------------*/
+SenderModelCard::SenderModelCard(const SenderModelCard& source) : ModelCard{source} {
+ m_filter = (source.m_filter) ? clone(*source.m_filter) : nullptr;
+} //SenderModelCard::SenderModelCard
+
+
+/*--------------------------------------------------------------------
+ Destructor
+ --------------------------------------------------------------------*/
+SenderModelCard::~SenderModelCard() {
+} //SenderModelCard::~SenderModelCard
+
+
+/*--------------------------------------------------------------------
+ Fill an inventory with the package items
+
+ inventory: The inventory to receive the package items
+
+ return: True if the package has added items to the inventory
+ --------------------------------------------------------------------*/
+bool SenderModelCard::fillInventory(Inventory& inventory) const {
+ using enum Entry::Type;
+ inventory.merge(Inventory{
+ {
+ { fieldID[sendFilterID], sendFilterID, element },
+ },
+ }.withType(&typeid(SenderModelCard)));
+ return base::fillInventory(inventory);
+} //SenderModelCard::fillInventory
+
+
+/*--------------------------------------------------------------------
+ Get the specified cargo
+
+ item: The inventory item to retrieve
+
+ return: The requested cargo (nullptr on failure)
+ --------------------------------------------------------------------*/
+Cargo::Unique SenderModelCard::getCargo(const Inventory::Item& item) const {
+ if (item.ownerType != &typeid(SenderModelCard))
+ return base::getCargo(item);
+ using namespace active::serialise;
+ switch (item.index) {
+ case sendFilterID:
+ return std::make_unique(PackageUniqueWrap{m_filter});
+ default:
+ return nullptr; //Requested an unknown index
+ }
+} //SenderModelCard::getCargo
+
+
+/*--------------------------------------------------------------------
+ Set to the default package content
+ --------------------------------------------------------------------*/
+void SenderModelCard::setDefault() {
+ base::setDefault();
+ m_filter->setDefault();
+} //SenderModelCard::setDefault
diff --git a/SpeckleConnector/Connector/Record/Model/SenderModelCard.h b/SpeckleConnector/Connector/Record/Model/SenderModelCard.h
new file mode 100644
index 0000000..0b3e010
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Model/SenderModelCard.h
@@ -0,0 +1,81 @@
+#ifndef CONNECTOR_RECORD_SENDER_MODEL_CARD
+#define CONNECTOR_RECORD_SENDER_MODEL_CARD
+
+#include "Connector/Record/Model/ModelCard.h"
+
+namespace connector::record {
+
+ class SendFilter;
+
+ /*!
+ A connector model send card - carries information about what was sent with the model
+ */
+ class SenderModelCard : public connector::record::ModelCard {
+ public:
+
+ // MARK: - Types
+
+ using base = connector::record::ModelCard;
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ */
+ SenderModelCard();
+ /*!
+ Constructor
+ @param filter The filter applied when the model was sent
+ */
+ SenderModelCard(const SendFilter& filter, const speckle::database::RecordID& modelID, const speckle::database::RecordID& projectID,
+ const speckle::database::RecordID& accountID, const speckle::utility::String& serverURL, const SettingList& settings);
+ /*!
+ Copy constructor
+ @param source The object to copy
+ */
+ SenderModelCard(const SenderModelCard& source);
+ /*!
+ Destructor
+ */
+ ~SenderModelCard();
+ /*!
+ Record cloning
+ @return A clone of this record
+ */
+ virtual SenderModelCard* clonePtr() const override { return new SenderModelCard(*this); };
+
+ // MARK: - Functions (const)
+
+ /*!
+ Get the filter applied when the model was sent
+ @return The model filter
+ */
+ const SendFilter& getFilter() const { return *m_filter; }
+
+ // MARK: - Serialisation
+
+ /*!
+ Fill an inventory with the package items
+ @param inventory The inventory to receive the package items
+ @return True if the package has added items to the inventory
+ */
+ bool fillInventory(active::serialise::Inventory& inventory) const override;
+ /*!
+ Get the specified cargo
+ @param item The inventory item to retrieve
+ @return The requested cargo (nullptr on failure)
+ */
+ Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
+ /*!
+ Set to the default package content
+ */
+ void setDefault() override;
+
+ private:
+ ///The filter applied when the model was sent
+ std::unique_ptr m_filter;
+ };
+
+}
+
+#endif //CONNECTOR_RECORD_SENDER_MODEL_CARD
diff --git a/SpeckleConnector/Connector/Version.h b/SpeckleConnector/Connector/Version.h
index 5c79e01..97c24a3 100644
--- a/SpeckleConnector/Connector/Version.h
+++ b/SpeckleConnector/Connector/Version.h
@@ -7,7 +7,7 @@ namespace connector {
static const unsigned int versionMinor = 2;
- static const unsigned int versionPatch = 2;
+ static const unsigned int versionPatch = 3;
}
diff --git a/SpeckleLib/Speckle/Database/AccountDatabase.cpp b/SpeckleLib/Speckle/Database/AccountDatabase.cpp
index c6847c1..b6f2967 100644
--- a/SpeckleLib/Speckle/Database/AccountDatabase.cpp
+++ b/SpeckleLib/Speckle/Database/AccountDatabase.cpp
@@ -56,7 +56,7 @@ AccountDatabase::AccountDatabase(const active::file::Path& path) {
//Create accounts database storage (with schema)
m_store = std::make_unique(
//Engine
- std::make_unique(path,
+ std::make_shared(path,
//Schema
DBaseSchema{active::utility::String{accountsDBaseName},
//Tables
diff --git a/SpeckleLib/Speckle/Database/Content/Record.h b/SpeckleLib/Speckle/Database/Content/Record.h
index 2c9c089..5d70542 100644
--- a/SpeckleLib/Speckle/Database/Content/Record.h
+++ b/SpeckleLib/Speckle/Database/Content/Record.h
@@ -3,18 +3,19 @@
#include "Active/Database/Content/Record.h"
#include "Speckle/Database/Identity/Link.h"
+#include "Speckle/Database/Identity/RecordID.h"
namespace speckle::database {
/*!
Base class for a database record
*/
- class Record : public active::database::Record {
+ class Record : public active::database::Record {
public:
// MARK: - Types
- using base = active::database::Record;
+ using base = active::database::Record;
///Unique pointer
using Unique = std::unique_ptr;
///Shared pointer
@@ -24,11 +25,17 @@ namespace speckle::database {
// MARK: - Constructors
+ /*!
+ Default constructor
+ */
+ Record() : base{active::utility::Guid{true}.operator active::utility::String(),
+ active::utility::Guid{true}.operator active::utility::String()} {} //TODO: Implement a better default for the ID
/*!
Constructor
@param ID The record ID
*/
- Record(speckle::utility::String ID) : base{ID} {}
+ Record(speckle::utility::String ID, speckle::utility::String::Option globID = std::nullopt) :
+ base{ID, globID.value_or(active::utility::Guid{true}.operator active::utility::String())} {}
/*!
Destructor
*/
diff --git a/SpeckleLib/Speckle/Database/Identity/Index.h b/SpeckleLib/Speckle/Database/Identity/Index.h
index 8b49749..c3b3e66 100644
--- a/SpeckleLib/Speckle/Database/Identity/Index.h
+++ b/SpeckleLib/Speckle/Database/Identity/Index.h
@@ -2,8 +2,11 @@
#define SPECKLE_DATABASE_INDEX
#include "Active/Database/Identity/Link.h"
+#include "Speckle/Database/Identity/RecordID.h"
#include "Speckle/Utility/String.h"
+#include
+
namespace speckle::database {
/*!
@@ -13,12 +16,12 @@ namespace speckle::database {
this is typically a guid, for Revit a string and for Vectorworks a handle. Note that this index is not necessarily persistent between
sessions.
*/
- class Index : public active::database::Index {
+ class Index : public active::database::Index {
public:
// MARK: - Types
- using base = active::database::Index;
+ using base = active::database::Index;
// MARK: - Constructors
diff --git a/SpeckleLib/Speckle/Database/Identity/Link.h b/SpeckleLib/Speckle/Database/Identity/Link.h
index dc6624b..2789d22 100644
--- a/SpeckleLib/Speckle/Database/Identity/Link.h
+++ b/SpeckleLib/Speckle/Database/Identity/Link.h
@@ -17,12 +17,12 @@ namespace speckle::database {
A link may optionally carry any number of settings. In the context of a user selection (for example) there might be settings describing where
the user made the selection (e.g. the hole in a floor slab), allowing a tool working on that selection to be more precise.
*/
- class Link : public active::database::Link {
+ class Link : public active::database::Link {
public:
// MARK: - Types
- using base = active::database::Link;
+ using base = active::database::Link;
// MARK: - Constructors
diff --git a/SpeckleLib/Speckle/Database/Identity/RecordID.h b/SpeckleLib/Speckle/Database/Identity/RecordID.h
new file mode 100644
index 0000000..b26eadd
--- /dev/null
+++ b/SpeckleLib/Speckle/Database/Identity/RecordID.h
@@ -0,0 +1,20 @@
+#ifndef SPECKLE_DATABASE_ID
+#define SPECKLE_DATABASE_ID
+
+#include "Speckle/Utility/String.h"
+
+namespace speckle::database {
+
+ //Common Speckle record identifier type
+ using RecordID = speckle::utility::String;
+ //Common Speckle table identifier type
+ using TableID = speckle::utility::String;
+ //Common Speckle database identifier type
+ using DBaseID = speckle::utility::String;
+
+ //A list of record IDs
+ using RecordIDList = std::vector;
+
+}
+
+#endif //SPECKLE_DATABASE_ID
diff --git a/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreCore.cpp b/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreCore.cpp
new file mode 100644
index 0000000..84e653e
--- /dev/null
+++ b/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreCore.cpp
@@ -0,0 +1,297 @@
+#include "Speckle/Database/Storage/DocumentStore/DocumentStoreCore.h"
+
+#include "Active/Utility/Defer.h"
+#include "Active/Utility/Memory.h"
+#include "Active/Utility/String.h"
+#include "Speckle/Environment/Addon.h"
+#include "Speckle/Event/Type/DocStoreMergeEvent.h"
+#include "Speckle/Event/Type/ProjectEvent.h"
+#include "Speckle/Utility/Guid.h"
+#include "Speckle/Utility/String.h"
+
+#ifdef ARCHICAD
+#include
+#include
+#endif
+
+using namespace active::event;
+using namespace active::setting;
+using namespace speckle::database;
+using namespace speckle::environment;
+using namespace speckle::event;
+using namespace speckle::utility;
+
+using enum DocumentStoreCore::Status;
+
+namespace {
+
+#ifdef ARCHICAD
+ /*--------------------------------------------------------------------
+ Convert an Archicad API error code to a DocumentStoreCore status
+
+ acErrorCode: The API error code
+
+ return: An equivalent status code
+ --------------------------------------------------------------------*/
+ DocumentStoreCore::Status convertArchicadError(long acErrorCode) {
+ using enum DocumentStoreCore::Status;
+ switch (acErrorCode) {
+ case NoError:
+ return nominal;
+ case APIERR_BADPARS:
+ return badParameter;
+ case APIERR_BADID:
+ return badID;
+ default:
+ break;
+ }
+ return error;
+ } //convertArchicadError
+
+
+ /*--------------------------------------------------------------------
+ Determine if a specified data store exists
+
+ id: The store identity
+
+ return: True if the store exists
+ --------------------------------------------------------------------*/
+ bool isExistingStore(active::utility::NameID& storeID) {
+ if (storeID.id)
+ return true; //We must have a store if the ID is populated
+ GS::UniString storeName{String{storeID.name}};
+ API_Guid acID;
+ if (auto statusCode = convertArchicadError(ACAPI_AddOnObject_GetObjectGuidFromName(storeName, &acID)); statusCode != nominal)
+ throw std::system_error(DocumentStoreCore::makeError(statusCode));
+ storeID.id = Guid{acID};
+ if (!storeID.id) {
+ GS::Array storedObjects;
+ ACAPI_AddOnObject_GetObjectList(&storedObjects);
+ for (auto iter = storedObjects.Enumerate(); iter != nullptr; ++iter) {
+ API_Guid objGuid = *iter;
+ GS::UniString objName;
+ GSHandle content = nullptr;
+ auto scope = active::utility::defer([&content](){ BMKillHandle(&content); });
+ if (ACAPI_AddOnObject_GetObjectContent(objGuid, &objName, &content) == NoError) {
+ if (objName == storeName) {
+ storeID.id = Guid{objGuid};
+ break;
+ }
+ }
+ }
+ }
+ return storeID.id.operator bool(); //Returns true if the store ID is non-null, i.e. the object exists
+ } //isExistingStore
+
+
+ /*--------------------------------------------------------------------
+ Copy a GS handle to a Memory object
+
+ handle: The GS handle
+ memory: The Memory object to receive the data
+ --------------------------------------------------------------------*/
+ void copyHandleToMemory(const GSHandle& handle, active::utility::Memory& memory) {
+ auto storeSize = BMGetHandleSize(handle);
+ memory.resize(storeSize);
+ active::utility::Memory::copy(memory.data(), *handle, storeSize, storeSize);
+ } //copyHandleToMemory
+
+#endif
+
+ ///Category for DocumentStore processing errors
+ class DocumentStoreCategory : public std::error_category {
+ public:
+ ///Category name
+ const char* name() const noexcept override {
+ return "active::database::sqlite::category";
+ }
+ /*!
+ Get a message for a specified error code
+ @param errorCode A DocumentStore processing code
+ @return The error message for the specified code
+ */
+ std::string message(int errorCode) const override {
+ //TODO: These error messages are ok for developers - but can we help users more?
+ switch (static_cast(errorCode)) {
+ case nominal:
+ return "";
+ case badParameter:
+ return "An internal function has been incorrectly used";
+ case badID:
+ return "Internal data has been requested using an invalid identity";
+ case error:
+ return "A non-specific error occurred";
+ default:
+ return "An unknown error occurred";
+ }
+ }
+ };
+
+ ///DocumentStore processing category error instance
+ static DocumentStoreCategory instance;
+
+}
+
+/*--------------------------------------------------------------------
+ Make an error code for DocumentStore processing
+
+ return: An STL error code
+ --------------------------------------------------------------------*/
+std::error_code DocumentStoreCore::makeError(DocumentStoreCore::Status code) {
+ return std::error_code(static_cast(code), instance);
+} //DocumentStoreCore::makeError
+
+
+/*--------------------------------------------------------------------
+ Handle a document merge operation
+
+ event: The merge event
+
+ return: True if the event should be closed
+ --------------------------------------------------------------------*/
+bool DocumentStoreCore::handle(const DocStoreMergeEvent& event) {
+#ifdef ARCHICAD
+ if (event.objects == nullptr)
+ return false;
+ for (const auto& object : *event.objects) {
+ if (*object.name != String{m_id.name})
+ continue;
+ active::utility::Memory toMerge;
+ copyHandleToMemory(object.data, toMerge);
+ mergeStore(toMerge);
+ writeStore();
+ }
+#endif
+ return false;
+} //DocumentStoreCore::handle
+
+
+/*--------------------------------------------------------------------
+ Handle a project event
+
+ event: The project event
+
+ return: True if the event should be closed
+ --------------------------------------------------------------------*/
+bool DocumentStoreCore::handle(const event::ProjectEvent& event) {
+#ifdef ARCHICAD
+ switch (event.getType()) {
+ case APINotify_Close:
+ resetStore(); //Wipe the cache, forcing a full reload when the data is requested again (after a project is opened)
+ break;
+ case APINotify_PreSave: case APINotify_SendChanges:
+ writeStore(); //Ensure the data is stored with the save/send
+ break;
+ default:
+ break;
+ }
+#endif
+ return false;
+} //DocumentStoreCore::handle
+
+
+/*--------------------------------------------------------------------
+ Read the data stored in the document
+
+ return: The stored data (empty if the data doesn't exist)
+ --------------------------------------------------------------------*/
+active::utility::Memory DocumentStoreCore::readStore() const {
+ active::utility::Memory result;
+ //First establish that we actually have stored data to read
+ if (!isExistingStore(m_id))
+ return result;
+ //Read the stored data
+#ifdef ARCHICAD
+ GS::UniString storeName{String{m_id.name}};
+ GSHandle storedData;
+ auto scoped = active::utility::defer([&storedData](){ BMKillHandle(&storedData); });
+ if (auto statusCode = convertArchicadError(ACAPI_AddOnObject_GetObjectContent(Guid{m_id.id}, &storeName, &storedData)); statusCode != nominal)
+ throw std::system_error(makeError(statusCode));
+ //Copy the stored data into the result
+ copyHandleToMemory(storedData, result);
+#endif
+ return result;
+} //DocumentStoreCore::readStore
+
+
+/*--------------------------------------------------------------------
+ Write the data to document storage
+
+ toWrite: The data to write to storage
+ --------------------------------------------------------------------*/
+void DocumentStoreCore::writeStore() {
+#ifdef ARCHICAD
+ //Ensure a suitable data store exists
+ if (!isExistingStore(m_id)) {
+ //Create when missing
+ API_Guid acID;
+ if (auto statusCode = convertArchicadError(ACAPI_AddOnObject_CreateUniqueObject(String{m_id.name}, &acID)); statusCode != nominal)
+ throw std::system_error(makeError(statusCode));
+ m_id.id = Guid{acID};
+ }
+ //Reserve the storage object in TW
+ if (addon()->isSharedDocument()) {
+ GS::HashTable conflicts;
+ if (auto statusCode = convertArchicadError(ACAPI_AddOnObject_ReserveObjects({Guid{m_id.id}}, &conflicts)); statusCode != nominal)
+ throw std::system_error(makeError(statusCode));
+ //TODO: Implamenent handling for conflicts
+ }
+ auto toWrite = buildStore();
+ //Write the new data
+ GSHandle output = BMAllocateHandle(static_cast(toWrite.size()), ALLOCATE_CLEAR, 0);
+ auto scoped = active::utility::defer([&output](){ BMKillHandle(&output); });
+ active::utility::Memory::copy(*output, toWrite.data(), toWrite.size(), toWrite.size());
+ if (auto statusCode = convertArchicadError(ACAPI_AddOnObject_ModifyObject(Guid{m_id.id}, nullptr, &output)); statusCode != nominal)
+ throw std::system_error(makeError(statusCode));
+ //Release the storage object in TW
+ if (addon()->isSharedDocument()) {
+ if (auto statusCode = convertArchicadError(ACAPI_AddOnObject_ReleaseObjects({Guid{m_id.id}})); statusCode != nominal)
+ throw std::system_error(makeError(statusCode));
+ }
+#endif
+} //DocumentStoreCore::writeStore
+
+
+/*--------------------------------------------------------------------
+ Get the event subscription list
+
+ return: The subscription list (an empty list will put the subscriber into a suspended state)
+ --------------------------------------------------------------------*/
+Subscriber::Subscription DocumentStoreCore::subscription() const {
+ auto result = DocStoreSubscriber::subscription();
+ auto other = ProjectSubscriber::subscription();
+ result.insert(other.begin(), other.end());
+ return result;
+} //DocumentStoreCore::subscription
+
+
+/*--------------------------------------------------------------------
+ Receive a subscribed event
+
+ event: The incoming event
+
+ return: True if the event should be closed
+ --------------------------------------------------------------------*/
+bool DocumentStoreCore::receive(const active::event::Event& event) {
+ return DocStoreSubscriber::receive(event) || ProjectSubscriber::receive(event);
+} //DocumentStoreCore::receive
+
+
+/*--------------------------------------------------------------------
+ Attach participant components to the app (as required)
+
+ return: True if the participant is able to function
+ --------------------------------------------------------------------*/
+bool DocumentStoreCore::attach() {
+ return DocStoreSubscriber::attach() && ProjectSubscriber::attach();
+} //DocumentStoreCore::attach
+
+
+/*--------------------------------------------------------------------
+ Start the participant operation
+
+ return: True if the participant is able to continue
+ --------------------------------------------------------------------*/
+bool DocumentStoreCore::start() {
+ return DocStoreSubscriber::start() && ProjectSubscriber::start();
+} //DocumentStoreCore::start
diff --git a/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreCore.h b/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreCore.h
new file mode 100644
index 0000000..c4a0585
--- /dev/null
+++ b/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreCore.h
@@ -0,0 +1,142 @@
+#ifndef SPECKLE_DATABASE_DOCUMENT_STORE_CORE
+#define SPECKLE_DATABASE_DOCUMENT_STORE_CORE
+
+#include "Active/File/Path.h"
+#include "Active/Setting/SettingList.h"
+#include "Active/Database/Storage/DBaseSchema.h"
+#include "Active/Utility/NameID.h"
+#include "Speckle/Event/Subscriber/DocStoreSubscriber.h"
+#include "Speckle/Event/Subscriber/ProjectSubscriber.h"
+
+namespace speckle::database {
+
+ using DocumentStoreSchema = active::database::DBaseSchema<>;
+
+ /*!
+ Core functionality and definitions for a mechanism to store data in a BIM (3rd-party) document/database
+
+ Currently implement for Archicad Add-On Objects
+ */
+ class DocumentStoreCore : public event::DocStoreSubscriber, public event::ProjectSubscriber {
+ public:
+
+ // MARK: - Types
+
+ ///Status of of the DocumentStore database
+ enum class Status {
+ nominal, ///
+#include
+
+namespace speckle::database {
+
+ ///Concept for the ability to store objects in a document
+ template
+ concept DocumentStorable = (active::database::CanWrap || active::database::FlatType) &&
+ std::is_base_of_v &&
+ std::is_base_of_v;
+
+ /*!
+ A database engine to store records in a 3rd-party BIM document
+
+ Due to the fact that these records are intended to represent a single table and are stored in a document, the concepts of 'table' and
+ 'document' aren't currently applicable (this could be extended in future if there is a use-case)
+ @tparam Obj Interface for the stored object. NB: This can be a base class for an object hierarchy, not necessarily a concrete class
+ @tparam ObjWrapper Wrapper type for (de)serialising objects
+ @tparam Transport The serialisation transport mechanism for objects
+ @tparam ObjID The object identifier type, e.g. Guid
+ */
+ template
+ requires DocumentStorable
+ class DocumentStoreEngine : public DocumentStoreCore, public active::database::DBaseEngine {
+ public:
+
+ // MARK: - Types
+
+ using base = active::database::DBaseEngine;
+ using Filter = base::Filter;
+ using Outline = base::Outline;
+ using Cache = active::database::RecordCache;
+
+ // MARK: - Constructors
+
+ /*!
+ Constructor
+ @param id The document storage identifier
+ */
+ DocumentStoreEngine(const active::utility::NameID& id, DocumentStoreSchema&& schema) : DocumentStoreCore{id, std::move(schema)} {}
+ DocumentStoreEngine(const DocumentStoreEngine&) = delete;
+
+ // MARK: - Functions (const)
+
+ /*!
+ Get an object by index
+ @param ID The object ID
+ @param tableID Optional table ID (defaults to the first table)
+ @param documentID Optional document ID (when the object is bound to a specific document)
+ @return The requested object (nullptr on failure)
+ */
+ std::unique_ptr getObject(const ObjID& objID, std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override;
+ /*!
+ Get all objects
+ @param tableID Optional table ID (defaults to the first table)
+ @param documentID Optional document ID (filter for this document only - nullopt = all objects)
+ @return The requested objects (nullptr on failure)
+ */
+ active::container::Vector getObjects(std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override;
+ /*!
+ Get a filtered list of objects
+ @param filter The object filter
+ @param tableID Optional table ID (defaults to the first table)
+ @param documentID Optional document ID (filter for this document only - nullopt = all objects)
+ @return The filtered objects (nullptr on failure)
+ */
+ active::container::Vector getObjects(const Filter& filter, std::optional tableID = std::nullopt,
+ std::optional documentID = std::nullopt) const override;
+ /*!
+ Write an object to the database
+ @param object The object to write
+ @param objID The object ID
+ @param objDocID The object document-specific ID (unique within a specific document - nullopt if not document-bound)
+ @param tableID Optional table ID (defaults to the first table)
+ @param documentID Optional document ID (when the object is bound to a specific document)
+ */
+ void write(const Obj& object, const ObjID& objID, std::optional objDocID = std::nullopt,
+ std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override;
+ /*!
+ Erase an object by index
+ @param ID The object ID
+ @param tableID Optional table ID (defaults to the first table)
+ @param documentID Optional document ID (when the object is bound to a specific document)
+ @throw Exception thrown on SQL error
+ */
+ void erase(const ObjID& ID, std::optional tableID = std::nullopt,
+ std::optional documentID = std::nullopt) const override;
+ /*!
+ Erase all objects
+ @param tableID Optional table ID (defaults to the first table)
+ @param documentID Optional document ID (when the object is bound to a specific document)
+ @throw Exception thrown on SQL error
+ */
+ void erase(std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override;
+ /*!
+ Get the database outline
+ @return The database outline
+ */
+ Outline getOutline() const override;
+
+ protected:
+ /*!
+ Get the cache of records built from the data stored in the document
+ @return The cached records
+ */
+ Cache* getCache() const;
+ /*!
+ Build new store data from the latest records
+ @return Data to store from the latest records
+ */
+ active::utility::Memory buildStore() override;
+ /*!
+ Merge existing stored data with incoming stored data (from an external source)
+ @param toMerge The external stored data to merge
+ @return The merged data to be stored
+ */
+ void mergeStore(const active::utility::Memory& toMerge) override;
+ /*!
+ Reset the stored data (some external change has invalidated previous data, e.g. the document was closed)
+ */
+ void resetStore() override {
+ DocumentStoreCore::resetStore();
+ m_cache.reset();
+ }
+
+ private:
+ //Cached records from the document store
+ mutable std::unique_ptr m_cache;
+ };
+
+ /*--------------------------------------------------------------------
+ Get the cache of records built from the data stored in the document
+
+ return: The cached records (nullptr on failure)
+ --------------------------------------------------------------------*/
+ template
+ requires DocumentStorable
+ typename DocumentStoreEngine::Cache* DocumentStoreEngine::getCache() const {
+ if (m_cache)
+ return m_cache.get();
+ //Read the data stored in the document
+ auto storedData = readStore();
+ m_cache = std::make_unique();
+ if (!storedData)
+ return m_cache.get(); //Return an empty container if there's no data
+ //Import the document data into the record cache
+ if constexpr (std::is_same_v)
+ Transport().receive(std::forward(*m_cache), active::serialise::Identity{}, storedData);
+ else
+ Transport().receive(ObjWrapper{*m_cache}, active::serialise::Identity{}, storedData);
+ return m_cache.get();
+ } //DocumentStoreEngine::getCache
+
+
+ /*--------------------------------------------------------------------
+ Get an object by index
+
+ index: The object index
+ tableID: Optional table ID (defaults to the first table)
+ documentID: Optional document ID (when the object is bound to a specific document)
+
+ return: The requested object (nullptr on failure)
+ --------------------------------------------------------------------*/
+ template
+ requires DocumentStorable
+ std::unique_ptr DocumentStoreEngine::getObject(const ObjID& ID, std::optional tableID,
+ std::optional documentID) const {
+ return getCache()->read(ID);
+ } //DocumentStoreEngine::getObject
+
+
+ /*--------------------------------------------------------------------
+ Get all objects
+
+ tableID: Optional table ID (defaults to the first table)
+ documentID: Optional document ID (filter for this document only - nullopt = all objects)
+
+ return: The requested objects (nullptr on failure)
+ --------------------------------------------------------------------*/
+ template
+ requires DocumentStorable
+ active::container::Vector DocumentStoreEngine::getObjects(std::optional tableID,
+ std::optional documentID) const {
+ return getCache()->read();
+ } //DocumentStoreEngine::getObjects
+
+
+ /*--------------------------------------------------------------------
+ Get all objects
+
+ filter: The object filter
+ tableID: Optional table ID (defaults to the first table)
+ documentID: Optional document ID (filter for this document only - nullopt = all objects)
+
+ return: The requested objects (nullptr on failure)
+ --------------------------------------------------------------------*/
+ template
+ requires DocumentStorable
+ active::container::Vector DocumentStoreEngine::getObjects(const Filter& filter, std::optional tableID,
+ std::optional documentID) const {
+ return getCache()->read(filter);
+ } //DocumentStoreEngine::getObjects
+
+
+ /*--------------------------------------------------------------------
+ Write an object to the database
+
+ object: The object to write
+ objID: The object ID
+ objDocID: The object document-specific ID (unique within a specific document - nullopt if not document-bound)
+ tableID: Optional table ID (defaults to the first table)
+ documentID: Optional document ID (when the object is bound to a specific document)
+ --------------------------------------------------------------------*/
+ template
+ requires DocumentStorable
+ void DocumentStoreEngine::write(const Obj& object, const ObjID& objID, std::optional objDocID,
+ std::optional tableID, std::optional documentID) const {
+ getCache()->write(object); //NB: In future we might support duplicating records if objID != obj.id
+ } //DocumentStoreEngine::write
+
+
+ /*--------------------------------------------------------------------
+ Erase an object by index
+
+ objID: The object ID
+ tableID: Optional table ID (defaults to the first table)
+ documentID: Optional document ID (when the object is bound to a specific document)
+
+ return: True if the object was successfully erased
+ --------------------------------------------------------------------*/
+ template
+ requires DocumentStorable
+ void DocumentStoreEngine::erase(const ObjID& ID, std::optional tableID,
+ std::optional documentID) const {
+ getCache()->erase(ID);
+ } //DocumentStoreEngine::erase
+
+
+ /*--------------------------------------------------------------------
+ Erase all objects
+
+ tableID: Optional table ID (defaults to the first table)
+ documentID: Optional document ID (filter for this document only - nullopt = all objects)
+ --------------------------------------------------------------------*/
+ template
+ requires DocumentStorable