diff --git a/.gitignore b/.gitignore
index cc16dc0..64576df 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@ build/
Documents/
ResourceObjects/
Install/
+enc_temp_folder/
.vs/
.vscode/
xcuserdata/
diff --git a/SpeckleConnector/Connector.vcxproj b/SpeckleConnector/Connector.vcxproj
index ce15579..8f18d5c 100644
--- a/SpeckleConnector/Connector.vcxproj
+++ b/SpeckleConnector/Connector.vcxproj
@@ -94,6 +94,7 @@
+
@@ -104,6 +105,9 @@
+
+
+
@@ -111,7 +115,15 @@
+
+
+
+
+
+
+
+
@@ -122,6 +134,9 @@
+
+
+
@@ -137,6 +152,7 @@
+
@@ -148,6 +164,9 @@
+
+
+
@@ -155,7 +174,16 @@
+
+
+
+
+
+
+
+
+
@@ -166,6 +194,9 @@
+
+
+
diff --git a/SpeckleConnector/Connector.vcxproj.filters b/SpeckleConnector/Connector.vcxproj.filters
index 8eb6949..49772c8 100644
--- a/SpeckleConnector/Connector.vcxproj.filters
+++ b/SpeckleConnector/Connector.vcxproj.filters
@@ -59,6 +59,21 @@
{b6d6326c-77f4-414a-bda6-e3e587c7ded2}
+
+ {0ac4b0a4-6a2a-4a48-9757-1172effc20e7}
+
+
+ {6693f9a9-5ece-4853-b008-4064d1c551ab}
+
+
+ {806f4af5-fa02-49b8-ac01-297991fe90ea}
+
+
+ {8bb3df60-affe-4b66-8d78-f1b98e6ba8df}
+
+
+ {1d9a10c3-cac6-4b15-afb9-f117b99b3a24}
+
@@ -198,6 +213,51 @@
Connector\Interface\Browser\Bridge\Base
+
+ Connector\Record\Collection
+
+
+ Connector\Interface\Browser\Bridge\Send\Arg
+
+
+ Connector\Interface\Browser\Bridge\Send\Arg
+
+
+ Connector\Interface\Browser\Bridge\Send\Arg
+
+
+ Connector\Interface\Browser\Bridge\Send\Arg
+
+
+ Connector\Interface\Browser\Bridge\Send
+
+
+ Connector\Record\Collection
+
+
+ Connector\Record\Collection
+
+
+ Connector\Interface\Browser\Bridge\Selection
+
+
+ Connector\Interface\Browser\Bridge\Selection
+
+
+ Connector\Interface\Browser\Bridge\Selection\Arg
+
+
+ Connector\Interface\Browser\Bridge\Base
+
+
+ Connector\Interface\Browser\Bridge\Base
+
+
+ Connector\Environment
+
+
+ Connector\Interface\Browser\Bridge\Base
+
@@ -333,5 +393,53 @@
Connector\Interface\Browser\Bridge\Base
+
+ Connector\Record\Collection
+
+
+ Connector\Interface\Browser\Bridge\Send\Arg
+
+
+ Connector\Interface\Browser\Bridge\Send\Arg
+
+
+ Connector\Interface\Browser\Bridge\Send\Arg
+
+
+ Connector\Interface\Browser\Bridge\Send\Arg
+
+
+ Connector\Interface\Browser\Bridge\Send
+
+
+ Connector\Record\Collection
+
+
+ Connector\Record\Collection
+
+
+ Connector\Interface\Browser\Bridge\Selection
+
+
+ Connector\Interface\Browser\Bridge\Selection
+
+
+ Connector\Interface\Browser\Bridge\Selection\Arg
+
+
+ Connector\Interface\Browser\Bridge\Base
+
+
+ Connector\Interface\Browser\Bridge\Base
+
+
+ Connector\Environment
+
+
+ Connector\Interface\Browser\Bridge\Send\Arg
+
+
+ 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 8431d0f..f64172b 100644
--- a/SpeckleConnector/Connector.xcodeproj/project.pbxproj
+++ b/SpeckleConnector/Connector.xcodeproj/project.pbxproj
@@ -23,13 +23,27 @@
/* Begin PBXBuildFile section */
210CC8832C80E6A300610F58 /* TriggerEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 210CC8812C80E6A300610F58 /* TriggerEvent.cpp */; };
+ 21384BCD2CD2EE7400D4602B /* OpenUrl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21384BC92CD2EE7400D4602B /* OpenUrl.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 */; };
+ 2192460D2CA3469D00CF5703 /* ProjectCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2192460B2CA3469D00CF5703 /* ProjectCollection.cpp */; };
+ 2199BB552CDA4B1700A4BEEC /* ConnectorProject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2199BB522CDA4B1700A4BEEC /* ConnectorProject.cpp */; };
+ 2199BB7E2CDD3FA800A4BEEC /* HighlightObjects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2199BB7C2CDD3FA800A4BEEC /* HighlightObjects.cpp */; };
219F30422C769283009834E9 /* ConfigTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219F30402C769282009834E9 /* ConfigTests.cpp */; };
+ 21A0FB982CB723240023F24E /* FinishProxy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A0FB942CB723240023F24E /* FinishProxy.cpp */; };
+ 21A79EC92CCDA45C001754E4 /* HighlightModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A79EC52CCDA45C001754E4 /* HighlightModel.cpp */; };
+ 21A890BC2CC15C540087E732 /* SelectionInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A890B22CC15C540087E732 /* SelectionInfo.cpp */; };
+ 21A890BD2CC15C540087E732 /* GetSelection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A890B52CC15C540087E732 /* GetSelection.cpp */; };
+ 21A890BE2CC15C540087E732 /* SelectionBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A890B72CC15C540087E732 /* SelectionBridge.cpp */; };
+ 21AEF9EB2CAB56E5000B8681 /* SendError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9E32CAB56E5000B8681 /* SendError.cpp */; };
+ 21AEF9EC2CAB56E5000B8681 /* SendViaBrowserArgs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9E52CAB56E5000B8681 /* SendViaBrowserArgs.cpp */; };
+ 21AEF9EF2CAB5720000B8681 /* SendObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9EE2CAB5720000B8681 /* SendObject.cpp */; };
+ 21AEF9FA2CAC3897000B8681 /* ConversionResult.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9F92CAC3897000B8681 /* ConversionResult.cpp */; };
+ 21AEF9FD2CAD3FD8000B8681 /* GetSendSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9FB2CAD3FD8000B8681 /* GetSendSettings.cpp */; };
21B67CA32C769CB400FD64FC /* libActiveLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21F69EF52C64FE91008B6A06 /* libActiveLib.a */; };
21B67CA42C769CB400FD64FC /* libArchicad27.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21F69ECD2C64C035008B6A06 /* libArchicad27.a */; };
21B67CAC2C77329800FD64FC /* BaseBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21B67CA52C77329800FD64FC /* BaseBridge.cpp */; };
@@ -220,6 +234,7 @@
21F69F8D2C70D7EE008B6A06 /* GetAccounts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21F69F8B2C70D7EE008B6A06 /* GetAccounts.cpp */; };
21F69FBB2C762EF0008B6A06 /* ConfigBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21F69FB42C762EF0008B6A06 /* ConfigBridge.cpp */; };
21F69FBC2C762EF0008B6A06 /* GetConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21F69FB62C762EF0008B6A06 /* GetConfig.cpp */; };
+ 21FF70492CA1A7F400AAD99A /* RecordCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21FF70462CA1A7F400AAD99A /* RecordCollection.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -284,6 +299,8 @@
/* Begin PBXFileReference section */
210CC8812C80E6A300610F58 /* TriggerEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TriggerEvent.cpp; sourceTree = ""; };
210CC8822C80E6A300610F58 /* TriggerEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TriggerEvent.h; sourceTree = ""; };
+ 21384BC92CD2EE7400D4602B /* OpenUrl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OpenUrl.cpp; sourceTree = ""; };
+ 21384BCC2CD2EE7400D4602B /* OpenUrl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenUrl.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 = ""; };
@@ -298,10 +315,39 @@
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 = ""; };
+ 2192460B2CA3469D00CF5703 /* ProjectCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProjectCollection.cpp; sourceTree = ""; };
+ 2192460C2CA3469D00CF5703 /* ProjectCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProjectCollection.h; sourceTree = ""; };
219388682C4E5DE2002A0180 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; };
+ 2199BB512CDA481A00A4BEEC /* ConnectorFix.grc */ = {isa = PBXFileReference; lastKnownFileType = text; name = ConnectorFix.grc; path = RFIX/ConnectorFix.grc; sourceTree = ""; };
+ 2199BB522CDA4B1700A4BEEC /* ConnectorProject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConnectorProject.cpp; sourceTree = ""; };
+ 2199BB532CDA4B1700A4BEEC /* ConnectorProject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConnectorProject.h; sourceTree = ""; };
+ 2199BB5C2CDA93CE00A4BEEC /* ConnectorImagesFix.grc */ = {isa = PBXFileReference; lastKnownFileType = text; name = ConnectorImagesFix.grc; path = RFIX/ConnectorImagesFix.grc; sourceTree = ""; };
+ 2199BB792CDCEA3900A4BEEC /* SendConversionResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendConversionResult.h; sourceTree = ""; };
+ 2199BB7C2CDD3FA800A4BEEC /* HighlightObjects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HighlightObjects.cpp; sourceTree = ""; };
+ 2199BB7D2CDD3FA800A4BEEC /* HighlightObjects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HighlightObjects.h; sourceTree = ""; };
219F30352C768F0A009834E9 /* Connector-AC27-Test.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Connector-AC27-Test.bundle"; sourceTree = BUILT_PRODUCTS_DIR; };
219F30402C769282009834E9 /* ConfigTests.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = ConfigTests.cpp; sourceTree = ""; };
219F30432C7693B6009834E9 /* Connector-AC27-Debug.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Connector-AC27-Debug.xctestplan"; sourceTree = SOURCE_ROOT; };
+ 21A0FB942CB723240023F24E /* FinishProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FinishProxy.cpp; sourceTree = ""; };
+ 21A0FB972CB723240023F24E /* FinishProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FinishProxy.h; sourceTree = ""; };
+ 21A79EC52CCDA45C001754E4 /* HighlightModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HighlightModel.cpp; sourceTree = ""; };
+ 21A79EC82CCDA45C001754E4 /* HighlightModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HighlightModel.h; sourceTree = ""; };
+ 21A890B22CC15C540087E732 /* SelectionInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SelectionInfo.cpp; sourceTree = ""; };
+ 21A890B32CC15C540087E732 /* SelectionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectionInfo.h; sourceTree = ""; };
+ 21A890B52CC15C540087E732 /* GetSelection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetSelection.cpp; sourceTree = ""; };
+ 21A890B62CC15C540087E732 /* GetSelection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetSelection.h; sourceTree = ""; };
+ 21A890B72CC15C540087E732 /* SelectionBridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SelectionBridge.cpp; sourceTree = ""; };
+ 21A890B82CC15C540087E732 /* SelectionBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectionBridge.h; sourceTree = ""; };
+ 21AEF9E32CAB56E5000B8681 /* SendError.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendError.cpp; sourceTree = ""; };
+ 21AEF9E42CAB56E5000B8681 /* SendError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendError.h; sourceTree = ""; };
+ 21AEF9E52CAB56E5000B8681 /* SendViaBrowserArgs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendViaBrowserArgs.cpp; sourceTree = ""; };
+ 21AEF9E62CAB56E5000B8681 /* SendViaBrowserArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendViaBrowserArgs.h; sourceTree = ""; };
+ 21AEF9ED2CAB5720000B8681 /* SendObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendObject.h; sourceTree = ""; };
+ 21AEF9EE2CAB5720000B8681 /* SendObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendObject.cpp; sourceTree = ""; };
+ 21AEF9F82CAC3897000B8681 /* ConversionResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConversionResult.h; sourceTree = ""; };
+ 21AEF9F92CAC3897000B8681 /* ConversionResult.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConversionResult.cpp; sourceTree = ""; };
+ 21AEF9FB2CAD3FD8000B8681 /* GetSendSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetSendSettings.cpp; sourceTree = ""; };
+ 21AEF9FC2CAD3FD8000B8681 /* GetSendSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetSendSettings.h; sourceTree = ""; };
21B67CA52C77329800FD64FC /* BaseBridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BaseBridge.cpp; sourceTree = ""; };
21B67CA62C77329800FD64FC /* BaseBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseBridge.h; sourceTree = ""; };
21B67CA72C77329800FD64FC /* GetSourceApplicationName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetSourceApplicationName.cpp; sourceTree = ""; };
@@ -511,7 +557,6 @@
21D1E9AC2BF14AF200957EAA /* TeamworkProductVersion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TeamworkProductVersion.framework; path = "../Archicad 27/Support/Frameworks/TeamworkProductVersion.framework"; sourceTree = ""; };
21D1EA452BF14B0700957EAA /* VWMM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VWMM.framework; path = "../Vectorworks 2024/SDKLib/LibMac/Release/VWMM.framework"; sourceTree = ""; };
21D1EA4A2BF14BBC00957EAA /* Connector.grc */ = {isa = PBXFileReference; lastKnownFileType = text; name = Connector.grc; path = RINT/Connector.grc; sourceTree = ""; };
- 21D1EA4B2BF14BC700957EAA /* ConnectorFix.grc */ = {isa = PBXFileReference; lastKnownFileType = text; name = ConnectorFix.grc; path = RFIX/ConnectorFix.grc; sourceTree = ""; };
21D1EA4C2BF14BF000957EAA /* Module-Info27.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Module-Info27.plist"; path = "RINT.Archicad/EN-GB/Module-Info27.plist"; sourceTree = ""; };
21F69EC62C64C035008B6A06 /* SpeckleLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SpeckleLib.xcodeproj; path = ../SpeckleLib/SpeckleLib.xcodeproj; sourceTree = ""; };
21F69EDB2C64ED10008B6A06 /* ConnectorMenu.grc */ = {isa = PBXFileReference; lastKnownFileType = text; name = ConnectorMenu.grc; path = RINT/ConnectorMenu.grc; sourceTree = ""; };
@@ -534,6 +579,8 @@
21F69FB72C762EF0008B6A06 /* GetConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetConfig.h; sourceTree = ""; };
21F69FBD2C7630B3008B6A06 /* UpdateConfig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UpdateConfig.cpp; sourceTree = ""; };
21F69FBE2C7630B3008B6A06 /* UpdateConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UpdateConfig.h; sourceTree = ""; };
+ 21FF70462CA1A7F400AAD99A /* RecordCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordCollection.cpp; sourceTree = ""; };
+ 21FF70472CA1A7F400AAD99A /* RecordCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordCollection.h; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -929,6 +976,24 @@
path = Identity;
sourceTree = "";
};
+ 2199BB4E2CDA47F900A4BEEC /* Fixed */ = {
+ isa = PBXGroup;
+ children = (
+ 2199BB512CDA481A00A4BEEC /* ConnectorFix.grc */,
+ 2199BB5C2CDA93CE00A4BEEC /* ConnectorImagesFix.grc */,
+ );
+ name = Fixed;
+ sourceTree = "";
+ };
+ 2199BB542CDA4B1700A4BEEC /* Environment */ = {
+ isa = PBXGroup;
+ children = (
+ 2199BB522CDA4B1700A4BEEC /* ConnectorProject.cpp */,
+ 2199BB532CDA4B1700A4BEEC /* ConnectorProject.h */,
+ );
+ path = Environment;
+ sourceTree = "";
+ };
219F30412C769282009834E9 /* ConnectorTests */ = {
isa = PBXGroup;
children = (
@@ -939,6 +1004,43 @@
path = ConnectorTests;
sourceTree = "";
};
+ 21A890B42CC15C540087E732 /* Arg */ = {
+ isa = PBXGroup;
+ children = (
+ 21A890B22CC15C540087E732 /* SelectionInfo.cpp */,
+ 21A890B32CC15C540087E732 /* SelectionInfo.h */,
+ );
+ path = Arg;
+ sourceTree = "";
+ };
+ 21A890B92CC15C540087E732 /* Selection */ = {
+ isa = PBXGroup;
+ children = (
+ 21A890B42CC15C540087E732 /* Arg */,
+ 21A890B52CC15C540087E732 /* GetSelection.cpp */,
+ 21A890B62CC15C540087E732 /* GetSelection.h */,
+ 21A890B72CC15C540087E732 /* SelectionBridge.cpp */,
+ 21A890B82CC15C540087E732 /* SelectionBridge.h */,
+ );
+ path = Selection;
+ sourceTree = "";
+ };
+ 21AEF9E72CAB56E5000B8681 /* Arg */ = {
+ isa = PBXGroup;
+ children = (
+ 21AEF9F92CAC3897000B8681 /* ConversionResult.cpp */,
+ 21AEF9F82CAC3897000B8681 /* ConversionResult.h */,
+ 2199BB792CDCEA3900A4BEEC /* SendConversionResult.h */,
+ 21AEF9E32CAB56E5000B8681 /* SendError.cpp */,
+ 21AEF9E42CAB56E5000B8681 /* SendError.h */,
+ 21AEF9EE2CAB5720000B8681 /* SendObject.cpp */,
+ 21AEF9ED2CAB5720000B8681 /* SendObject.h */,
+ 21AEF9E52CAB56E5000B8681 /* SendViaBrowserArgs.cpp */,
+ 21AEF9E62CAB56E5000B8681 /* SendViaBrowserArgs.h */,
+ );
+ path = Arg;
+ sourceTree = "";
+ };
21B67CAB2C77329800FD64FC /* Base */ = {
isa = PBXGroup;
children = (
@@ -957,6 +1059,12 @@
21B67CA82C77329800FD64FC /* GetSourceApplicationName.h */,
21B67CA92C77329800FD64FC /* GetSourceApplicationVersion.cpp */,
21B67CAA2C77329800FD64FC /* GetSourceApplicationVersion.h */,
+ 21A79EC52CCDA45C001754E4 /* HighlightModel.cpp */,
+ 21A79EC82CCDA45C001754E4 /* HighlightModel.h */,
+ 2199BB7C2CDD3FA800A4BEEC /* HighlightObjects.cpp */,
+ 2199BB7D2CDD3FA800A4BEEC /* HighlightObjects.h */,
+ 21384BC92CD2EE7400D4602B /* OpenUrl.cpp */,
+ 21384BCC2CD2EE7400D4602B /* OpenUrl.h */,
21D0BDD52C935DAE0077E104 /* RemoveModel.cpp */,
21D0BDD62C935DAE0077E104 /* RemoveModel.h */,
21D0BDD22C935D1A0077E104 /* UpdateModel.cpp */,
@@ -1023,8 +1131,11 @@
21D0BD5D2C89BFEA0077E104 /* Send */ = {
isa = PBXGroup;
children = (
+ 21AEF9E72CAB56E5000B8681 /* Arg */,
21D0BD962C8F13F30077E104 /* GetSendFilters.cpp */,
21D0BD952C8F13F30077E104 /* GetSendFilters.h */,
+ 21AEF9FB2CAD3FD8000B8681 /* GetSendSettings.cpp */,
+ 21AEF9FC2CAD3FD8000B8681 /* GetSendSettings.h */,
21D0BD8D2C8EE4490077E104 /* Send.cpp */,
21D0BD8A2C8EE4490077E104 /* Send.h */,
21D0BD5B2C89BFEA0077E104 /* SendBridge.cpp */,
@@ -1036,6 +1147,7 @@
21D0BDD82C9387E60077E104 /* Record */ = {
isa = PBXGroup;
children = (
+ 21FF70482CA1A7F400AAD99A /* Collection */,
21D0BDD92C9387F70077E104 /* Model */,
);
path = Record;
@@ -1080,7 +1192,6 @@
isa = PBXGroup;
children = (
21D1EA4A2BF14BBC00957EAA /* Connector.grc */,
- 21D1EA4B2BF14BC700957EAA /* ConnectorFix.grc */,
21F69EDB2C64ED10008B6A06 /* ConnectorMenu.grc */,
21D1EA4C2BF14BF000957EAA /* Module-Info27.plist */,
21F69EFE2C66AD55008B6A06 /* SpecklePalette.grc */,
@@ -1133,6 +1244,7 @@
21B67CCD2C77694500FD64FC /* Connector.h */,
21F69F102C677BC0008B6A06 /* ConnectorResource.h */,
21B67CCB2C77670400FD64FC /* Database */,
+ 2199BB542CDA4B1700A4BEEC /* Environment */,
21F69F092C677BC0008B6A06 /* Event */,
21F69F0E2C677BC0008B6A06 /* Interface */,
21D0BDD82C9387E60077E104 /* Record */,
@@ -1159,6 +1271,7 @@
21B67CAB2C77329800FD64FC /* Base */,
21F69FB82C762EF0008B6A06 /* Config */,
21D0BD5D2C89BFEA0077E104 /* Send */,
+ 21A890B92CC15C540087E732 /* Selection */,
21B67CD82C78C83800FD64FC /* Test */,
);
path = Bridge;
@@ -1188,6 +1301,19 @@
path = Config;
sourceTree = "";
};
+ 21FF70482CA1A7F400AAD99A /* Collection */ = {
+ isa = PBXGroup;
+ children = (
+ 21A0FB942CB723240023F24E /* FinishProxy.cpp */,
+ 21A0FB972CB723240023F24E /* FinishProxy.h */,
+ 21FF70462CA1A7F400AAD99A /* RecordCollection.cpp */,
+ 21FF70472CA1A7F400AAD99A /* RecordCollection.h */,
+ 2192460B2CA3469D00CF5703 /* ProjectCollection.cpp */,
+ 2192460C2CA3469D00CF5703 /* ProjectCollection.h */,
+ );
+ path = Collection;
+ sourceTree = "";
+ };
7EA5F91E157FA18400693CEA /* EN-GB */ = {
isa = PBXGroup;
children = (
@@ -1199,6 +1325,7 @@
81494D9D09DA5892006864FB /* Resource */ = {
isa = PBXGroup;
children = (
+ 2199BB4E2CDA47F900A4BEEC /* Fixed */,
7EA5F91E157FA18400693CEA /* EN-GB */,
);
name = Resource;
@@ -1393,28 +1520,39 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 21AEF9FA2CAC3897000B8681 /* ConversionResult.cpp in Sources */,
21D0BDAB2C8F363E0077E104 /* CardSetting.cpp in Sources */,
21B67CE32C78D1FB00FD64FC /* SayHiArg.cpp in Sources */,
+ 21AEF9EB2CAB56E5000B8681 /* SendError.cpp in Sources */,
215F08462C9633A800CD343B /* EverythingSendFilter.cpp in Sources */,
21F69FBB2C762EF0008B6A06 /* ConfigBridge.cpp in Sources */,
21F69F8A2C70D2C4008B6A06 /* AccountBridge.cpp in Sources */,
+ 21A890BE2CC15C540087E732 /* SelectionBridge.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 */,
+ 21A0FB982CB723240023F24E /* FinishProxy.cpp in Sources */,
21B67CC32C77649F00FD64FC /* GetDocumentState.cpp in Sources */,
+ 2199BB7E2CDD3FA800A4BEEC /* HighlightObjects.cpp in Sources */,
21D0BD602C89BFEA0077E104 /* SendBridge.cpp in Sources */,
21D0BD972C8F13F30077E104 /* GetSendFilters.cpp in Sources */,
21B67CAC2C77329800FD64FC /* BaseBridge.cpp in Sources */,
+ 2192460D2CA3469D00CF5703 /* ProjectCollection.cpp in Sources */,
21D0BD6A2C8A0DB40077E104 /* GetIsDevMode.cpp in Sources */,
210CC8832C80E6A300610F58 /* TriggerEvent.cpp in Sources */,
21B67CEB2C78D27200FD64FC /* DocumentInfo.cpp in Sources */,
21B67CB92C774BFA00FD64FC /* GetConnectorVersion.cpp in Sources */,
21B67CD92C78C83800FD64FC /* TestBridge.cpp in Sources */,
+ 21AEF9FD2CAD3FD8000B8681 /* GetSendSettings.cpp in Sources */,
214B7A372C764BCD00D586C1 /* UpdateConfig.cpp in Sources */,
+ 21AEF9EC2CAB56E5000B8681 /* SendViaBrowserArgs.cpp in Sources */,
+ 21FF70492CA1A7F400AAD99A /* RecordCollection.cpp in Sources */,
+ 21A79EC92CCDA45C001754E4 /* HighlightModel.cpp in Sources */,
21B67CC02C775A0D00FD64FC /* GetDocumentInfo.cpp in Sources */,
21D0BDD42C935D1A0077E104 /* UpdateModel.cpp in Sources */,
+ 21A890BD2CC15C540087E732 /* GetSelection.cpp in Sources */,
21B67CE72C78D23B00FD64FC /* ConnectorConfig.cpp in Sources */,
21B67CAD2C77329800FD64FC /* GetSourceApplicationName.cpp in Sources */,
21D0BDE02C9393980077E104 /* SendFilter.cpp in Sources */,
@@ -1422,6 +1560,10 @@
215F082A2C947F4400CD343B /* CardMover.cpp in Sources */,
215F08372C95808B00CD343B /* ReceiverModelCard.cpp in Sources */,
21D0BDD72C935DAE0077E104 /* RemoveModel.cpp in Sources */,
+ 21A890BC2CC15C540087E732 /* SelectionInfo.cpp in Sources */,
+ 2199BB552CDA4B1700A4BEEC /* ConnectorProject.cpp in Sources */,
+ 21AEF9EF2CAB5720000B8681 /* SendObject.cpp in Sources */,
+ 21384BCD2CD2EE7400D4602B /* OpenUrl.cpp in Sources */,
21B67CDC2C78C88000FD64FC /* SayHi.cpp in Sources */,
215F082E2C94C5C000CD343B /* FilterMover.cpp in Sources */,
21F69F122C677BC0008B6A06 /* ConnectorMenu.cpp in Sources */,
@@ -1967,7 +2109,7 @@
);
LOCALISATION_SUFFIX = "EN-GB";
MACH_O_TYPE = mh_bundle;
- MACOSX_DEPLOYMENT_TARGET = 11.0;
+ MACOSX_DEPLOYMENT_TARGET = 13.3;
NNA_WARNING_CPLUSPLUSFLAGS = "-Wno-deprecated";
OBJROOT = "";
ONLY_ACTIVE_ARCH = YES;
@@ -2074,7 +2216,7 @@
);
LOCALISATION_SUFFIX = "EN-GB";
MACH_O_TYPE = mh_bundle;
- MACOSX_DEPLOYMENT_TARGET = 11.0;
+ MACOSX_DEPLOYMENT_TARGET = 13.3;
NNA_WARNING_CPLUSPLUSFLAGS = "-Wno-deprecated";
OBJROOT = "";
PLUGIN_FOLDER = "";
diff --git a/SpeckleConnector/Connector/Connector.cpp b/SpeckleConnector/Connector/Connector.cpp
index c4369dd..1a4e1d6 100644
--- a/SpeckleConnector/Connector/Connector.cpp
+++ b/SpeckleConnector/Connector/Connector.cpp
@@ -1,9 +1,9 @@
#include "Active/File/Directory.h"
#include "ConnectorResource.h"
#include "Connector/Connector.h"
-#include "Connector/Database/ModelCardDatabase.h"
-#include "Interface/ConnectorMenu.h"
-#include "Interface/ConnectorPalette.h"
+#include "Connector/Environment/ConnectorProject.h"
+#include "Connector/Interface/ConnectorMenu.h"
+#include "Connector/Interface/ConnectorPalette.h"
#include "Speckle/Database/AccountDatabase.h"
#include "Speckle/Environment/Addon.h"
#include "Speckle/Utility/String.h"
@@ -11,7 +11,7 @@
using namespace active::file;
using namespace active::environment;
using namespace connector;
-using namespace connector::database;
+using namespace connector::environment;
using namespace speckle::database;
using namespace speckle::environment;
using namespace speckle::utility;
@@ -29,26 +29,27 @@ namespace {
ConnectorInstance(const String& name) : ConnectorAddon{name} {
add();
add();
- //The connector 'owns' the model card database, so the publisher list should only hold a weak reference
- addWeak(m_modelCards.getSubscription());
}
// MARK: Functions (const)
- /*!
- Get the model card database
- @return The model card database
- */
- const ModelCardDatabase* getModelCardDatabase() const override { return &m_modelCards; }
/*!
Get the account database
@return The account database
*/
const AccountDatabase* getAccountDatabase() const override;
+ protected:
+ /*!
+ Make a new new project. Allows Addon subclasses to define a Project subclass with additional functions/databases
+ @return A new project instance
+ */
+ virtual std::shared_ptr makeProject() const override {
+ return std::dynamic_pointer_cast(std::make_shared());
+ }
+
private:
mutable std::unique_ptr m_account;
- ModelCardDatabase m_modelCards;
};
///The active addon instance
diff --git a/SpeckleConnector/Connector/Connector.h b/SpeckleConnector/Connector/Connector.h
index 3eed043..06ad932 100755
--- a/SpeckleConnector/Connector/Connector.h
+++ b/SpeckleConnector/Connector/Connector.h
@@ -4,9 +4,6 @@
namespace speckle::database {
class AccountDatabase;
}
-namespace connector::database {
- class ModelCardDatabase;
-}
namespace connector {
@@ -16,11 +13,6 @@ namespace connector {
// MARK: Functions (const)
- /*!
- Get the model card database
- @return The model card database
- */
- const virtual database::ModelCardDatabase* getModelCardDatabase() const = 0;
/*!
Get the account database
@return The account database
diff --git a/SpeckleConnector/Connector/ConnectorResource.h b/SpeckleConnector/Connector/ConnectorResource.h
index 68b5c29..17e4482 100755
--- a/SpeckleConnector/Connector/ConnectorResource.h
+++ b/SpeckleConnector/Connector/ConnectorResource.h
@@ -28,6 +28,7 @@ enum StringResource {
enum TitleString {
addonNameID = 1,
addonDescriptionID,
+ noStoreyID,
};
@@ -37,7 +38,7 @@ enum PromptString {
//Information strings (in UI content, logging, reports)
-enum InfoString {
+enum GeneralString {
};
@@ -53,6 +54,11 @@ enum WarningString {
//Error strings (errors displayed in alerts)
enum ErrorString {
+ noSelectedModelItemsID = 1,
+ modelCardNotFoundID,
+ noProjectOpenID,
+ accountNotFoundID,
+ elementTypeNotConvertedID,
};
#endif //CONNECTOR_RESOURCE
diff --git a/SpeckleConnector/Connector/Database/Identity/RecordID.h b/SpeckleConnector/Connector/Database/Identity/RecordID.h
index ad36268..1437e49 100644
--- a/SpeckleConnector/Connector/Database/Identity/RecordID.h
+++ b/SpeckleConnector/Connector/Database/Identity/RecordID.h
@@ -1,16 +1,8 @@
#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/ModelCardDatabase.cpp b/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp
index 761d8fc..9a2f0b3 100644
--- a/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp
+++ b/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp
@@ -71,6 +71,16 @@ ModelCardDatabase::ModelCardDatabase() {
ModelCardDatabase::~ModelCardDatabase() {}
+/*--------------------------------------------------------------------
+ Get a specified card from the database
+
+ return: The requested card (nullptr on failure)
+ --------------------------------------------------------------------*/
+ModelCard::Unique ModelCardDatabase::getCard(const speckle::utility::String& cardID) const {
+ return m_store->getObject(cardID);
+} //ModelCardDatabase::getCard
+
+
/*--------------------------------------------------------------------
Get all model cards
@@ -101,6 +111,16 @@ void ModelCardDatabase::erase(const String& cardID) const {
} //ModelCardDatabase::erase
+/*--------------------------------------------------------------------
+ Get the unique ID of the engine storage
+
+ return: The databas unique ID
+ --------------------------------------------------------------------*/
+RecordID ModelCardDatabase::getStoreID() const {
+ return m_engine->getUniqueID();
+} //ModelCardDatabase::getStoreID
+
+
/*--------------------------------------------------------------------
Get a serialisation wrapper for the database
diff --git a/SpeckleConnector/Connector/Database/ModelCardDatabase.h b/SpeckleConnector/Connector/Database/ModelCardDatabase.h
index d2e7db6..2f1e080 100644
--- a/SpeckleConnector/Connector/Database/ModelCardDatabase.h
+++ b/SpeckleConnector/Connector/Database/ModelCardDatabase.h
@@ -29,6 +29,11 @@ namespace connector::database {
// MARK: - Functions (const)
+ /*!
+ Get a specified card from the database
+ @return The requested card (nullptr on failure)
+ */
+ record::ModelCard::Unique getCard(const speckle::utility::String& cardID) const;
/*!
Get all model cards
@return All the cards
@@ -49,6 +54,11 @@ namespace connector::database {
@return A database wrapper
*/
std::unique_ptr wrapper() const;
+ /*!
+ Get the unique ID of the engine storage
+ @return The database unique ID
+ */
+ speckle::database::RecordID getStoreID() const;
// MARK: - Functions (mutating)
diff --git a/SpeckleConnector/Connector/Environment/ConnectorProject.cpp b/SpeckleConnector/Connector/Environment/ConnectorProject.cpp
new file mode 100644
index 0000000..c639094
--- /dev/null
+++ b/SpeckleConnector/Connector/Environment/ConnectorProject.cpp
@@ -0,0 +1,33 @@
+#include "Connector/Environment/ConnectorProject.h"
+
+#include "Connector/Connector.h"
+#include "Connector/Database/ModelCardDatabase.h"
+
+using namespace active::event;
+using namespace connector::database;
+using namespace connector::environment;
+using namespace speckle::utility;
+
+/*--------------------------------------------------------------------
+ Default constructor
+ --------------------------------------------------------------------*/
+ConnectorProject::ConnectorProject() {
+ m_modelCards = std::make_shared();
+ connector()->addWeak(m_modelCards->getSubscription());
+}
+
+
+/*--------------------------------------------------------------------
+ Destructor
+ --------------------------------------------------------------------*/
+ConnectorProject::~ConnectorProject() {}
+
+
+/*--------------------------------------------------------------------
+ Get the model card database
+
+ return; The model card database
+ --------------------------------------------------------------------*/
+const ModelCardDatabase* ConnectorProject::getModelCardDatabase() const {
+ return m_modelCards.get();
+} //ConnectorProject::getModelCardDatabase
diff --git a/SpeckleConnector/Connector/Environment/ConnectorProject.h b/SpeckleConnector/Connector/Environment/ConnectorProject.h
new file mode 100644
index 0000000..4aa2ff0
--- /dev/null
+++ b/SpeckleConnector/Connector/Environment/ConnectorProject.h
@@ -0,0 +1,53 @@
+#ifndef CONNECTOR_ENVIRONMENT_CONNECTOR_PROJECT
+#define CONNECTOR_ENVIRONMENT_CONNECTOR_PROJECT
+
+#include "Speckle/Environment/Project.h"
+
+namespace connector::database {
+ class ModelCardDatabase;
+}
+
+namespace connector::environment {
+
+ /*!
+ A BIM project contained Speckle connector data, e.g. a model card database
+ */
+ class ConnectorProject : public speckle::environment::Project {
+ public:
+
+ // MARK: - Types
+
+ ///Shared pointer
+ using Shared = std::shared_ptr;
+ ///Weak pointer
+ using Weak = std::weak_ptr;
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ */
+ ConnectorProject();
+
+ ConnectorProject(const ConnectorProject&) = delete;
+ /*!
+ Destructor
+ */
+ ~ConnectorProject();
+
+ // MARK: - Functions (const)
+
+ /*!
+ Get the model card database
+ @return The model card database
+ */
+ const connector::database::ModelCardDatabase* getModelCardDatabase() const;
+
+ private:
+ ///The model card database
+ std::shared_ptr m_modelCards;
+ };
+
+}
+
+#endif //CONNECTOR_ENVIRONMENT_CONNECTOR_PROJECT
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Account/GetAccounts.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Account/GetAccounts.cpp
index 0c042a8..07872f0 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 = CargoHold>, Vector>;
}
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Account/GetAccounts.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Account/GetAccounts.h
index 798f492..f079268 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Account/GetAccounts.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Account/GetAccounts.h
@@ -6,7 +6,7 @@
namespace connector::interfac::browser::bridge {
/*!
- JS Function class to retrieve the names of the methods supported by the bridge
+ JS Function class to retrieve the user's account(s)
*/
class GetAccounts : public speckle::interfac::browser::bridge::BridgeMethod {
public:
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.cpp
index 6c08025..741dc51 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.cpp
@@ -1,21 +1,16 @@
#include "Connector/Interface/Browser/Bridge/Base/AddModel.h"
#include "Connector/Connector.h"
+#include "Connector/Environment/ConnectorProject.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::environment;
using namespace connector::record;
using namespace connector::interfac::browser::bridge;
using namespace speckle::utility;
-namespace {
-
- using WrappedValue = active::serialise::CargoHold;
-
-}
-
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
@@ -30,6 +25,10 @@ AddModel::AddModel() : BridgeMethod{"AddModel", [&](const ModelCardEventWrapper&
card: The card to add
--------------------------------------------------------------------*/
void AddModel::run(const ModelCard& card) const {
- if (auto modelCardDBase = connector()->getModelCardDatabase(); modelCardDBase != nullptr)
+ auto project = connector()->getActiveProject().lock();
+ auto connectorProject = dynamic_cast(project.get());
+ if (!connectorProject)
+ return;
+ if (auto modelCardDBase = connectorProject->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
index b616315..9723578 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.h
@@ -8,7 +8,7 @@
namespace connector::interfac::browser::bridge {
- ///Argument parameter for a string
+ ///Argument parameter for a model card
using CardHold = active::serialise::CargoHold;
///Argument type for this method
using ModelCardEventWrapper = speckle::interfac::browser::bridge::JSArgType;
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h
index 56ac1b5..84b9848 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h
@@ -39,20 +39,20 @@ namespace connector::interfac::browser::bridge {
// 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
- */
+ 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)
- */
+ 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
- */
+ Set to the default package content
+ */
void setDefault() override;
};
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp
index f40155f..19f2cad 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.cpp
@@ -1,5 +1,4 @@
#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"
@@ -8,6 +7,20 @@
#include "Connector/Interface/Browser/Bridge/Base/GetSourceApplicationVersion.h"
#include "Connector/Interface/Browser/Bridge/Base/RemoveModel.h"
#include "Connector/Interface/Browser/Bridge/Base/UpdateModel.h"
+#include "Connector/Interface/Browser/Bridge/Base/HighlightModel.h"
+#include "Connector/Interface/Browser/Bridge/Base/HighlightObjects.h"
+#include "Connector/Interface/Browser/Bridge/Base/OpenUrl.h"
+#include "Speckle/Event/Type/ProjectEvent.h"
+
+#include "Speckle/Environment/Project.h"
+#include "Speckle/Record/Element/Element.h"
+#include "Connector/Connector.h"
+#include "Connector/ConnectorResource.h"
+#include "Speckle/Database/Identity/RecordID.h"
+#include "Speckle/Database/BIMElementDatabase.h"
+#include "Connector/Record/Model/SenderModelCard.h"
+#include "Connector/Record/Model/Filter/SendFilter.h"
+#include "Connector/Database/ModelCardDatabase.h"
using namespace connector::interfac::browser::bridge;
@@ -22,6 +35,28 @@ BaseBridge::BaseBridge() : BrowserBridge{"baseBinding"} {
addMethod();
addMethod();
addMethod();
+ addMethod();
+ addMethod();
+ addMethod();
addMethod();
addMethod();
} //BaseBridge::BaseBridge
+
+/*--------------------------------------------------------------------
+ Handle a project event
+
+ event: The project event
+
+ return: True if the event should be closed
+ --------------------------------------------------------------------*/
+bool BaseBridge::handle(const speckle::event::ProjectEvent& event) {
+ using enum speckle::event::ProjectEvent::Type;
+ switch (event.getType()) {
+ case open:
+ sendEvent("documentChanged");
+ break;
+ default:
+ break;
+ }
+ return false;
+} //BaseBridge::handle
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.h
index e7076a4..5e5e248 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/BaseBridge.h
@@ -2,13 +2,14 @@
#define CONNECTOR_INTERFACE_BRIDGE_BASE_BRIDGE
#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h"
+#include "Speckle/Event/Subscriber/ProjectSubscriber.h"
namespace connector::interfac::browser::bridge {
/*!
- A browser bridge to provide configuration settings
+ A browser bridge to manage document settings
*/
- class BaseBridge : public speckle::interfac::browser::bridge::BrowserBridge {
+ class BaseBridge : public speckle::interfac::browser::bridge::BrowserBridge, public speckle::event::ProjectSubscriber {
public:
// MARK: - Types
@@ -22,6 +23,14 @@ namespace connector::interfac::browser::bridge {
Default constructor
*/
BaseBridge();
+
+ protected:
+ /*!
+ Handle the project events
+ @param event The project event
+ @return True if the event should be closed
+ */
+ bool handle(const speckle::event::ProjectEvent& event) override;
};
}
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetConnectorVersion.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetConnectorVersion.cpp
index 5b8a14d..1e3e6e9 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetConnectorVersion.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetConnectorVersion.cpp
@@ -25,13 +25,13 @@ GetConnectorVersion::GetConnectorVersion() : BridgeMethod{"GetConnectorVersion",
/*--------------------------------------------------------------------
- Get the host application version
+ Get the connector software version
- return: The application version
+ return: The connector software version
--------------------------------------------------------------------*/
std::unique_ptr GetConnectorVersion::run() const {
//Implement other platforms as required
- String result{active::utility::String{connector::versionMajor} + "." + active::utility::String{connector::versionMinor} + "." +
- active::utility::String{connector::versionPatch}};
+ String result{String{connector::versionMajor} + "." + String{connector::versionMinor} + "." +
+ String{connector::versionPatch}};
return std::make_unique(result);
} //GetConnectorVersion::run
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetConnectorVersion.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetConnectorVersion.h
index 77a95be..5878765 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetConnectorVersion.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetConnectorVersion.h
@@ -8,7 +8,7 @@ namespace connector::interfac::browser::bridge {
class ConnectorConfig;
/*!
- JS Function class to retrieve the names of the methods supported by the bridge
+ JS Function class to get the connector software version
*/
class GetConnectorVersion : public speckle::interfac::browser::bridge::BridgeMethod {
public:
@@ -23,8 +23,8 @@ namespace connector::interfac::browser::bridge {
// MARK: - Functions (const)
/*!
- Get the host application version
- @return The application version
+ Get the connector software version
+ @return The connector software version
*/
std::unique_ptr run() const;
};
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp
index 3d69108..726b1bf 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp
@@ -2,12 +2,15 @@
#include "Active/Serialise/CargoHold.h"
#include "Connector/Connector.h"
+#include "Connector/Environment/ConnectorProject.h"
+#include "Connector/Database/ModelCardDatabase.h"
#include "Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h"
#include "Speckle/Environment/Project.h"
#include "Speckle/Utility/Guid.h"
using namespace active::container;
using namespace active::serialise;
+using namespace connector::environment;
using namespace connector::interfac::browser::bridge;
using namespace speckle::utility;
@@ -32,13 +35,17 @@ GetDocumentInfo::GetDocumentInfo() : BridgeMethod{"GetDocumentInfo", [&]() {
--------------------------------------------------------------------*/
std::unique_ptr GetDocumentInfo::run() const {
auto docInfo = std::make_unique();
- if (auto project = connector()->getActiveProject().lock(); project) {
- auto info = project->getInfo();
- docInfo->name = info.name;
- if (info.path)
- docInfo->location = *info.path;
- //TODO: No suitable project ID is currently available
+ auto project = connector()->getActiveProject().lock();
+ auto connectorProject = dynamic_cast(project.get());
+ if (!connectorProject)
+ return nullptr;
+ auto info = connectorProject->getInfo();
+ docInfo->name = info.name;
+ if (info.path)
+ docInfo->location = *info.path;
+ if (auto cardDatabase = connectorProject->getModelCardDatabase(); cardDatabase != nullptr)
+ docInfo->ID = cardDatabase->getStoreID();
+ else
docInfo->ID = Guid{true}.operator String();
- }
return std::make_unique(std::move(docInfo));
} //GetDocumentInfo::run
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp
index ed812b5..1011d4c 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp
@@ -1,16 +1,13 @@
#include "Connector/Interface/Browser/Bridge/Base/GetDocumentState.h"
-#include "Active/Serialise/CargoHold.h"
-#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
#include "Connector/Connector.h"
-#include "Connector/Record/Model/ModelCard.h"
+#include "Connector/Environment/ConnectorProject.h"
#include "Connector/Database/ModelCardDatabase.h"
using namespace active::container;
using namespace active::serialise;
+using namespace connector::environment;
using namespace connector::interfac::browser::bridge;
-using namespace connector::database;
-using namespace connector::record;
using namespace speckle::utility;
/*--------------------------------------------------------------------
@@ -22,12 +19,16 @@ GetDocumentState::GetDocumentState() : BridgeMethod{"GetDocumentState", [&]() {
/*--------------------------------------------------------------------
- Get the document info
+ Get the document model cards
- return: The document info
+ return: The document model cards
--------------------------------------------------------------------*/
std::unique_ptr GetDocumentState::run() const {
- if (auto modelCardDBase = connector()->getModelCardDatabase(); modelCardDBase != nullptr) {
+ auto project = connector()->getActiveProject().lock();
+ auto connectorProject = dynamic_cast(project.get());
+ if (!connectorProject)
+ return nullptr;
+ if (auto modelCardDBase = connectorProject->getModelCardDatabase(); modelCardDBase != nullptr) {
return modelCardDBase->wrapper();
}
return nullptr;
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.h
index 472b1db..c73ca07 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.h
@@ -6,7 +6,7 @@
namespace connector::interfac::browser::bridge {
/*!
- JS Function class to retrieve the information about the active document
+ JS Function class to retrieve model cards stored in the current document
*/
class GetDocumentState : public speckle::interfac::browser::bridge::BridgeMethod {
public:
@@ -21,8 +21,8 @@ namespace connector::interfac::browser::bridge {
// MARK: - Functions (const)
/*!
- Get the document info
- @return The document info
+ Get the document model cards
+ @return The document model cards
*/
std::unique_ptr run() const;
};
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightModel.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightModel.cpp
new file mode 100644
index 0000000..0e1021b
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightModel.cpp
@@ -0,0 +1,55 @@
+#include "Connector/Interface/Browser/Bridge/Base/HighlightModel.h"
+#include "Connector/Connector.h"
+#include "Connector/ConnectorResource.h"
+#include "Connector/Environment/ConnectorProject.h"
+#include "Connector/Database/ModelCardDatabase.h"
+#include "Connector/Interface/Browser/Bridge/Send/Arg/SendError.h"
+#include "Connector/Record/Model/SenderModelCard.h"
+#include "Connector/Record/Model/Filter/SendFilter.h"
+#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h"
+#include "Speckle/Record/Element/Element.h"
+#include "Speckle/Database/BIMElementDatabase.h"
+#include "Speckle/Environment/Project.h"
+
+using namespace speckle::record::element;
+using namespace connector::environment;
+using namespace connector::interfac::browser::bridge;
+using namespace connector::record;
+using namespace speckle::utility;
+
+/*--------------------------------------------------------------------
+ Default constructor
+ --------------------------------------------------------------------*/
+HighlightModel::HighlightModel() : BridgeMethod{"HighlightModel", [&](const HighlightModelArgs& args) {
+ run(args);
+}} {}
+
+
+/*--------------------------------------------------------------------
+ Highlight elements linked to the model card selection
+
+ modelCardID: The ID of the target model card
+ --------------------------------------------------------------------*/
+void HighlightModel::run(const String& modelCardID) const {
+ auto project = connector()->getActiveProject().lock();
+ auto connectorProject = dynamic_cast(project.get());
+ if (!connectorProject)
+ return;
+ //Find the specified model card
+ auto modelCardDatabase = connectorProject->getModelCardDatabase();
+ auto modelCard = modelCardDatabase->getCard(modelCardID);
+ if (!modelCard) {
+ getBridge()->sendEvent("setModelError",
+ std::make_unique(connector()->getLocalString(errorString, modelCardNotFoundID), modelCardID));
+ return;
+ }
+ if (auto senderCard = dynamic_cast(modelCard.get())) {
+ auto modelCardSelection = senderCard->getFilter().getElementIDs();
+ auto project = connector()->getActiveProject().lock();
+ if (!project)
+ return; // TODO: is this OK? should this throw?
+ auto elementDatabase = project->getElementDatabase();
+ elementDatabase->clearSelection();
+ elementDatabase->setSelection(modelCardSelection);
+ }
+} //HighlightModel::run
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightModel.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightModel.h
new file mode 100644
index 0000000..8d3e2a9
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightModel.h
@@ -0,0 +1,39 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_HIGHLIGHT_MODEL
+#define CONNECTOR_INTERFACE_BRIDGE_HIGHLIGHT_MODEL
+
+#include "Active/Serialise/CargoHold.h"
+#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
+#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h"
+
+namespace connector::interfac::browser::bridge {
+
+ ///Argument parameter for a string
+ using StringHold = active::serialise::CargoHold, speckle::utility::String>;
+ ///Argument type for this method
+ using HighlightModelArgs = speckle::interfac::browser::bridge::JSArgType;
+
+ /*!
+ JS Function class to highlight elements from the selected model card in the open document
+ */
+ class HighlightModel : public speckle::interfac::browser::bridge::BridgeMethod {
+ public:
+
+ // MARK: - Constructors
+
+ /*!
+ Constructor
+ */
+ HighlightModel();
+
+ // MARK: - Functions (const)
+
+ /*!
+ Highlight elements linked to the model card selection
+ @param modelCardID The ID of the target model card
+ */
+ void run(const speckle::utility::String& modelCardID) const;
+ };
+
+}
+
+#endif //CONNECTOR_INTERFACE_HIGHLIGHT_MODEL
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightObjects.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightObjects.cpp
new file mode 100644
index 0000000..5e19180
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightObjects.cpp
@@ -0,0 +1,40 @@
+#include "Connector/Interface/Browser/Bridge/Base/HighlightObjects.h"
+
+#include "Connector/Connector.h"
+#include "Connector/Environment/ConnectorProject.h"
+#include "Speckle/Database/BIMElementDatabase.h"
+#include "Speckle/Environment/Project.h"
+
+using namespace connector::environment;
+using namespace connector::interfac::browser::bridge;
+using namespace speckle::database;
+using namespace speckle::utility;
+
+/*--------------------------------------------------------------------
+ Default constructor
+ --------------------------------------------------------------------*/
+HighlightObjects::HighlightObjects() : BridgeMethod{"HighlightObjects", [&](const HighlightObjectArgs& args) {
+ run(args);
+}} {}
+
+
+/*--------------------------------------------------------------------
+ Highlight specified objects
+
+ objectIDs: List of object IDs to be highlighted
+ --------------------------------------------------------------------*/
+void HighlightObjects::run(const StringList& objectIDs) const {
+ BIMLinkList objectSelection;
+ for (const auto& text : objectIDs)
+ if (Guid guid{text}; !guid.empty())
+ objectSelection.emplace_back(guid);
+ if (objectSelection.empty())
+ return;
+ auto project = connector()->getActiveProject().lock();
+ auto connectorProject = dynamic_cast(project.get());
+ if (!connectorProject)
+ return;
+ auto elementDatabase = project->getElementDatabase();
+ elementDatabase->clearSelection();
+ elementDatabase->setSelection(objectSelection);
+} //HighlightObjects::run
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightObjects.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightObjects.h
new file mode 100644
index 0000000..b99df2c
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightObjects.h
@@ -0,0 +1,42 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_HIGHLIGHT_OBJECTS
+#define CONNECTOR_INTERFACE_BRIDGE_HIGHLIGHT_OBJECTS
+
+#include "Active/Serialise/CargoHold.h"
+#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
+#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
+#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h"
+
+namespace connector::interfac::browser::bridge {
+
+ ///List of strings
+ using StringList = std::vector;
+ ///Argument parameter for a string
+ using StringListHold = active::serialise::CargoHold, StringList>;
+ ///Argument type for this method
+ using HighlightObjectArgs = speckle::interfac::browser::bridge::JSArgType;
+
+ /*!
+ JS Function class to highlight objects using passed application IDs
+ */
+ class HighlightObjects : public speckle::interfac::browser::bridge::BridgeMethod {
+ public:
+
+ // MARK: - Constructors
+
+ /*!
+ Constructor
+ */
+ HighlightObjects();
+
+ // MARK: - Functions (const)
+
+ /*!
+ Highlight specified objects
+ @param objectIDs List of object IDs to be highlighted
+ */
+ void run(const StringList& objectIDs) const;
+ };
+
+}
+
+#endif //CONNECTOR_INTERFACE_BRIDGE_HIGHLIGHT_OBJECTS
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/OpenUrl.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/OpenUrl.cpp
new file mode 100644
index 0000000..985655a
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/OpenUrl.cpp
@@ -0,0 +1,24 @@
+#include "Connector/Interface/Browser/Bridge/Base/OpenUrl.h"
+
+#include "Speckle/Environment/Platform.h"
+
+using namespace connector::interfac::browser::bridge;
+using namespace speckle::environment;
+using namespace speckle::utility;
+
+/*--------------------------------------------------------------------
+ Default constructor
+ --------------------------------------------------------------------*/
+OpenUrl::OpenUrl() : BridgeMethod{"OpenUrl", [&](const SendArgs& args) {
+ run(args);
+}} {}
+
+
+/*--------------------------------------------------------------------
+ Opens an url
+
+ url: The URL to open
+ --------------------------------------------------------------------*/
+void OpenUrl::run(const String& url) const {
+ platform()->openURL(url);
+} //OpenUrl::run
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/OpenUrl.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/OpenUrl.h
new file mode 100644
index 0000000..aa8fa35
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/OpenUrl.h
@@ -0,0 +1,41 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_OPEN_URL
+#define CONNECTOR_INTERFACE_BRIDGE_OPEN_URL
+
+#include "Active/Serialise/CargoHold.h"
+#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
+#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h"
+
+namespace connector::interfac::browser::bridge {
+
+ class ConnectorConfig;
+
+ ///Argument parameter for a string
+ using StringHold = active::serialise::CargoHold, speckle::utility::String>;
+ ///Argument type for this method
+ using SendArgs = speckle::interfac::browser::bridge::JSArgType;
+
+ /*!
+ JS Function class to highlight elements from the selected model card in the open document
+ */
+ class OpenUrl : public speckle::interfac::browser::bridge::BridgeMethod {
+ public:
+
+ // MARK: - Constructors
+
+ /*!
+ Constructor
+ */
+ OpenUrl();
+
+ // MARK: - Functions (const)
+
+ /*!
+ Opens an url
+ @param url The URL to open
+ */
+ void run(const speckle::utility::String& url) const;
+ };
+
+}
+
+#endif //CONNECTOR_INTERFACE_BRIDGE_OPEN_URL
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/RemoveModel.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/RemoveModel.cpp
index 722d2fa..91a3ad1 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/RemoveModel.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/RemoveModel.cpp
@@ -1,22 +1,16 @@
#include "Connector/Interface/Browser/Bridge/Base/RemoveModel.h"
#include "Connector/Connector.h"
+#include "Connector/Environment/ConnectorProject.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::environment;
using namespace connector::record;
using namespace connector::interfac::browser::bridge;
using namespace speckle::utility;
-namespace {
-
- using WrappedValue = active::serialise::CargoHold;
-
-}
-
/*--------------------------------------------------------------------
Default constructor
--------------------------------------------------------------------*/
@@ -31,6 +25,10 @@ RemoveModel::RemoveModel() : BridgeMethod{"RemoveModel", [&](const ModelCardEven
card: The card to add
--------------------------------------------------------------------*/
void RemoveModel::run(const ModelCard& card) const {
- if (auto modelCardDBase = connector()->getModelCardDatabase(); modelCardDBase != nullptr)
+ auto project = connector()->getActiveProject().lock();
+ auto connectorProject = dynamic_cast(project.get());
+ if (!connectorProject)
+ return;
+ if (auto modelCardDBase = connectorProject->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
index d6a900d..f5cde48 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/RemoveModel.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/RemoveModel.h
@@ -8,13 +8,13 @@
namespace connector::interfac::browser::bridge {
- ///Argument parameter for a string
+ ///Argument parameter for a model card
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
+ JS Function class to remove a model card from the document storage
*/
class RemoveModel : public speckle::interfac::browser::bridge::BridgeMethod {
public:
@@ -29,8 +29,8 @@ namespace connector::interfac::browser::bridge {
// MARK: - Functions (const)
/*!
- Add a model card to document storage
- @param card The card to add
+ Remove a model card from document storage
+ @param card The card to remove
*/
void run(const connector::record::ModelCard& card) const;
};
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.cpp
index cd845dc..6472d95 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.cpp
@@ -2,11 +2,12 @@
#include "Connector/Connector.h"
#include "Connector/Database/ModelCardDatabase.h"
+#include "Connector/Environment/ConnectorProject.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::environment;
using namespace connector::record;
using namespace connector::interfac::browser::bridge;
using namespace speckle::utility;
@@ -26,11 +27,15 @@ UpdateModel::UpdateModel() : BridgeMethod{"UpdateModel", [&](const ModelCardEven
/*--------------------------------------------------------------------
- Add a model card to document storage
+ Update a model card in document storage
- card: The card to add
+ card: The card to update
--------------------------------------------------------------------*/
void UpdateModel::run(const ModelCard& card) const {
- if (auto modelCardDBase = connector()->getModelCardDatabase(); modelCardDBase != nullptr)
+ auto project = connector()->getActiveProject().lock();
+ auto connectorProject = dynamic_cast(project.get());
+ if (!connectorProject)
+ return;
+ if (auto modelCardDBase = connectorProject->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
index 024151a..9829a21 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.h
@@ -8,13 +8,13 @@
namespace connector::interfac::browser::bridge {
- ///Argument parameter for a string
+ ///Argument parameter for a model card
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
+ JS Function class to update a model card in document storage
*/
class UpdateModel : public speckle::interfac::browser::bridge::BridgeMethod {
public:
@@ -29,8 +29,8 @@ namespace connector::interfac::browser::bridge {
// MARK: - Functions (const)
/*!
- Add a model card to document storage
- @param card The card to add
+ Update a model card in document storage
+ @param card The card to update
*/
void run(const connector::record::ModelCard& card) const;
};
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/GetConfig.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/GetConfig.h
index ff4eea7..bd9acac 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/GetConfig.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/GetConfig.h
@@ -6,7 +6,7 @@
namespace connector::interfac::browser::bridge {
/*!
- JS Function class to retrieve the names of the methods supported by the bridge
+ JS Function class to retrieve the current display configuration settings
*/
class GetConfig : public speckle::interfac::browser::bridge::BridgeMethod {
public:
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/UpdateConfig.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/UpdateConfig.h
index 3cd68fd..1076900 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/UpdateConfig.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/UpdateConfig.h
@@ -9,11 +9,11 @@ namespace connector::interfac::browser::bridge {
class ConnectorConfig;
- ///Argument for a JS call to update the configuration
+ ///Argument for a JS call to update the display configuration settings
using UpdateArgs = speckle::interfac::browser::bridge::JSArgType;
/*!
- JS Function class to retrieve the names of the methods supported by the bridge
+ JS Function class to update the display configuration settings
*/
class UpdateConfig : public speckle::interfac::browser::bridge::BridgeMethod {
public:
@@ -22,7 +22,6 @@ namespace connector::interfac::browser::bridge {
/*!
Constructor
- @param bridge The parent bridge object (provides access to bridge methods)
*/
UpdateConfig();
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp
new file mode 100644
index 0000000..08dbb5c
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.cpp
@@ -0,0 +1,89 @@
+#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
+#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
+#include "Connector/Connector.h"
+#include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h"
+#include "Speckle/Database/BIMElementDatabase.h"
+#include "Speckle/Environment/Project.h"
+#include "Speckle/Record/Element/Element.h"
+
+#include
+
+using namespace active::serialise;
+using namespace connector::interfac::browser::bridge;
+using namespace speckle::record::element;
+
+namespace {
+
+ ///Serialisation fields
+ enum FieldIndex {
+ selectedObjectIdsID,
+ summaryID,
+ };
+
+ ///Serialisation field IDs
+ static std::array fieldID = {
+ Identity{"selectedObjectIds"},
+ Identity{"summary"},
+ };
+
+}
+
+SelectionInfo::SelectionInfo() {
+ auto project = connector()->getActiveProject().lock();
+ if (!project) {
+ // TODO: is this OK?
+ return;
+ }
+
+ auto elementDatabase = project->getElementDatabase();
+ auto selected = elementDatabase->getSelection();
+
+ active::utility::String summary(selected.size());
+ summary += " objects selected.";
+ m_summary = summary;
+
+ for (const auto& link : selected) {
+ m_selectedElementIds.push_back(link);
+ }
+}
+
+
+/*--------------------------------------------------------------------
+ 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 SelectionInfo::fillInventory(Inventory& inventory) const {
+ using enum Entry::Type;
+ inventory.merge(Inventory{
+ {
+ { fieldID[selectedObjectIdsID], selectedObjectIdsID, element },
+ { fieldID[summaryID], summaryID, element },
+ },
+ }.withType(&typeid(SelectionInfo)));
+ return true;
+} //SelectionInfo::fillInventory
+
+
+/*--------------------------------------------------------------------
+ Get the specified cargo
+
+ item: The inventory item to retrieve
+
+ return: The requested cargo (nullptr on failure)
+ --------------------------------------------------------------------*/
+Cargo::Unique SelectionInfo::getCargo(const Inventory::Item& item) const {
+ if (item.ownerType != &typeid(SelectionInfo))
+ return nullptr;
+ using namespace active::serialise;
+ switch (item.index) {
+ case selectedObjectIdsID:
+ return std::make_unique>>(m_selectedElementIds, false, fieldID[selectedObjectIdsID].name);
+ case summaryID:
+ return std::make_unique>(m_summary);
+ default:
+ return nullptr; //Requested an unknown index
+ }
+} //SelectionInfo::getCargo
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h
new file mode 100644
index 0000000..18bace9
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h
@@ -0,0 +1,45 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_SELECTION_INFO
+#define CONNECTOR_INTERFACE_BRIDGE_SELECTION_INFO
+
+#include "Active/Serialise/Package/Package.h"
+
+namespace connector::interfac::browser::bridge {
+
+ /*!
+ Configuration settings class
+ */
+ class SelectionInfo : public active::serialise::Package {
+ public:
+
+ // MARK: - Types
+
+ using base = active::serialise::Package;
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ */
+ SelectionInfo();
+
+ active::utility::String m_summary = "No objects selected";
+ std::vector m_selectedElementIds;
+
+ // 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;
+ };
+}
+
+#endif //CONNECTOR_INTERFACE_BRIDGE_SELECTION_INFO
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp
new file mode 100644
index 0000000..37f918a
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.cpp
@@ -0,0 +1,23 @@
+#include "Active/Serialise/CargoHold.h"
+#include "Connector/Interface/Browser/Bridge/Selection/GetSelection.h"
+#include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h"
+
+using namespace active::serialise;
+using namespace connector::interfac::browser::bridge;
+
+/*--------------------------------------------------------------------
+ Default constructor
+ --------------------------------------------------------------------*/
+GetSelection::GetSelection() : BridgeMethod{"GetSelection", [&]() {
+ return run();
+}} {}
+
+
+/*--------------------------------------------------------------------
+ Get the current selection info
+ based on the ArchiCAD mdoel selection
+ --------------------------------------------------------------------*/
+std::unique_ptr GetSelection::run() const {
+ auto selectionInfo = std::make_unique();
+ return std::make_unique>(std::move(selectionInfo));
+} //GetSelection::run
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.h
new file mode 100644
index 0000000..7dd06c2
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/GetSelection.h
@@ -0,0 +1,29 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_GETSELECTION
+#define CONNECTOR_INTERFACE_BRIDGE_GETSELECTION
+
+#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h"
+
+namespace connector::interfac::browser::bridge {
+
+ class GetSelection : public speckle::interfac::browser::bridge::BridgeMethod {
+ public:
+
+ // MARK: - Constructors
+
+ /*!
+ Constructor
+ */
+ GetSelection();
+
+ // MARK: - Functions (const)
+
+ /*!
+ Get the current selection info
+ based on the ArchiCAD mdoel selection
+ */
+ std::unique_ptr run() const;
+ };
+
+}
+
+#endif //CONNECTOR_INTERFACE_BRIDGE_GETSELECTION
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp
new file mode 100644
index 0000000..cb05aed
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp
@@ -0,0 +1,30 @@
+#include "Active/Serialise/CargoHold.h"
+#include "Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h"
+#include "Connector/Interface/Browser/Bridge/Selection/GetSelection.h"
+#include "Connector/Interface/Browser/Bridge/Selection/Arg/SelectionInfo.h"
+
+using namespace active::serialise;
+using namespace connector::interfac::browser::bridge;
+
+/*--------------------------------------------------------------------
+ Default constructor
+ --------------------------------------------------------------------*/
+SelectionBridge::SelectionBridge() : BrowserBridge{"selectionBinding"} {
+ //Add bridge methods
+ addMethod();
+} //SelectionBridge::SelectionBridge
+
+
+/*--------------------------------------------------------------------
+ Handle a selection change
+
+ event: The selection event
+
+ return: True if the event should be closed
+ --------------------------------------------------------------------*/
+bool SelectionBridge::handle(const speckle::event::SelectionEvent& event) {
+ auto selectionInfo = std::make_unique();
+ auto wrapped = std::make_unique>(std::move(selectionInfo));
+ sendEvent("setSelection", std::move(wrapped));
+ return true;
+} //SelectionBridge::handle
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h
new file mode 100644
index 0000000..40b6c1b
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h
@@ -0,0 +1,39 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_SELECTION_BRIDGE
+#define CONNECTOR_INTERFACE_BRIDGE_SELECTION_BRIDGE
+
+#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h"
+#include "Speckle/Event/Subscriber/SelectionSubscriber.h"
+#include "Speckle/Event/Type/SelectionEvent.h"
+
+namespace connector::interfac::browser::bridge {
+
+ /*!
+ A browser bridge to manage element selection information passed between the JS UI and the BIM application
+ */
+ class SelectionBridge : public speckle::interfac::browser::bridge::BrowserBridge, public speckle::event::SelectionSubscriber {
+ public:
+
+ // MARK: - Types
+
+ using base = speckle::interfac::browser::bridge::BrowserBridge;
+
+ // MARK: - Constructors
+
+ using base::base;
+ /*!
+ Default constructor
+ */
+ SelectionBridge();
+
+ protected:
+ /*!
+ Handle a selection change
+ @param event The selection event
+ @return True if the event should be closed
+ */
+ bool handle(const speckle::event::SelectionEvent& event) override;
+ };
+
+}
+
+#endif //CONNECTOR_INTERFACE_BRIDGE_SELECTION_BRIDGE
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp
new file mode 100644
index 0000000..7566b21
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.cpp
@@ -0,0 +1,121 @@
+#include "Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.h"
+
+#include "Active/Serialise/CargoHold.h"
+#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
+
+#include
+
+using namespace active::serialise;
+using namespace connector::interfac::browser::bridge;
+using namespace speckle::utility;
+
+namespace {
+
+ ///Serialisation fields
+ enum FieldIndex {
+ statusID,
+ srcID,
+ srcTypeID,
+ resID,
+ resTypeID,
+ errorID,
+ };
+
+ ///Serialisation field IDs
+ static std::array fieldID = {
+ Identity{"status"},
+ Identity{"sourceId"},
+ Identity{"sourceType"},
+ Identity{"resultId"},
+ Identity{"resultType"},
+ Identity{"error"},
+ };
+
+ ///Conversion status enumerator names
+ std::array statusName{
+ "success",
+ "warning",
+ "info",
+ "error",
+ };
+
+}
+
+/*--------------------------------------------------------------------
+ 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 ConversionResult::fillInventory(active::serialise::Inventory& inventory) const {
+ using enum Entry::Type;
+ inventory.merge(Inventory{
+ {
+ { fieldID[statusID], statusID, element },
+ { fieldID[srcID], srcID, element, !sourceID.empty() },
+ { fieldID[srcTypeID], srcTypeID, element, !sourceType.empty() },
+ { fieldID[resID], resID, element, !resultID.empty() },
+ { fieldID[resTypeID], resTypeID, element, !resultType.empty() },
+ { fieldID[errorID], errorID, element, error.operator bool() },
+ },
+ }.withType(&typeid(ConversionResult)));
+ return true;
+} //ConversionResult::fillInventory
+
+
+/*--------------------------------------------------------------------
+ Get the specified cargo
+
+ item: The inventory item to retrieve
+
+ return: The requested cargo (nullptr on failure)
+ --------------------------------------------------------------------*/
+Cargo::Unique ConversionResult::getCargo(const active::serialise::Inventory::Item& item) const {
+ if (item.ownerType != &typeid(ConversionResult))
+ return nullptr;
+ using namespace active::serialise;
+ switch (item.index) {
+ case statusID:
+ return Cargo::Unique{new CargoHold, uint16_t>(static_cast(status))};
+ case srcID:
+ return std::make_unique>(sourceID);
+ case srcTypeID:
+ return std::make_unique>(sourceType);
+ case resID:
+ return std::make_unique>(resultID);
+ case resTypeID:
+ return std::make_unique>(resultType);
+ case errorID:
+ return std::make_unique(*error);
+ default:
+ return nullptr; //Requested an unknown index
+ }
+} //ConversionResult::getCargo
+
+
+/*--------------------------------------------------------------------
+ Get a conversion status enumerator from text
+
+ text; The incoming text
+
+ return: The equivalent conversion status (nullopt on failure)
+ --------------------------------------------------------------------*/
+std::optional connector::interfac::browser::bridge::toConversionStatus(const String& text) {
+ for (auto i = 0; i < statusName.size(); ++i)
+ if (text == statusName[i])
+ return static_cast(i + 1);
+ return std::nullopt;
+} //active::geometry::toAnchor2D
+
+
+/*--------------------------------------------------------------------
+ Get the text for a conversion status value
+
+ status: The incoming status
+
+ return: The conversion status as text
+ --------------------------------------------------------------------*/
+String connector::interfac::browser::bridge::fromConversionStatus(ConversionResult::Status status) {
+ return statusName.at(static_cast(status) - 1);
+} //active::geometry::fromAnchor2D
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.h
new file mode 100644
index 0000000..5da3f33
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.h
@@ -0,0 +1,117 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_CONVERSION_RESULT
+#define CONNECTOR_INTERFACE_BRIDGE_CONVERSION_RESULT
+
+#include "Active/Serialise/Package/Package.h"
+#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
+#include "Connector/Interface/Browser/Bridge/Send/Arg/SendError.h"
+#include "Speckle/Utility/String.h"
+
+namespace connector::interfac::browser::bridge {
+
+ /*!
+ The result of a conversion process (BIM records to/from Speckle)
+ */
+ class ConversionResult : public active::serialise::Package {
+ public:
+ enum class Status : uint16_t {
+ success = 1, /// toConversionStatus(const speckle::utility::String& text);
+ /*!
+ Get the text for a conversion status value
+ @param status The incoming status
+ @return The conversion status as text
+ */
+ speckle::utility::String fromConversionStatus(ConversionResult::Status status);
+}
+
+namespace active::serialise {
+
+ /*!
+ Import the object from the specified string (specialisation for bool)
+ @param source The string to read
+ @return True if the data was successfully read
+ */
+ template<> inline
+ bool ValueWrap::read(const utility::String& source) {
+ auto converted = connector::interfac::browser::bridge::toConversionStatus(source);
+ if (!converted)
+ return false;
+ base::get() = *converted;
+ return true;
+ } //ValueWrap::read
+
+
+ /*!
+ Import the object from the specified string (specialisation for bool)
+ @param source The string to read
+ @return True if the data was successfully read
+ */
+ template<> inline
+ bool ValueWrap>::read(const utility::String& source) {
+ auto converted = connector::interfac::browser::bridge::toConversionStatus(source);
+ base::get() = converted;
+ return converted.operator bool();
+ } //ValueWrap::read
+
+
+ /*!
+ Export the object to the specified string (specialisation for bool)
+ @param dest The string to write the data to
+ @return True if the data was successfully written
+ */
+ template<> inline
+ bool ValueWrap::write(utility::String& dest) const {
+ dest = connector::interfac::browser::bridge::fromConversionStatus(get());
+ return true;
+ } //ValueWrap::write
+}
+
+#endif //CONNECTOR_INTERFACE_BRIDGE_CONVERSION_RESULT
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendConversionResult.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendConversionResult.h
new file mode 100644
index 0000000..c1168c5
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendConversionResult.h
@@ -0,0 +1,49 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_SEND_CONVERSION_RESULT
+#define CONNECTOR_INTERFACE_BRIDGE_SEND_CONVERSION_RESULT
+
+#include "Connector/Interface/Browser/Bridge/Send/Arg/ConversionResult.h"
+#include "Speckle/Serialise/Collection/ConversionReporter.h"
+
+namespace connector::interfac::browser::bridge {
+
+ /*!
+ A result from converting a record to Speckle
+ */
+ class SendConversionResult : public ConversionResult {
+ public:
+
+ // MARK: - Constructors
+
+ /*!
+ Constructor
+ @param stat The send/conversion status of the target record
+ @param srcID The record application ID
+ @param srcType The record application type name
+ @param err An optional error report
+ */
+ SendConversionResult(Status stat, speckle::utility::String srcID, speckle::utility::String srcType, SendError::Option err = std::nullopt) {
+ status = stat;
+ sourceID = srcID;
+ sourceType = srcType;
+ error = err;
+ }
+ /*!
+ Constructor
+ @param stat The send/conversion status of the target record
+ @param srcID The record application ID
+ @param srcType The record application type name
+ @param err An optional error report
+ */
+ SendConversionResult(const speckle::database::BIMRecordID& srcID, const speckle::serialise::ConversionReporter::Data& data) {
+ status = data.status == speckle::serialise::ConversionReporter::Data::Status::success ?
+ ConversionResult::Status::success : ConversionResult::Status::error;
+ sourceID = srcID.operator speckle::utility::String();
+ sourceType = data.typeName;
+ if (!data.message.empty())
+ error = SendError{data.message};
+ }
+ };
+
+}
+
+#endif //CONNECTOR_INTERFACE_BRIDGE_SEND_CONVERSION_RESULT
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp
new file mode 100644
index 0000000..6557140
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.cpp
@@ -0,0 +1,70 @@
+#include "Connector/Interface/Browser/Bridge/Send/Arg/SendError.h"
+
+#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
+
+#include
+
+using namespace active::serialise;
+using namespace connector::interfac::browser::bridge;
+using namespace speckle::utility;
+
+namespace {
+
+ ///Serialisation fields
+ enum FieldIndex {
+ messageID,
+ cardID,
+ stackID,
+ };
+
+ ///Serialisation field IDs
+ static std::array fieldID = {
+ Identity{"message"},
+ Identity{"modelCardId"},
+ Identity{"stackTrace"},
+ };
+
+}
+
+/*--------------------------------------------------------------------
+ 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 SendError::fillInventory(active::serialise::Inventory& inventory) const {
+ using enum Entry::Type;
+ inventory.merge(Inventory{
+ {
+ { fieldID[messageID], messageID, element },
+ { fieldID[cardID], cardID, element, !modelCardID.empty() },
+ { fieldID[stackID], stackID, element, modelCardID.empty() }, //Field not included when a model card is sent
+ },
+ }.withType(&typeid(SendError)));
+ return true;
+} //SendError::fillInventory
+
+
+/*--------------------------------------------------------------------
+ Get the specified cargo
+
+ item: The inventory item to retrieve
+
+ return: The requested cargo (nullptr on failure)
+ --------------------------------------------------------------------*/
+Cargo::Unique SendError::getCargo(const active::serialise::Inventory::Item& item) const {
+ if (item.ownerType != &typeid(SendError))
+ return nullptr;
+ using namespace active::serialise;
+ switch (item.index) {
+ case messageID:
+ return std::make_unique>(message);
+ case cardID:
+ return std::make_unique>(modelCardID);
+ case stackID:
+ return std::make_unique>(stackTrace);
+ default:
+ return nullptr; //Requested an unknown index
+ }
+} //SendError::getCargo
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.h
new file mode 100644
index 0000000..bbc5b2a
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendError.h
@@ -0,0 +1,56 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_SEND_ERROR
+#define CONNECTOR_INTERFACE_BRIDGE_SEND_ERROR
+
+#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
+#include "Speckle/Utility/String.h"
+
+namespace connector::interfac::browser::bridge {
+
+ /*!
+ A send error to return to the JS in the event of an error
+ */
+ class SendError final : public active::serialise::Package {
+ public:
+
+ // MARK: Types
+
+ ///Optional
+ using Option = std::optional;
+
+ // MARK: - Constructors
+
+ /*!
+ Constructor
+ @param errMess The error message
+ @param card The ID of the model card associated with the wrror
+ */
+ SendError(const speckle::utility::String& errMess, const speckle::utility::String& card = {}) : message{errMess}, modelCardID{card} {}
+
+ // MARK: - Public variables
+
+ ///The error message
+ speckle::utility::String message;
+ ///The ID of the model card associated with the data
+ speckle::utility::String modelCardID;
+ ///The error stack trace
+ speckle::utility::String stackTrace;
+
+ // 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;
+ };
+
+}
+
+#endif //CONNECTOR_INTERFACE_BRIDGE_SEND_ERROR
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp
new file mode 100644
index 0000000..ef14dc0
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.cpp
@@ -0,0 +1,87 @@
+#include "Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h"
+
+#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
+#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
+#include "Connector/Record/Collection/ProjectCollection.h"
+
+#include
+
+using namespace active::serialise;
+using namespace connector::interfac::browser::bridge;
+using namespace connector::record;
+using namespace speckle::serialise;
+using namespace speckle::utility;
+
+namespace {
+
+ ///Serialisation fields
+ enum FieldIndex {
+ idID,
+ rootObjID,
+ };
+
+ ///Serialisation field IDs
+ static std::array fieldID = {
+ Identity{"id"},
+ Identity{"rootObject"},
+ };
+
+}
+
+/*--------------------------------------------------------------------
+ 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 SendObject::fillInventory(active::serialise::Inventory& inventory) const {
+ using enum Entry::Type;
+ inventory.merge(Inventory{
+ {
+ { fieldID[idID], idID, element },
+ { fieldID[rootObjID], rootObjID, element },
+ },
+ }.withType(&typeid(SendObject)));
+ return true;
+} //SendObject::fillInventory
+
+
+/*--------------------------------------------------------------------
+ Get the specified cargo
+
+ item: The inventory item to retrieve
+
+ return: The requested cargo (nullptr on failure)
+ --------------------------------------------------------------------*/
+Cargo::Unique SendObject::getCargo(const active::serialise::Inventory::Item& item) const {
+ if (item.ownerType != &typeid(SendObject))
+ return nullptr;
+ using namespace active::serialise;
+ switch (item.index) {
+ case idID:
+ return std::make_unique(id);
+ case rootObjID:
+ if (m_object)
+ return std::make_unique(*m_object);
+ return std::make_unique();
+ default:
+ return nullptr; //Requested an unknown index
+ }
+} //SendObject::getCargo
+
+
+/*--------------------------------------------------------------------
+ Get the conversion results from the send object serialisation
+
+ return: The serialisation conversion results
+ --------------------------------------------------------------------*/
+std::vector SendObject::getConversionResults() const {
+ std::vector convertResults;
+ auto collection = dynamic_cast(m_object.get());
+ if (collection == nullptr)
+ return convertResults;
+ for (const auto& item : collection->getLog())
+ convertResults.emplace_back(SendConversionResult{item.first, item.second});
+ return convertResults;
+} //SendObject::getConversionResults
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h
new file mode 100644
index 0000000..cc385cc
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h
@@ -0,0 +1,70 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_SEND_OBJECT
+#define CONNECTOR_INTERFACE_BRIDGE_SEND_OBJECT
+
+#include "Active/Serialise/CargoHold.h"
+#include "Connector/Interface/Browser/Bridge/Config/Arg/ConnectorConfig.h"
+#include "Connector/Interface/Browser/Bridge/Send/Arg/SendConversionResult.h"
+#include "Speckle/Database/Content/Record.h"
+#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h"
+
+namespace connector::interfac::browser::bridge {
+
+ /*!
+ Class defining the primary content of a send
+ */
+ class SendObject final : public active::serialise::Package {
+ public:
+
+ using base = std::reference_wrapper;
+
+ // MARK: - Constructors
+
+ /*!
+ Default constructor
+ @param object The object to send
+ */
+ SendObject(std::unique_ptr object) : m_object{std::move(object)} { id = m_object->getID(); }
+
+ // MARK: - Public variables
+
+ ///The root object id which should be used for creating the version
+ speckle::utility::String id;
+
+ // 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;
+ /*!
+ Use a manager in (de)serialisation processes
+ @param management The management to use
+ */
+ void useManagement(active::serialise::Management* management) const override { m_object->useManagement(management); }
+ /*!
+ Get the cargo management
+ @return The active management
+ */
+ active::serialise::Management* management() const override { return m_object->management(); }
+ /*!
+ Get the conversion results from the send object serialisation
+ @return The serialisation conversion results
+ */
+ std::vector getConversionResults() const;
+
+ private:
+ ///The object to send
+ std::unique_ptr m_object;
+ };
+
+}
+
+#endif //CONNECTOR_INTERFACE_BRIDGE_SEND_OBJECT
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp
new file mode 100644
index 0000000..7b91d43
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.cpp
@@ -0,0 +1,121 @@
+#include "Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h"
+
+#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
+#include "Connector/Record/Model/ModelCard.h"
+#include "Speckle/Record/Credentials/Account.h"
+
+#include
+
+using namespace active::serialise;
+using namespace connector::record;
+using namespace connector::interfac::browser::bridge;
+using namespace speckle::database;
+using namespace speckle::record::cred;
+using namespace speckle::serialise;
+using namespace speckle::utility;
+
+namespace {
+
+ ///Serialisation fields
+ enum FieldIndex {
+ cardID,
+ projID,
+ modID,
+ tokenID,
+ serverID,
+ accID,
+ messageID,
+ sendObjectID,
+ convResultID,
+ };
+
+ ///Serialisation field IDs
+ static std::array fieldID = {
+ Identity{"modelCardId"},
+ Identity{"projectId"},
+ Identity{"modelId"},
+ Identity{"token"},
+ Identity{"serverUrl"},
+ Identity{"accountId"},
+ Identity{"message"},
+ Identity{"sendObject"},
+ Identity{"sendConversionResults"},
+ };
+
+}
+
+/*--------------------------------------------------------------------
+ Constructor
+
+ modelCard: The model card to populate into the send info for the browser
+ account: The account linked to the send
+ object: The object to be sent
+ results: The conversion results (reporting any conversion errors etc)
+ --------------------------------------------------------------------*/
+SendViaBrowserArgs::SendViaBrowserArgs(const ModelCard& modelCard, const Account& account, SendObject&& object) :
+ modelCardID(modelCard.getID()), projectID(modelCard.getProjectID()), modelID(modelCard.getModelID()), token{account.getToken()},
+ serverURL{account.getServerURL()}, accountID{account.getID()}, sendObject{std::move(object)} {
+} //SendViaBrowserArgs::SendViaBrowserArgs
+
+
+/*--------------------------------------------------------------------
+ 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 SendViaBrowserArgs::fillInventory(active::serialise::Inventory& inventory) const {
+ using enum Entry::Type;
+ inventory.merge(Inventory{
+ {
+ { fieldID[cardID], cardID, element },
+ { fieldID[projID], projID, element },
+ { fieldID[modID], modID, element },
+ { fieldID[tokenID], tokenID, element },
+ { fieldID[serverID], serverID, element },
+ { fieldID[accID], accID, element },
+ { fieldID[messageID], messageID, element },
+ { fieldID[sendObjectID], sendObjectID, element },
+ { fieldID[convResultID], convResultID, element },
+ },
+ }.withType(&typeid(SendViaBrowserArgs)));
+ return true;
+} //SendViaBrowserArgs::fillInventory
+
+
+/*--------------------------------------------------------------------
+ Get the specified cargo
+
+ item: The inventory item to retrieve
+
+ return: The requested cargo (nullptr on failure)
+ --------------------------------------------------------------------*/
+Cargo::Unique SendViaBrowserArgs::getCargo(const active::serialise::Inventory::Item& item) const {
+ if (item.ownerType != &typeid(SendViaBrowserArgs))
+ return nullptr;
+ using namespace active::serialise;
+ switch (item.index) {
+ case cardID:
+ return std::make_unique(modelCardID);
+ case projID:
+ return std::make_unique(projectID);
+ case modID:
+ return std::make_unique(modelID);
+ case tokenID:
+ return std::make_unique(token);
+ case serverID:
+ return std::make_unique(serverURL);
+ case accID:
+ return std::make_unique(accountID);
+ case messageID:
+ return std::make_unique(message);
+ case sendObjectID:
+ return std::make_unique(sendObject);
+ case convResultID:
+ sendConversionResults = sendObject.getConversionResults();
+ return Cargo::Unique{new ContainerWrap{sendConversionResults}};
+ default:
+ return nullptr; //Requested an unknown index
+ }
+} //SendViaBrowserArgs::getCargo
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h
new file mode 100644
index 0000000..e0ea188
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h
@@ -0,0 +1,89 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_SEND_VIA_BROWSER_ARGS
+#define CONNECTOR_INTERFACE_BRIDGE_SEND_VIA_BROWSER_ARGS
+
+#include "Active/Serialise/Package/Package.h"
+#include "Active/Utility/String.h"
+#include "Connector/Interface/Browser/Bridge/Send/Arg/SendConversionResult.h"
+#include "Connector/Interface/Browser/Bridge/Send/Arg/SendObject.h"
+#include "Speckle/Database/Identity/RecordID.h"
+
+namespace speckle::record::cred {
+ class Account;
+}
+
+namespace connector::record {
+ class ModelCard;
+}
+
+namespace connector::interfac::browser::bridge {
+
+ class ConnectorConfig;
+
+ /*!
+ A commit of a project version (model) to the Speckle server
+
+ An object of this type is prepared by the Send bridge method
+ */
+ class SendViaBrowserArgs final : public active::serialise::Package {
+ public:
+
+ // MARK: - Constructors
+
+ /*!
+ Constructor
+ @param modelCard The model card to populate into the send info for the browser
+ @param account The account linked to the send
+ @param object The object to be sent
+ */
+ SendViaBrowserArgs(const connector::record::ModelCard& modelCard, const speckle::record::cred::Account& account, SendObject&& object);
+
+ // MARK: - Public variables
+
+ ///ID of the model card driving the send request
+ speckle::database::RecordID modelCardID;
+ ///The source project ID (from the model card)
+ speckle::database::RecordID projectID;
+ ///The model ID (from the model card)
+ speckle::database::RecordID modelID;
+ ///The account token (from the user account info)
+ speckle::utility::String token;
+ ///The server URL (from the user account info)
+ speckle::utility::String serverURL;
+ ///The user account ID
+ speckle::utility::String accountID;
+ ///The send message
+ speckle::utility::String message; //TODO: Clarify what this is used for
+ ///The conversion report (summarising the conversion results on an element-by-element basis)
+ mutable std::vector sendConversionResults;
+ ///The commit content
+ SendObject sendObject;
+
+ // 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;
+ /*!
+ Use a manager in (de)serialisation processes
+ @param management The management to use
+ */
+ void useManagement(active::serialise::Management* management) const override { sendObject.useManagement(management); }
+ /*!
+ Get the cargo management
+ @return The active management
+ */
+ active::serialise::Management* management() const override { return sendObject.management(); }
+ };
+
+}
+
+#endif //CONNECTOR_INTERFACE_BRIDGE_SEND_VIA_BROWSER_ARGS
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendFilters.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendFilters.h
index 9f52396..c666e8f 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendFilters.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendFilters.h
@@ -18,7 +18,6 @@ namespace connector::interfac::browser::bridge {
/*!
Constructor
- @param bridge The parent bridge object (provides access to bridge methods)
*/
GetSendFilters();
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendSettings.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendSettings.cpp
new file mode 100644
index 0000000..5616a40
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendSettings.cpp
@@ -0,0 +1,36 @@
+#include "Connector/Interface/Browser/Bridge/Send/GetSendSettings.h"
+
+#include "Active/Container/Vector.h"
+#include "Active/Serialise/CargoHold.h"
+#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
+#include "Connector/Record/Model/CardSetting.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 = CargoHold, PackageWrap>, Vector>;
+
+}
+
+/*--------------------------------------------------------------------
+ Default constructor
+ --------------------------------------------------------------------*/
+GetSendSettings::GetSendSettings() : BridgeMethod{"GetSendSettings", [&]() {
+ return run();
+}} {}
+
+
+/*--------------------------------------------------------------------
+ Get send settings relevant to the host BIM application
+
+ return: The send settings
+ --------------------------------------------------------------------*/
+std::unique_ptr GetSendSettings::run() const {
+ auto filters = std::make_unique>();
+ return std::make_unique(std::move(filters));
+} //GetSendSettings::run
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendSettings.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendSettings.h
new file mode 100644
index 0000000..c57d274
--- /dev/null
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/GetSendSettings.h
@@ -0,0 +1,35 @@
+#ifndef CONNECTOR_INTERFACE_BRIDGE_GET_SEND_SETTINGS
+#define CONNECTOR_INTERFACE_BRIDGE_GET_SEND_SETTINGS
+
+#include "Active/Serialise/CargoHold.h"
+#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h"
+
+namespace connector::interfac::browser::bridge {
+
+ class ConnectorConfig;
+
+ /*!
+ JS Function class to retrieve the send settings relevant to the host BIM application
+ */
+ class GetSendSettings : public speckle::interfac::browser::bridge::BridgeMethod {
+ public:
+
+ // MARK: - Constructors
+
+ /*!
+ Constructor
+ */
+ GetSendSettings();
+
+ // MARK: - Functions (const)
+
+ /*!
+ Get send settings relevant to the host BIM application
+ @return The send settings
+ */
+ std::unique_ptr run() const;
+ };
+
+}
+
+#endif //CONNECTOR_INTERFACE_BRIDGE_GET_SEND_SETTINGS
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp
index a037058..002b24f 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp
@@ -2,10 +2,34 @@
#include "Active/Serialise/CargoHold.h"
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
+#include "Connector/Connector.h"
+#include "Connector/ConnectorResource.h"
+#include "Connector/Database/ModelCardDatabase.h"
+#include "Connector/Environment/ConnectorProject.h"
+#include "Connector/Interface/Browser/Bridge/Send/Arg/SendConversionResult.h"
+#include "Connector/Interface/Browser/Bridge/Send/Arg/SendViaBrowserArgs.h"
+#include "Connector/Record/Collection/ProjectCollection.h"
+#include "Connector/Record/Model/SenderModelCard.h"
+#include "Connector/Record/Model/Filter/SendFilter.h"
+#include "Speckle/Database/AccountDatabase.h"
+#include "Speckle/Database/BIMElementDatabase.h"
+#include "Speckle/Database/Content/BIMRecord.h"
+#include "Speckle/Environment/Project.h"
+#include "Speckle/Environment/Host.h"
+#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h"
+#include "Speckle/Record/Credentials/Account.h"
+#include "Speckle/Record/Element/Element.h"
+#include "Speckle/Serialise/Detached/Storage/DetachedMemoryStore.h"
#include "Speckle/Utility/Exception.h"
using namespace active::serialise;
+using namespace connector::environment;
using namespace connector::interfac::browser::bridge;
+using namespace connector::record;
+using namespace speckle::database;
+using namespace speckle::environment;
+using namespace speckle::record::element;
+using namespace speckle::serialise;
using namespace speckle::utility;
/*--------------------------------------------------------------------
@@ -19,9 +43,56 @@ Send::Send() : BridgeMethod{"Send", [&](const SendArgs& args) {
/*--------------------------------------------------------------------
Send a specified model
- modelCardID: The ID of the madel to send
+ modelCardID: The ID of the model card identifying the objects to send
--------------------------------------------------------------------*/
void Send::run(const String& modelCardID) const {
- ///TODO: Find and send selected elements - the following is a placeholder
- throw Exception{"No objects were found to convert. Please update your publish filter!"};
+ //We can currently only send from the 3D model view
+ host()->makeModelViewActive(true);
+ //Get the active project
+ auto project = connector()->getActiveProject().lock();
+ if (!project) {
+ getBridge()->sendEvent("setModelError",
+ std::make_unique(connector()->getLocalString(errorString, noProjectOpenID), modelCardID));
+ return;
+ }
+ auto connectorProject = dynamic_cast(project.get());
+ if (!connectorProject)
+ return;
+ //Find the specified model card
+ auto modelCardDatabase = connectorProject->getModelCardDatabase();
+ auto modelCard = modelCardDatabase->getCard(modelCardID);
+ if (!modelCard) {
+ getBridge()->sendEvent("setModelError",
+ std::make_unique(connector()->getLocalString(errorString, modelCardNotFoundID), modelCardID));
+ return;
+ }
+ //Get the user account
+ auto accountDatabase = connector()->getAccountDatabase();
+ auto account = accountDatabase->getAccount(modelCard->getAccountID(), modelCard->getServerURL());
+ if (!account) {
+ getBridge()->sendEvent("setModelError",
+ std::make_unique(connector()->getLocalString(errorString, accountNotFoundID), modelCardID));
+ return;
+ }
+ //Get the selected elements from the modelcard
+ auto elementDatabase = project->getElementDatabase();
+ ElementIDList selected{};
+ if (auto senderCard = dynamic_cast(modelCard.get())) {
+ selected = senderCard->getFilter().getElementIDs();
+ }
+ //Build a collection from the selected elements
+ auto collection = std::make_unique(project, modelCard->getID());
+ for (const auto& link : selected) {
+ if (auto element = elementDatabase->getElement(link); element)
+ collection->addElement(*element);
+ else {
+ //Report failure to convert element
+ collection->logRecord(link, {ConversionReporter::Data::Status::failure, String{}, String{},
+ connector()->getLocalString(errorString, elementTypeNotConvertedID)}, false);
+ collection->incrementSkippedRecords();
+ }
+ }
+ //Send the collected information
+ auto result = std::make_unique(*modelCard, *account, SendObject{std::move(collection)});
+ getBridge()->sendEvent("sendByBrowser", std::move(result));
} //Send::run
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.h
index 60ab477..7c3cb44 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.h
@@ -25,7 +25,6 @@ namespace connector::interfac::browser::bridge {
/*!
Constructor
- @param bridge The parent bridge object (provides access to bridge methods)
*/
Send();
@@ -33,7 +32,7 @@ namespace connector::interfac::browser::bridge {
/*!
Send a specified model
- @param modelCardID The ID of the madel to send
+ @param modelCardID The ID of the model card identifying the objects to send
*/
void run(const speckle::utility::String& modelCardID) const;
};
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.cpp
index d4180e6..6d8ae7e 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.cpp
@@ -1,9 +1,28 @@
#include "Connector/Interface/Browser/Bridge/Send/SendBridge.h"
-
#include "Connector/Interface/Browser/Bridge/Send/GetSendFilters.h"
+#include "Connector/Interface/Browser/Bridge/Send/GetSendSettings.h"
#include "Connector/Interface/Browser/Bridge/Send/Send.h"
+#include "Connector/Connector.h"
+#include "Connector/ConnectorResource.h"
+#include "Connector/Database/ModelCardDatabase.h"
+#include "Connector/Environment/ConnectorProject.h"
+#include "Speckle/Event/Type/ElementEvent.h"
+#include "Speckle/Record/Element/Element.h"
+#include "Speckle/Database/BIMElementDatabase.h"
+#include "Speckle/Environment/Project.h"
+#include "Speckle/Database/Identity/RecordID.h"
+#include "Active/Serialise/CargoHold.h"
+#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
+#include "Connector/Record/Model/SenderModelCard.h"
+#include "Connector/Record/Model/Filter/SendFilter.h"
+using namespace speckle::database;
+using namespace connector::environment;
using namespace connector::interfac::browser::bridge;
+using namespace speckle::utility;
+using namespace speckle::event;
+using namespace active::serialise;
+using namespace connector::record;
/*--------------------------------------------------------------------
Default constructor
@@ -11,5 +30,58 @@ using namespace connector::interfac::browser::bridge;
SendBridge::SendBridge() : BrowserBridge{"sendBinding"} {
//Add bridge methods
addMethod();
+ addMethod();
addMethod();
} //SendBridge::SendBridge
+
+
+/*--------------------------------------------------------------------
+ Handle an element change
+
+ event: The selection event
+
+ return: True if the event should be closed
+ --------------------------------------------------------------------*/
+bool SendBridge::handle(const ElementEvent& event) {
+ using enum ElementEvent::Type;
+ auto eventType = event.getEventType();
+ switch (eventType) {
+ case begin:
+ m_changedElements.clear();
+ break;
+ case end: {
+ auto project = connector()->getActiveProject().lock();
+ auto connectorProject = dynamic_cast(project.get());
+ if (!connectorProject)
+ return false;
+ auto modelCardDatabase = connectorProject->getModelCardDatabase();
+ auto modelCards = modelCardDatabase->getCards();
+ // POC: this is probably not efficient, should test, review and refactor it
+ RecordIDList expiredModelCardIds;
+ for (const auto& modelCard : modelCards) {
+ if (auto senderCard = dynamic_cast(modelCard.get())) {
+ auto modelCardSelection = senderCard->getFilter().getElementIDs();
+ for (const auto& elemId : modelCardSelection) {
+ if (std::find(m_changedElements.begin(), m_changedElements.end(), elemId) != m_changedElements.end()) {
+ expiredModelCardIds.push_back(modelCard->getID());
+ break;
+ }
+ }
+ }
+ }
+ if (!expiredModelCardIds.empty()) {
+ auto wrapped = std::make_unique, RecordIDList>>(std::move(expiredModelCardIds));
+ sendEvent("setModelsExpired", std::move(wrapped));
+ }
+ break;
+ }
+ case changeElem: case editElem: case deleteElem: {
+ if (event.getElmentID())
+ m_changedElements.push_back(*event.getElmentID());
+ break;
+ }
+ default:
+ break;
+ }
+ return false;
+} //SendBridge::handle
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.h
index e05f980..391cb57 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.h
@@ -2,13 +2,14 @@
#define CONNECTOR_INTERFACE_BRIDGE_SEND_BRIDGE
#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h"
+#include "Speckle/Event/Subscriber/ElementSubscriber.h"
namespace connector::interfac::browser::bridge {
/*!
A browser bridge to support sending model data to a Speckle server
*/
- class SendBridge : public speckle::interfac::browser::bridge::BrowserBridge {
+ class SendBridge : public speckle::interfac::browser::bridge::BrowserBridge, public speckle::event::ElementSubscriber {
public:
// MARK: - Types
@@ -22,6 +23,14 @@ namespace connector::interfac::browser::bridge {
Default constructor
*/
SendBridge();
+
+ protected:
+ /*!
+ Handle an element change
+ @param event The selection event
+ @return True if the event should be closed
+ */
+ bool handle(const speckle::event::ElementEvent& event) override;
};
}
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/GetComplexType.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/GetComplexType.h
index 9e9a532..742ad20 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/GetComplexType.h
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/GetComplexType.h
@@ -1,5 +1,5 @@
-#ifndef CONNECTOR_INTERFACE_BRIDGE_GET_CONFIG
-#define CONNECTOR_INTERFACE_BRIDGE_GET_CONFIG
+#ifndef CONNECTOR_INTERFACE_BRIDGE_GET_COMPLEX_TYPE
+#define CONNECTOR_INTERFACE_BRIDGE_GET_COMPLEX_TYPE
#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h"
@@ -15,7 +15,6 @@ namespace connector::interfac::browser::bridge {
/*!
Constructor
- @param bridge The parent bridge object (provides access to bridge methods)
*/
GetComplexType();
@@ -30,4 +29,4 @@ namespace connector::interfac::browser::bridge {
}
-#endif //CONNECTOR_INTERFACE_BRIDGE_GET_CONFIG
+#endif //CONNECTOR_INTERFACE_BRIDGE_GET_COMPLEX_TYPE
diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/GoAway.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/GoAway.cpp
index 69c0a90..3693d41 100644
--- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/GoAway.cpp
+++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/GoAway.cpp
@@ -1,8 +1,9 @@
#include "Connector/Interface/Browser/Bridge/Test/GoAway.h"
-using namespace connector::interfac::browser::bridge;
+#include "Speckle/Environment/Platform.h"
-#include
+using namespace connector::interfac::browser::bridge;
+using namespace speckle::environment;
/*--------------------------------------------------------------------
Default constructor
@@ -16,5 +17,5 @@ GoAway::GoAway() : BridgeMethod{"GoAway", [&]() {
Write a message to the console
--------------------------------------------------------------------*/
void GoAway::run() const {
- std::cout << "Okay, going away.";
+ platform()->writeToConsole("Okay, going away.");
} //GoAway::run
diff --git a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp
index 53c0ab8..5dd0408 100644
--- a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp
+++ b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp
@@ -1,17 +1,24 @@
#include "Connector/Interface/ConnectorPalette.h"
#include "Active/Event/Event.h"
+#include "Active/Utility/String.h"
+#include "Active/Serialise/JSON/JSONTransport.h"
+#include "Active/Utility/BufferOut.h"
+#include "Connector/Connector.h"
#include "Connector/ConnectorResource.h"
#include "Connector/Event/ConnectorEventID.h"
#include "Connector/Interface/Browser/Bridge/Account/AccountBridge.h"
#include "Connector/Interface/Browser/Bridge/Base/BaseBridge.h"
#include "Connector/Interface/Browser/Bridge/Config/ConfigBridge.h"
#include "Connector/Interface/Browser/Bridge/Send/SendBridge.h"
+#include "Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h"
#include "Connector/Interface/Browser/Bridge/Test/TestBridge.h"
#include "Speckle/Environment/Addon.h"
#include "Speckle/Event/Type/MenuEvent.h"
#include "Speckle/Interface/Browser/JSPortal.h"
+#include "Speckle/Event/Type/ProjectEvent.h"
+
#include
#include
#include
@@ -73,9 +80,6 @@ namespace {
virtual void PanelResized(const DG::PanelResizeEvent& ev) override;
virtual void PanelCloseRequested(const DG::PanelCloseRequestEvent& ev, bool* accepted) override;
- static GS::Array GetSelectedElements();
- static void ModifySelection(const GS::UniString& elemGuidStr, SelectionModification modification);
-
static GSErrCode __ACENV_CALL PaletteControlCallBack(Int32 paletteId, API_PaletteMessageID messageID, GS::IntPtr param);
static GS::Ref instance;
@@ -106,7 +110,9 @@ ConnectorPalette::ConnectorPalette() {
return: The subscription list (an empty list will put the subscriber into a suspended state)
--------------------------------------------------------------------*/
ConnectorPalette::Subscription ConnectorPalette::subscription() const {
- return { {toggleConnectorPaletteID} };
+ auto result = ProjectSubscriber::subscription();
+ result.insert(toggleConnectorPaletteID);
+ return result;
} //ConnectorPalette::subscription
@@ -128,16 +134,49 @@ bool ConnectorPalette::start() {
return: True if the event should be closed
--------------------------------------------------------------------*/
bool ConnectorPalette::receive(const active::event::Event& event) {
- if (BrowserPalette::HasInstance() && BrowserPalette::GetInstance().IsVisible()) {
- BrowserPalette::GetInstance().Hide ();
- } else {
- if (!BrowserPalette::HasInstance())
- BrowserPalette::CreateInstance();
- BrowserPalette::GetInstance().Show();
+ if (event == toggleConnectorPaletteID) {
+ if (BrowserPalette::HasInstance() && BrowserPalette::GetInstance().IsVisible()) {
+ BrowserPalette::GetInstance().Hide();
+ }
+ else {
+ if (!BrowserPalette::HasInstance())
+ BrowserPalette::CreateInstance();
+ BrowserPalette::GetInstance().Show();
+ }
+ return true;
}
- return true;
+
+ return ProjectSubscriber::receive(event);
+
} //ConnectorPalette::receive
+/*--------------------------------------------------------------------
+ Handle a project event
+
+ event: The project event
+
+ return: True if the event should be closed
+ --------------------------------------------------------------------*/
+bool ConnectorPalette::handle(const speckle::event::ProjectEvent& event) {
+ using enum speckle::event::ProjectEvent::Type;
+ switch (event.getType()) {
+ case open: {
+ if (BrowserPalette::HasInstance() && !BrowserPalette::GetInstance().IsVisible()) {
+ BrowserPalette::GetInstance().Show();
+ BrowserPalette::GetInstance().EnableItems();
+ }
+ } break;
+ case close: {
+ if (BrowserPalette::HasInstance() && BrowserPalette::GetInstance().IsVisible()) {
+ BrowserPalette::GetInstance().Hide();
+ }
+ } break;
+ default:
+ break;
+ }
+ return false;
+} //ConnectorPalette::handle
+
//NB: Following is placeholder from GS example code - will be refactored to better suit our purposes
@@ -164,9 +203,29 @@ BrowserPalette::BrowserPalette() :
BeginEventProcessing();
//Install required connector bridges
install();
- install();
+
+ if (auto ref = install(); ref) {
+ if (auto baseBridgeRef = std::dynamic_pointer_cast(ref); baseBridgeRef) {
+ connector::connector()->addWeak(baseBridgeRef);
+ }
+ }
+
install();
- install();
+
+ if (auto ref = install(); ref) {
+ if (auto sendBridgeRef = std::dynamic_pointer_cast(ref); sendBridgeRef) {
+ connector::connector()->addWeak(sendBridgeRef);
+ sendBridgeRef->start();
+ }
+ }
+
+ if (auto ref = install(); ref) {
+ if (auto selectionBridgeRef = std::dynamic_pointer_cast(ref); selectionBridgeRef) {
+ connector::connector()->addWeak(selectionBridgeRef);
+ selectionBridgeRef->start();
+ }
+ }
+
install();
InitBrowserControl();
}
@@ -206,7 +265,8 @@ void BrowserPalette::Hide() {
void BrowserPalette::InitBrowserControl() {
#ifdef TESTING_MODE
- browser->LoadURL("https://boisterous-douhua-e3cefb.netlify.app/test");
+ //browser->LoadURL("https://boisterous-douhua-e3cefb.netlify.app/test");
+ browser->LoadURL("https://boisterous-douhua-e3cefb.netlify.app");
#else
browser->LoadURL("https://boisterous-douhua-e3cefb.netlify.app/");
#endif
@@ -239,31 +299,6 @@ void BrowserPalette::PanelCloseRequested(const DG::PanelCloseRequestEvent&, bool
*accepted = true;
}
-GS::Array BrowserPalette::GetSelectedElements() {
- API_SelectionInfo selectionInfo;
- GS::Array selNeigs;
- ACAPI_Selection_Get(&selectionInfo, &selNeigs, false, false);
- BMKillHandle((GSHandle*)&selectionInfo.marquee.coords);
-
- GS::Array selectedElements;
- for(const API_Neig& neig : selNeigs) {
- API_Elem_Head elemHead = {};
- elemHead.guid = neig.guid;
- ACAPI_Element_GetHeader(&elemHead);
-
- ElementInfo elemInfo;
- elemInfo.guidStr = APIGuidToString(elemHead.guid);
- ACAPI_Element_GetElemTypeName(elemHead.type, elemInfo.typeName);
- ACAPI_Element_GetElementInfoString(&elemHead.guid, &elemInfo.elemID);
- selectedElements.Push(elemInfo);
- }
- return selectedElements;
-}
-
-void BrowserPalette::ModifySelection(const GS::UniString& elemGuidStr, BrowserPalette::SelectionModification modification) {
- ACAPI_Selection_Select({ API_Neig(APIGuidFromString(elemGuidStr.ToCStr().Get())) }, modification == AddToSelection);
-}
-
GSErrCode __ACENV_CALL BrowserPalette::PaletteControlCallBack(Int32, API_PaletteMessageID messageID, GS::IntPtr param) {
switch(messageID) {
case APIPalMsg_OpenPalette:
@@ -284,18 +319,10 @@ GSErrCode __ACENV_CALL BrowserPalette::PaletteControlCallBack(Int32, API_Palette
break;
case APIPalMsg_HidePalette_End:
- if(HasInstance() && !GetInstance().IsVisible())
+ if (HasInstance() && !GetInstance().IsVisible())
+ {
GetInstance().Show();
- break;
-
- case APIPalMsg_DisableItems_Begin:
- if(HasInstance() && GetInstance().IsVisible())
- GetInstance().DisableItems();
- break;
-
- case APIPalMsg_DisableItems_End:
- if(HasInstance() && GetInstance().IsVisible())
- GetInstance().EnableItems();
+ }
break;
case APIPalMsg_IsPaletteVisible:
diff --git a/SpeckleConnector/Connector/Interface/ConnectorPalette.h b/SpeckleConnector/Connector/Interface/ConnectorPalette.h
index 289e243..b756242 100644
--- a/SpeckleConnector/Connector/Interface/ConnectorPalette.h
+++ b/SpeckleConnector/Connector/Interface/ConnectorPalette.h
@@ -2,10 +2,11 @@
#define CONNECTOR_CONNECTOR_PALETTE
#include "Active/Event/Subscriber.h"
+#include "Speckle/Event/Subscriber/ProjectSubscriber.h"
namespace connector {
- class ConnectorPalette : public active::event::Subscriber {
+ class ConnectorPalette : public speckle::event::ProjectSubscriber {
public:
/*!
Default constructor
@@ -32,6 +33,13 @@ namespace connector {
@return True if the event should be closed
*/
bool receive(const active::event::Event& event) override;
+ protected:
+ /*!
+ Handle the project events
+ @param event The project event
+ @return True if the event should be closed
+ */
+ bool handle(const speckle::event::ProjectEvent& event) override;
};
}
diff --git a/SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp b/SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp
new file mode 100644
index 0000000..3979204
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Collection/FinishProxy.cpp
@@ -0,0 +1,68 @@
+#include "Connector/Record/Collection/FinishProxy.h"
+
+#include "Active/Serialise/Package/Wrapper/ContainerWrap.h"
+#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
+
+#include
+
+using namespace active::serialise;
+using namespace connector::record;
+using namespace speckle::utility;
+
+namespace {
+
+ ///Serialisation fields
+ enum FieldIndex {
+ materialID,
+ linkedMeshID,
+ };
+
+ ///Serialisation field IDs
+ static std::array fieldID = {
+ Identity{"value"},
+ Identity{"objects"},
+ };
+
+}
+
+/*--------------------------------------------------------------------
+ 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 FinishProxy::fillInventory(active::serialise::Inventory& inventory) const {
+ using enum Entry::Type;
+ inventory.merge(Inventory{
+ {
+ { fieldID[materialID], materialID, element },
+ { fieldID[linkedMeshID], linkedMeshID, element },
+ },
+ }.withType(&typeid(FinishProxy)));
+ return base::fillInventory(inventory);
+} //FinishProxy::fillInventory
+
+
+/*--------------------------------------------------------------------
+ Get the specified cargo
+
+ item: The inventory item to retrieve
+
+ return: The requested cargo (nullptr on failure)
+ --------------------------------------------------------------------*/
+Cargo::Unique FinishProxy::getCargo(const active::serialise::Inventory::Item& item) const {
+ if (item.ownerType != &typeid(FinishProxy))
+ return base::getCargo(item);
+ using namespace active::serialise;
+ switch (item.index) {
+ case materialID:
+ return std::make_unique(m_finish);
+ case linkedMeshID: {
+ auto result = new ContainerWrap(m_meshID);
+ return Cargo::Unique{result};
+ }
+ default:
+ return nullptr; //Requested an unknown index
+ }
+} //FinishProxy::getCargo
diff --git a/SpeckleConnector/Connector/Record/Collection/FinishProxy.h b/SpeckleConnector/Connector/Record/Collection/FinishProxy.h
new file mode 100644
index 0000000..3ad7b3e
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Collection/FinishProxy.h
@@ -0,0 +1,60 @@
+#ifndef CONNECTOR_RECORD_COLLECTION_MATERIAL_PROXY
+#define CONNECTOR_RECORD_COLLECTION_MATERIAL_PROXY
+
+#include "Speckle/Database/Content/BIMRecord.h"
+#include "Speckle/Record/Attribute/Finish.h"
+#include "Speckle/Utility/String.h"
+
+namespace connector::record {
+
+ /*!
+ A proxy record binding a surface finishes to meshes
+ */
+ class FinishProxy : public speckle::database::BIMRecord {
+ public:
+
+ using base = speckle::database::BIMRecord;
+
+ // MARK: - Constructors
+
+ /*!
+ Constructor
+ @param finish The proxy surface finish
+ @param meshID The list of mesh IDs the finish is applied to
+ */
+ FinishProxy(const speckle::record::attribute::Finish& finish, const std::unordered_set& meshID) :
+ base{speckle::utility::Guid{true}, speckle::utility::Guid{}, std::nullopt}, m_finish{finish} {
+ std::copy(meshID.begin(), meshID.end(), std::back_inserter(m_meshID));
+ }
+
+ /*!
+ Get the speckle type identifier
+ @return The speckle type (relevant objects should override as required, but "Base" is still considered a type on its own)
+ */
+ speckle::utility::String getSpeckleType() const override { return "Objects.Other.RenderMaterialProxy"; }
+
+ // 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;
+
+ private:
+ ///The proxy surface finish
+ speckle::record::attribute::Finish m_finish;
+ ///The list of mesh IDs the finish is applied to
+ std::vector m_meshID;
+ };
+
+}
+
+#endif //CONNECTOR_RECORD_COLLECTION_MATERIAL_PROXY
diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp
new file mode 100644
index 0000000..9a38c85
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp
@@ -0,0 +1,202 @@
+#include "Connector/Record/Collection/ProjectCollection.h"
+
+#include "Active/Serialise/CargoHold.h"
+#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
+#include "Active/Serialise/Management/Management.h"
+#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
+#include "Connector/Connector.h"
+#include "Connector/ConnectorResource.h"
+#include "Connector/Record/Collection/FinishProxy.h"
+#include "Speckle/Database/BIMAttributeDatabase.h"
+#include "Speckle/Database/BIMElementDatabase.h"
+#include "Speckle/Record/Attribute/Finish.h"
+#include "Speckle/Record/Element/Element.h"
+
+#include
+
+#ifdef ARCHICAD
+#include
+#include
+#endif
+
+using namespace active::serialise;
+using namespace connector::record;
+using namespace speckle::database;
+using namespace speckle::record::attribute;
+using namespace speckle::utility;
+
+#ifdef ARCHICAD
+namespace connector::record {
+ class ProjectCollection::FinishCache : public std::unordered_map {};
+}
+#endif
+
+namespace {
+
+ ///Serialisation fields
+ enum FieldIndex {
+ finishProxyID,
+ };
+
+ ///Serialisation field IDs
+ static std::array fieldID = {
+ Identity{"renderMaterialProxies"},
+ };
+
+ using WrappedProxy = CargoHold;
+
+}
+
+/*--------------------------------------------------------------------
+ Constructor
+
+ project: The source project
+ modelCardID: The model card ID for the send operation
+ --------------------------------------------------------------------*/
+ProjectCollection::ProjectCollection(speckle::environment::Project::Shared project, const RecordID& modelCardID) :
+ base{project->getInfo().name, project}, ConversionReporter{modelCardID}, m_management {
+ std::make_unique()
+} {
+ m_management->push_back(this);
+ m_finishes = std::make_unique();
+ base::useManagement(m_management.get());
+} //ProjectCollection::ProjectCollection
+
+
+/*--------------------------------------------------------------------
+ Destructor
+ --------------------------------------------------------------------*/
+ProjectCollection::~ProjectCollection() {
+} //ProjectCollection::~ProjectCollection
+
+
+/*--------------------------------------------------------------------
+ Add an element to the collection hierarchy
+
+ index The index of the element to add
+
+ return: True if the element was added (false typically means the element already exists)
+ --------------------------------------------------------------------*/
+bool ProjectCollection::addElement(const speckle::database::BIMIndex& index) {
+ //Lookup the element in the element database of the active project
+ auto elementDbase = m_project->getElementDatabase();
+ if (elementDbase == nullptr)
+ return false;
+ if (auto element = elementDbase->getElement(index); element) {
+ addElement(*element); //Add the element to the collection hierarchy
+ return true;
+ }
+ return false;
+} //ProjectCollection::addElement
+
+
+/*--------------------------------------------------------------------
+ Add an element to the collection hierarchy
+
+ element: The element to add
+
+ return: True if the element was added (false typically means the element already exists)
+ --------------------------------------------------------------------*/
+bool ProjectCollection::addElement(const speckle::record::element::Element& element) {
+ std::vector collectionNames;
+ //The first collection hierarchy level is the element storey/level
+ auto storey = element.getStorey();
+ collectionNames.emplace_back(storey ? storey->getName() : connector()->getLocalString(titleString, noStoreyID));
+ //The next level is the name of the element type
+ collectionNames.emplace_back(element.getTypeName());
+ //Add any future levels here as required
+ RecordCollection* collection = this;
+ for (const auto& childName : collectionNames)
+ collection = collection->getChild(childName);
+ if (!collection->addIndex(BIMIndex{element.getBIMID(), element.getTableID()}))
+ return false;
+ incrementProjectedRecords();
+ return true;
+} //ProjectCollection::addElement
+
+
+/*--------------------------------------------------------------------
+ Add a material proxy record to the collection
+
+ materialIndex: The index of the material to add
+ objectID: The object the material is applied to
+
+ return: True if the material proxy was added (false typically means the record already exists)
+ --------------------------------------------------------------------*/
+bool ProjectCollection::addFinishProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID) {
+ auto iter = m_finishProxies.find(materialIndex);
+ if (iter == m_finishProxies.end())
+ iter = m_finishProxies.insert({materialIndex, {}}).first;
+ return iter->second.insert(objectID).second;
+} //ProjectCollection::addFinishProxy
+
+
+/*--------------------------------------------------------------------
+ Add a ModelerAPI material to the collection (NB: These are not persistent so need to be captured by this method)
+
+ material: A material
+ objectID: The object the material is applied to
+
+ return: True if the material proxy was added (false typically means the record already exists)
+ --------------------------------------------------------------------*/
+bool ProjectCollection::addFinishProxy(const Finish& finish, const speckle::database::BIMRecordID& objectID) {
+ auto iter = m_finishes->find(finish.getBIMID());
+ if (iter == m_finishes->end())
+ iter = m_finishes->insert({finish.getBIMID(), finish}).first;
+ return addFinishProxy(speckle::database::BIMIndex{finish.getBIMID()}, objectID);
+} //ProjectCollection::addFinishProxy
+
+
+/*--------------------------------------------------------------------
+ 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 ProjectCollection::fillInventory(active::serialise::Inventory& inventory) const {
+ using enum Entry::Type;
+ base::fillInventory(inventory);
+ inventory.merge(Inventory{
+ {
+ { Identity{fieldID[finishProxyID]}, finishProxyID, std::numeric_limits::max(), std::nullopt },
+ },
+ }.withType(&typeid(ProjectCollection)));
+ return true;
+} //ProjectCollection::fillInventory
+
+
+/*--------------------------------------------------------------------
+ Get the specified cargo
+
+ item: The inventory item to retrieve
+
+ return: The requested cargo (nullptr on failure)
+ --------------------------------------------------------------------*/
+Cargo::Unique ProjectCollection::getCargo(const Inventory::Item& item) const {
+ if (item.ownerType != &typeid(ProjectCollection))
+ return base::getCargo(item);
+ using namespace active::serialise;
+ //TODO: This is only currently coded to write collection content - reading can be added as required in future
+ switch (item.index) {
+ case finishProxyID: {
+ if (item.available < m_finishProxies.size()) {
+ auto iter = m_finishProxies.begin();
+ std::advance(iter, item.available);
+ const Finish* finish = nullptr;
+ if (auto fin = m_finishes->find(iter->first); fin != m_finishes->end())
+ finish = &fin->second;
+ else if (auto attribute = m_project->getAttributeDatabase()->getAttribute(iter->first, iter->first.tableID); attribute)
+ finish = dynamic_cast(attribute.get());
+ if (finish != nullptr) {
+ auto proxy = std::make_unique(*finish, iter->second);
+ return std::make_unique(std::move(proxy));
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return nullptr; //Requested an unknown index
+} //ProjectCollection::getCargo
diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h
new file mode 100644
index 0000000..cc1e9e6
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h
@@ -0,0 +1,111 @@
+#ifndef CONNECTOR_RECORD_ROOT_COLLECTiON
+#define CONNECTOR_RECORD_ROOT_COLLECTiON
+
+#include "Connector/Record/Collection/RecordCollection.h"
+#include "Speckle/Serialise/Collection/FinishCollector.h"
+#include "Speckle/Serialise/Collection/ConversionReporter.h"
+
+#include
+
+namespace active::serialise {
+ class Management;
+}
+
+namespace speckle::record::element {
+ class Element;
+}
+
+namespace connector::record {
+
+ /*!
+ Root collection for sending a project model to a Speckle server
+
+ Additional information is anticipated at the root level that will not apply at any other level in the container hierarchy, e.g.:
+ - Classification hierarchy
+ - Layers
+ - Other attributes, e.g. materials
+ Add all this supplementary data to the root container as required
+ */
+ class ProjectCollection : public RecordCollection, public speckle::serialise::FinishCollector, public speckle::serialise::ConversionReporter {
+ public:
+
+ // MARK: - Types
+
+ using base = RecordCollection;
+
+ // MARK: - Constructors
+
+ /*!
+ Constructor
+ @param project The source project
+ @param modelCardID The model card ID for the send operation
+ */
+ ProjectCollection(speckle::environment::Project::Shared project, const speckle::database::RecordID& modelCardID);
+ ProjectCollection(const ProjectCollection&) = delete;
+ /*!
+ Destructor
+ */
+ ~ProjectCollection();
+
+ using base::base;
+
+ // MARK: - Functions (const)
+
+ // MARK: - Functions (mutating)
+
+ /*!
+ Add an element to the collection hierarchy
+ @param index The index of the element to add
+ @return True if the element was added (false typically means the element already exists)
+ */
+ bool addElement(const speckle::database::BIMIndex& index);
+ /*!
+ Add an element to the collection hierarchy
+ @param element The element to add
+ @return True if the element was added (false typically means the element already exists)
+ */
+ bool addElement(const speckle::record::element::Element& element);
+ /*!
+ Add a material proxy record to the collection
+ @param materialIndex The index of the material to add
+ @param objectID The object the material is applied to
+ @return True if the material proxy was added (false typically means the record already exists)
+ */
+ bool addFinishProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID) override;
+ /*!
+ Add a ModelerAPI material to the collection (NB: These are not persistent so need to be captured by this method)
+ @param finish A finish
+ @param objectID The object the material is applied to
+ @return True if the material proxy was added (false typically means the record already exists)
+ */
+ bool addFinishProxy(const speckle::record::attribute::Finish& finish, const speckle::database::BIMRecordID& objectID) override;
+
+ // 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)
+ */
+ active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
+
+ private:
+ using FinishProxies = std::unordered_map>;
+
+ std::unique_ptr m_management;
+ ///Finish proxies accumulated from meshes generated from the collection elements
+ FinishProxies m_finishProxies;
+ class FinishCache;
+ ///Finishes cache
+ std::unique_ptr m_finishes;
+ };
+
+}
+
+#endif //CONNECTOR_RECORD_ROOT_COLLECTiON
diff --git a/SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp b/SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp
new file mode 100644
index 0000000..55e747a
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Collection/RecordCollection.cpp
@@ -0,0 +1,127 @@
+#include "Connector/Record/Collection/RecordCollection.h"
+
+#include "Active/Serialise/CargoHold.h"
+#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
+#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
+#include "Speckle/Database/BIMElementDatabase.h"
+
+using namespace active::serialise;
+using namespace connector::record;
+using namespace speckle::database;
+using namespace speckle::environment;
+using namespace speckle::record::element;
+using namespace speckle::utility;
+
+#include
+
+namespace {
+
+ ///Serialisation fields
+ enum FieldIndex {
+ nameID,
+ elementID,
+ };
+
+ ///Serialisation field IDs
+ static std::array fieldID = {
+ Identity{"name"},
+ Identity{"elements"},
+ };
+
+ using WrappedElement = CargoHold;
+
+}
+
+/*--------------------------------------------------------------------
+ Constructor
+
+ name: The collection name
+ project: The source project
+ --------------------------------------------------------------------*/
+RecordCollection::RecordCollection(const speckle::utility::String& name, Project::Shared project) : m_name{name}, m_project{project} {
+} //RecordCollection::RecordCollection
+
+
+/*--------------------------------------------------------------------
+ Get a child collection by name (adding if missing)
+
+ name: The child name
+
+ return: A pointer to the requested child (nullptr on failure, caller does not take ownership)
+ --------------------------------------------------------------------*/
+RecordCollection* RecordCollection::getChild(const speckle::utility::String& name) {
+ //Return an existing child if possible
+ if (auto iter = m_children.find(name); iter != m_children.end())
+ return &iter->second;
+ //Otherwise insert and return a new collection with the requested name
+ return &m_children.insert({name, RecordCollection{name, m_project}}).first->second;
+} //RecordCollection::getChild
+
+
+/*--------------------------------------------------------------------
+ Add an index to the collection
+
+ index: The index to add
+
+ return: True if the index was added (false typically means the index already exists)
+ --------------------------------------------------------------------*/
+bool RecordCollection::addIndex(const speckle::database::BIMIndex& index) {
+ return m_indices.insert(index).second;
+} //RecordCollection::addIndex
+
+
+/*--------------------------------------------------------------------
+ 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 RecordCollection::fillInventory(active::serialise::Inventory& inventory) const {
+ using enum Entry::Type;
+ base::fillInventory(inventory);
+ inventory.merge(Inventory{
+ {
+ { Identity{fieldID[nameID]}, nameID, element },
+ { Identity{fieldID[elementID]}, elementID, m_children.size() + m_indices.size(), std::nullopt },
+ },
+ }.withType(&typeid(RecordCollection)));
+ return true;
+} //RecordCollection::fillInventory
+
+
+/*--------------------------------------------------------------------
+ Get the specified cargo
+
+ item: The inventory item to retrieve
+
+ return: The requested cargo (nullptr on failure)
+ --------------------------------------------------------------------*/
+Cargo::Unique RecordCollection::getCargo(const Inventory::Item& item) const {
+ if (item.ownerType != &typeid(RecordCollection))
+ return base::getCargo(item);
+ using namespace active::serialise;
+ //TODO: This is only currently coded to write collection content - reading can be added as required in future
+ switch (item.index) {
+ case nameID:
+ return std::make_unique(m_name);
+ case elementID: {
+ if (item.available < m_children.size()) {
+ auto iter = m_children.begin();
+ std::advance(iter, item.available);
+ return std::make_unique(iter->second);
+ }
+ auto index = item.available - m_children.size();
+ if (index < m_indices.size()) {
+ auto iter = m_indices.begin();
+ std::advance(iter, index);
+ if (auto element = m_project->getElementDatabase()->getElement(*iter, iter->tableID); element)
+ return std::make_unique(std::move(element));
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return nullptr; //Requested an unknown index
+} //RecordCollection::getCargo
diff --git a/SpeckleConnector/Connector/Record/Collection/RecordCollection.h b/SpeckleConnector/Connector/Record/Collection/RecordCollection.h
new file mode 100644
index 0000000..023a604
--- /dev/null
+++ b/SpeckleConnector/Connector/Record/Collection/RecordCollection.h
@@ -0,0 +1,122 @@
+#ifndef CONNECTOR_RECORD_RECORD_COLLECTiON
+#define CONNECTOR_RECORD_RECORD_COLLECTiON
+
+#include "Speckle/Database/Content/Record.h"
+#include "Speckle/Database/Identity/BIMIndex.h"
+#include "Speckle/Environment/Project.h"
+#include "Speckle/Utility/String.h"
+
+#include
+#include
+
+namespace connector::record {
+
+ class ProjectCollection;
+
+ /*!
+ Container for a collection of elements (and potentially tables of associated attributes) for Speckle commits
+
+ The container only stores element indices - database operations (including serialisation) will lookup records from a specified BIMDatabase on
+ demand.
+
+ This container can used hierarchically, so an collection can be nested within another collection. The current structure is:
+ - Root
+ - Element containers dividing elements by level/storey
+ - Element containers dividing elements by classification
+ - [nested classification leaf nodes)
+ - Associated attributes, e.g. classification table (future)
+
+ Any level in the hierarchy may contain element indices, although this is currently unlikely at the root level (all elements have a level/storey)
+ Each container should be named appropriately, e.g. a level/storey collection should be named to match the level/storey.
+
+ Note that the serialisation is currently implemented for sending only. Receive can be added as required
+ */
+ class RecordCollection : public speckle::database::Record {
+ public:
+
+ // MARK: - Types
+
+ using base = speckle::database::Record;
+
+ // MARK: - Constructors
+
+ /*!
+ Destructor
+ */
+ ~RecordCollection() {}
+
+ // MARK: - Functions (const)
+
+ /*!
+ Get the speckle type identifier
+ @return The speckle type (relevant objects should override as required, but "Base" is still considered a type on its own)
+ */
+ speckle::utility::String getSpeckleType() const override { return "Speckle.Core.Models.Collections.Collection"; }
+ /*!
+ Get the container name
+ @return The container name
+ */
+ const speckle::utility::String& getName() const { return m_name; }
+ /*!
+ Find a child by name
+ @param name The required child name
+ @return A pointer to the requested child (nullptr if not found)
+ */
+ RecordCollection* findChild(const speckle::utility::String& name) 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)
+ */
+ active::serialise::Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override;
+
+ private:
+ friend ProjectCollection;
+
+ // MARK: - Types
+
+ using Indices = std::unordered_set;
+ using Children = std::unordered_map