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; + + /*! + Constructor + @param name The collection name + @param project The source project + */ + RecordCollection(const speckle::utility::String& name, speckle::environment::Project::Shared project); + + /*! + Get a child collection by name (adding if missing) + @param name The child name + @return A pointer to the requested child (nullptr on failure, caller does not take ownership) + */ + RecordCollection* getChild(const speckle::utility::String& name); + /*! + Add an index to the collection + @param index The index to add + @return True if the index was added (false typically means the index already exists) + */ + bool addIndex(const speckle::database::BIMIndex& index); + + ///The source project for the collection + speckle::environment::Project::Shared m_project; + ///The collection name + speckle::utility::String m_name; + ///Child nodes of this collection + Children m_children; + ///Indices of records in this collection + Indices m_indices; + }; + +} + +#endif //CONNECTOR_RECORD_RECORD_COLLECTiON diff --git a/SpeckleConnector/Connector/Record/Model/CardMover.cpp b/SpeckleConnector/Connector/Record/Model/CardMover.cpp index ae4e451..f793fe1 100644 --- a/SpeckleConnector/Connector/Record/Model/CardMover.cpp +++ b/SpeckleConnector/Connector/Record/Model/CardMover.cpp @@ -1,13 +1,9 @@ -/*! -Copyright 2024 Ralph Wessel and Hugh Wessel -Distributed under the MIT License (See accompanying file LICENSE.txt or copy at https://opensource.org/license/mit/) -*/ - #include "Connector/Record/Model/CardMover.h" #include "Connector/Record/Model/ReceiverModelCard.h" #include "Connector/Record/Model/SenderModelCard.h" +using namespace active::serialise; using namespace connector::record; namespace { @@ -37,7 +33,7 @@ namespace { } ///The handler for model card packages -std::shared_ptr CardMover::m_handler = std::make_shared(attributeTag); +std::shared_ptr CardMover::m_handler = std::make_shared(attributeTag); /*-------------------------------------------------------------------- diff --git a/SpeckleConnector/Connector/Record/Model/CardMover.h b/SpeckleConnector/Connector/Record/Model/CardMover.h index 62bfe7c..09ebbb2 100644 --- a/SpeckleConnector/Connector/Record/Model/CardMover.h +++ b/SpeckleConnector/Connector/Record/Model/CardMover.h @@ -6,10 +6,10 @@ namespace connector::record { /*! - Wrapper to box/unbox objects during (de)serialisation, including reading/writing a specified attribute to determine object type + Wrapper to box/unbox model cards during (de)serialisation - Note that a derived class could also define the package handler, allowing the wrapper to be created via a default constructor that is - automatically bound to a set of internally defined object types + Model cards are polymorphic - this class ensures the type information is included when a card is serialised + and the correct object type is constructed on deserialisation */ class CardMover : public active::serialise::Mover { public: diff --git a/SpeckleConnector/Connector/Record/Model/Filter/ArchicadEverythingFilter.h b/SpeckleConnector/Connector/Record/Model/Filter/ArchicadEverythingFilter.h index 19f2af6..b320c9a 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/ArchicadEverythingFilter.h +++ b/SpeckleConnector/Connector/Record/Model/Filter/ArchicadEverythingFilter.h @@ -1,7 +1,7 @@ #ifndef CONNECTOR_RECORD_ARCHICAD_EVERYTHING_FILTER #define CONNECTOR_RECORD_ARCHICAD_EVERYTHING_FILTER -#include "Connector/Database/Identity/RecordID.h" +#include "Speckle/Database/Identity/RecordID.h" #include "Connector/Record/Model/Filter/EverythingSendFilter.h" namespace connector::record { diff --git a/SpeckleConnector/Connector/Record/Model/Filter/ArchicadSelectionFilter.h b/SpeckleConnector/Connector/Record/Model/Filter/ArchicadSelectionFilter.h index 231e3b4..097198f 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/ArchicadSelectionFilter.h +++ b/SpeckleConnector/Connector/Record/Model/Filter/ArchicadSelectionFilter.h @@ -1,7 +1,7 @@ #ifndef CONNECTOR_RECORD_ARCHICAD_SELECTION_FILTER #define CONNECTOR_RECORD_ARCHICAD_SELECTION_FILTER -#include "Connector/Database/Identity/RecordID.h" +#include "Speckle/Database/Identity/RecordID.h" #include "Connector/Record/Model/Filter/DirectSelectionSendFilter.h" namespace connector::record { diff --git a/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.cpp b/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.cpp index 4463b06..b413ef4 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.cpp +++ b/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.cpp @@ -7,7 +7,7 @@ #include using namespace active::serialise; -using namespace connector::database; +using namespace speckle::database; using namespace connector::record; using namespace speckle::utility; @@ -56,7 +56,7 @@ Cargo::Unique DirectSelectionSendFilter::getCargo(const Inventory::Item& item) c using namespace active::serialise; switch (item.index) { case selectedElemID: - return std::make_unique>(m_selectedElements); + return std::make_unique>(m_selectedElements, false, fieldID[selectedElemID].name); default: return nullptr; //Requested an unknown index } diff --git a/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.h b/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.h index b4ae701..f2e64a5 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.h +++ b/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.h @@ -1,7 +1,7 @@ #ifndef CONNECTOR_RECORD_DIRECT_SELECT_SEND_FILTER #define CONNECTOR_RECORD_DIRECT_SELECT_SEND_FILTER -#include "Connector/Database/Identity/RecordID.h" +#include "Speckle/Database/Identity/RecordID.h" #include "Connector/Record/Model/Filter/SendFilter.h" namespace connector::record { @@ -36,7 +36,7 @@ namespace connector::record { Get the filtered element IDs @return The filter elements */ - const database::ElementIDList& getElementIDs() const override { return m_selectedElements; } + const speckle::database::ElementIDList& getElementIDs() const override { return m_selectedElements; } // MARK: - Serialisation @@ -59,7 +59,7 @@ namespace connector::record { private: ///A list of selected element IDs - database::ElementIDList m_selectedElements; + speckle::database::ElementIDList m_selectedElements; }; } diff --git a/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.cpp b/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.cpp index 9dce303..00a49aa 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.cpp +++ b/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.cpp @@ -9,7 +9,7 @@ #include using namespace active::serialise; -using namespace connector::database; +using namespace speckle::database; using namespace connector::record; using namespace speckle::utility; diff --git a/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.h b/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.h index 94e2303..4cd604e 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.h +++ b/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.h @@ -1,7 +1,7 @@ #ifndef CONNECTOR_RECORD_EVERYTHING_SEND_FILTER #define CONNECTOR_RECORD_EVERYTHING_SEND_FILTER -#include "Connector/Database/Identity/RecordID.h" +#include "Speckle/Database/Identity/RecordID.h" #include "Connector/Record/Model/Filter/SendFilter.h" namespace connector::record { @@ -36,13 +36,13 @@ namespace connector::record { Get the filtered element IDs @return The filter elements */ - const database::ElementIDList& getElementIDs() const override { return m_emptyList; } + const speckle::database::ElementIDList& getElementIDs() const override { return m_emptyList; } /*! Determine if the filter has expired because an element in the selection has changed @param changed The list of changed element IDs @return True if the one of the changed elements is in the selection */ - virtual bool checkExpiry(const database::ElementIDList& changed) const override { return true; } + virtual bool checkExpiry(const speckle::database::ElementIDList& changed) const override { return true; } // MARK: - Serialisation @@ -65,7 +65,7 @@ namespace connector::record { private: ///Enables a const empty list to be returned - database::ElementIDList m_emptyList; + speckle::database::ElementIDList m_emptyList; }; } diff --git a/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.cpp b/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.cpp index cd624ce..23e0644 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.cpp +++ b/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.cpp @@ -1,8 +1,3 @@ -/*! -Copyright 2024 Ralph Wessel and Hugh Wessel -Distributed under the MIT License (See accompanying file LICENSE.txt or copy at https://opensource.org/license/mit/) -*/ - #include "Connector/Record/Model/Filter/FilterMover.h" #include "Connector/Record/Model/Filter/ArchicadEverythingFilter.h" diff --git a/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.cpp b/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.cpp index 81e2bf2..8b42cc8 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.cpp +++ b/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.cpp @@ -5,7 +5,7 @@ #include using namespace active::serialise; -using namespace connector::database; +using namespace speckle::database; using namespace connector::record; using namespace speckle::utility; diff --git a/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.h b/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.h index 999d5fd..cedfc56 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.h +++ b/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.h @@ -3,7 +3,7 @@ #include "Active/Serialise/Package/Package.h" #include "Active/Utility/Cloner.h" -#include "Connector/Database/Identity/RecordID.h" +#include "Speckle/Database/Identity/RecordID.h" #include "Speckle/Utility/String.h" namespace connector::record { @@ -59,13 +59,13 @@ namespace connector::record { Get the filtered element IDs @return The filter elements */ - virtual const database::ElementIDList& getElementIDs() const = 0; + virtual const speckle::database::ElementIDList& getElementIDs() const = 0; /*! Determine if the filter has expired because an element in the selection has changed @param changed The list of changed element IDs @return True if the one of the changed elements is in the selection */ - virtual bool checkExpiry(const database::ElementIDList& changed) const; + virtual bool checkExpiry(const speckle::database::ElementIDList& changed) const; // MARK: - Serialisation diff --git a/SpeckleConnector/Connector/Record/Model/ModelCard.h b/SpeckleConnector/Connector/Record/Model/ModelCard.h index a192a8b..ca3eadd 100644 --- a/SpeckleConnector/Connector/Record/Model/ModelCard.h +++ b/SpeckleConnector/Connector/Record/Model/ModelCard.h @@ -11,7 +11,10 @@ namespace connector::record { /*! - A connector send filter + Base class for a Speckle model card + + A model card captures key information about a model submitted to a Speckle server, e.g. the model ID, the target server + and account, and any settings or filters applicable to the host BIM application and open document */ class ModelCard : public speckle::database::Record { public: @@ -19,6 +22,8 @@ namespace connector::record { // MARK: - Types using base = speckle::database::Record; + ///Unique pointer + using Unique = std::unique_ptr; //List of card settings using SettingList = active::container::Vector; @@ -58,18 +63,23 @@ namespace connector::record { */ const speckle::utility::String& getModelID() const { return m_modelID; } /*! - Get the setting type - @return The setting type + Get the ID of the active BIM project + @return The ID of the active BIM project */ const speckle::utility::String& getProjectID() const { return m_projectID; } /*! - Get the setting type - @return The setting type + Get the user account ID + @return The user account ID */ const speckle::utility::String& getAccountID() const { return m_accountID; } /*! - Get the setting type - @return The setting type + Get the user commit message + @return The user commit message + */ + const speckle::utility::String& getMessage() const { return m_message; } + /*! + Get the server URL + @return The server URL */ const speckle::utility::String& getServerURL() const { return m_serverURL; } /*! @@ -106,6 +116,8 @@ namespace connector::record { speckle::database::RecordID m_accountID; ///The server URL speckle::utility::String m_serverURL; + ///The commit message from the user for the card + speckle::utility::String m_message; ///Settings for the model rendering, e.g. level of detail (LoD) SettingList m_settings; ///True if the card has expired diff --git a/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.cpp b/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.cpp index 3877f7c..55bb8c8 100644 --- a/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.cpp +++ b/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.cpp @@ -6,7 +6,7 @@ #include using namespace active::serialise; -using namespace connector::database; +using namespace speckle::database; using namespace connector::record; using namespace speckle::database; using namespace speckle::utility; diff --git a/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.h b/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.h index 95c4217..e13acdb 100644 --- a/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.h +++ b/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.h @@ -1,7 +1,7 @@ #ifndef CONNECTOR_RECORD_RECEIVER_MODEL_CARD #define CONNECTOR_RECORD_RECEIVER_MODEL_CARD -#include "Connector/Database/Identity/RecordID.h" +#include "Speckle/Database/Identity/RecordID.h" #include "Connector/Record/Model/ModelCard.h" namespace connector::record { @@ -37,7 +37,7 @@ namespace connector::record { const speckle::database::RecordID& modelID, const speckle::utility::String& modelName, const speckle::database::RecordID& selectedVersion, const speckle::database::RecordID& latestVersion, const speckle::database::RecordID& accountID, const speckle::utility::String& serverURL, - bool hasDimissedWarning, database::ElementIDList&& bakedObjects, const SettingList& settings) : + bool hasDimissedWarning, speckle::database::ElementIDList&& bakedObjects, const SettingList& settings) : ModelCard{modelID, projectID, accountID, serverURL, settings}, m_projectName{projectName}, m_modelName{modelName}, m_selectedVersionID{selectedVersion}, m_latestVersionID{latestVersion}, m_hasDismissedUpdateWarning{hasDimissedWarning}, m_bakedObjectIDs{bakedObjects} {} @@ -78,7 +78,7 @@ namespace connector::record { Get the IDs of objects accepted in the receive @return The accepted object IDs */ - const database::ElementIDList& getBakedObjectIDs() const { return m_bakedObjectIDs; } + const speckle::database::ElementIDList& getBakedObjectIDs() const { return m_bakedObjectIDs; } // MARK: - Serialisation @@ -111,7 +111,7 @@ namespace connector::record { ///True if the user has already dismissed an alert to update bool m_hasDismissedUpdateWarning = false; ///IDs of objects accepted in the receive - database::ElementIDList m_bakedObjectIDs; + speckle::database::ElementIDList m_bakedObjectIDs; }; } diff --git a/SpeckleConnector/RFIX.WIN/Connector.rc b/SpeckleConnector/RFIX.WIN/Connector.rc index 4a82144..f35153d 100644 --- a/SpeckleConnector/RFIX.WIN/Connector.rc +++ b/SpeckleConnector/RFIX.WIN/Connector.rc @@ -11,5 +11,6 @@ #include "Speckle.grc.rc2" #include "ConnectorFix.grc.rc2" +#include "ConnectorImagesFix.grc.rc2" 1 ICON LOADONCALL MOVEABLE IMPURE ACAP.ico diff --git a/SpeckleConnector/RFIX/ConnectorImagesFix.grc b/SpeckleConnector/RFIX/ConnectorImagesFix.grc new file mode 100644 index 0000000..9756af1 --- /dev/null +++ b/SpeckleConnector/RFIX/ConnectorImagesFix.grc @@ -0,0 +1,10 @@ + +#ifdef macintosh +'GICN' 32500 "Speckle menu icon" { + "32500Mac" +} +#else +'GICN' 32500 "Speckle menu icon" { + "32500Win" +} +#endif diff --git a/SpeckleConnector/RFIX/Images/32500Mac_18x18.svg b/SpeckleConnector/RFIX/Images/32500Mac_18x18.svg new file mode 100644 index 0000000..dd35afa --- /dev/null +++ b/SpeckleConnector/RFIX/Images/32500Mac_18x18.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/SpeckleConnector/RFIX/Images/32500Win_18x18.svg b/SpeckleConnector/RFIX/Images/32500Win_18x18.svg new file mode 100644 index 0000000..bfa9d2b --- /dev/null +++ b/SpeckleConnector/RFIX/Images/32500Win_18x18.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/SpeckleConnector/RINT/Connector.grc b/SpeckleConnector/RINT/Connector.grc index 20de2c7..24aba3e 100644 --- a/SpeckleConnector/RINT/Connector.grc +++ b/SpeckleConnector/RINT/Connector.grc @@ -1,4 +1,13 @@ 'STR#' 32600 "Title strings" { /* [ 1] */ "Speckle Connector" /* [ 2] */ "Connector to share model content with Speckle" +/* [ 3] */ "No level" +} + +'STR#' 32604 "Error strings" { +/* [ 1] */ "No objects were found to convert. Please update your publish filter!" +/* [ 2] */ "The specified model card cannot be found. Try another card or create a new one" +/* [ 3] */ "Please open a project first" +/* [ 4] */ "The specified Speckle account cannot be found. Check that you have logged into your Speckle account with the Speckle Manager" +/* [ 5] */ "Unsupported conversion" } diff --git a/SpeckleConnector/RINT/ConnectorMenu.grc b/SpeckleConnector/RINT/ConnectorMenu.grc index 340795b..6bbad15 100644 --- a/SpeckleConnector/RINT/ConnectorMenu.grc +++ b/SpeckleConnector/RINT/ConnectorMenu.grc @@ -1,5 +1,5 @@ 'STR#' 32500 "Connector Menu" { - /*[ 1]*/ "Speckle Connector" + /*[ 1]*/ "Speckle Connector^E3^EL^ES^ED^EE^EI^EW^ET^32500" } diff --git a/SpeckleConnector/RINT/SpecklePalette.grc b/SpeckleConnector/RINT/SpecklePalette.grc index 2a6a44b..29391a6 100644 --- a/SpeckleConnector/RINT/SpecklePalette.grc +++ b/SpeckleConnector/RINT/SpecklePalette.grc @@ -1,7 +1,7 @@ /* --- Dockable browser palette ----------------------------------------------*/ -'GDLG' 32500 Palette | topCaption | close | grow 0 0 450 150 "Speckle Connector" { -/* [ 1] */ Browser 0 0 450 150 +'GDLG' 32500 Palette | topCaption | close | grow 0 0 350 150 "Speckle Connector" { +/* [ 1] */ Browser 0 0 350 150 } 'DLGH' 32500 DLG_32500_Browser_Palette { diff --git a/SpeckleLib/RINT/Speckle.grc b/SpeckleLib/RINT/Speckle.grc index 552987b..aa8eab1 100644 --- a/SpeckleLib/RINT/Speckle.grc +++ b/SpeckleLib/RINT/Speckle.grc @@ -1,3 +1,5 @@ 'STR#' 32700 "Speckle Title strings" { /* [ 1] */ "Untitled" +/* [ 2] */ "Unknown" +/* [ 3] */ "Converting elements" } diff --git a/SpeckleLib/Speckle/Database/AccountDatabase.cpp b/SpeckleLib/Speckle/Database/AccountDatabase.cpp index b6f2967..eb8fbe6 100644 --- a/SpeckleLib/Speckle/Database/AccountDatabase.cpp +++ b/SpeckleLib/Speckle/Database/AccountDatabase.cpp @@ -81,6 +81,27 @@ AccountDatabase::AccountDatabase(const active::file::Path& path) { AccountDatabase::~AccountDatabase() {} +/*-------------------------------------------------------------------- + Get a specified account. NB: The server URL is provided as a fallback for the search if the specified accountID is not found + + accountID: The account ID (the primary search field) + serverURL: The server URL (a fallback search field if the account ID does not exist) + + return: The requested account (nullptr on failure) + --------------------------------------------------------------------*/ +std::unique_ptr AccountDatabase::getAccount(const String& accountID, const String& serverURL) const { + //First attempt to find a matching account ID + auto matchingAccount = m_store->getObjects([&accountID](const auto& acc) { return acc.getID() == accountID; }); + if (!matchingAccount.empty()) + return matchingAccount.release(matchingAccount.begin()); + //Alternatively seek an account with a matching server URL + matchingAccount = m_store->getObjects([&serverURL](const auto& acc) { return acc.getServerURL() == serverURL; }); + if (!matchingAccount.empty()) + return matchingAccount.release(matchingAccount.begin()); + return nullptr; +} //AccountDatabase::getAccount + + /*-------------------------------------------------------------------- Get all accounts diff --git a/SpeckleLib/Speckle/Database/AccountDatabase.h b/SpeckleLib/Speckle/Database/AccountDatabase.h index 28295e9..7e4f6dd 100644 --- a/SpeckleLib/Speckle/Database/AccountDatabase.h +++ b/SpeckleLib/Speckle/Database/AccountDatabase.h @@ -4,6 +4,10 @@ #include "Active/File/Path.h" #include "Speckle/Record/Credentials/Account.h" +namespace speckle::record::cred { + class Account; +} + namespace speckle::database { /*! @@ -27,6 +31,13 @@ namespace speckle::database { // MARK: - Functions (const) + /*! + Get a specified account. NB: The server URL is provided as a fallback for the search if the specified accountID is not found + @param accountID The account ID (the primary search field) + @param serverURL The server URL (a fallback search field if the account ID does not exist) + @return The requested account (nullptr on failure) + */ + std::unique_ptr getAccount(const speckle::utility::String& accountID, const speckle::utility::String& serverURL) const; /*! Get all accounts @return All the accounts diff --git a/SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp new file mode 100644 index 0000000..2fbf967 --- /dev/null +++ b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp @@ -0,0 +1,155 @@ +#include "Speckle/Database/BIMAttributeDatabase.h" + +#include "Active/Database/Storage/Storage.h" +#include "Active/Serialise/UnboxedTransport.h" +#include "Speckle/Database/Identity/RecordID.h" +#include "Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h" +#include "Speckle/Record/Attribute/Attribute.h" + +#include + +using namespace active::container; +using namespace active::database; +using namespace active::event; +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::record; +using namespace speckle::record::attribute; +using namespace speckle::database; +using namespace speckle::utility; + +namespace speckle::database { + + ///Define other platform engines here as required +#ifdef ARCHICAD + using AttributeDatabaseEngine = ArchicadAttributeDBaseEngine; +#endif + + ///Attribute database engine declaration + class BIMAttributeDatabase::Engine : public AttributeDatabaseEngine { + using base = ArchicadAttributeDBaseEngine; + using base::base; + }; + + ///Attribute database storage declaration + class BIMAttributeDatabase::Store : public Storage { + using base = Storage; + using base::base; + }; + +} + +namespace { + + ///The database storage identifier for attributes + const char* attributeDBaseName = "speckle::database::BIMAttributeDatabase"; + ///The primary model table, e.g. floor plan in Archicad + const char* modelTableName = "Model"; + +} + +/*-------------------------------------------------------------------- + Constructor + --------------------------------------------------------------------*/ +BIMAttributeDatabase::BIMAttributeDatabase() { + m_engine = std::make_shared(attributeDBaseName, + //Schema + DBaseSchema{active::utility::String{attributeDBaseName}, + //Tables + { + //Model attribute table + { + modelTableName, 0, 0, {} //The primary model. Additonal tables could be linked to other drawings/layouts in future + } + } + } + ); + m_store = std::make_shared(m_engine); +} //BIMAttributeDatabase::BIMAttributeDatabase + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +BIMAttributeDatabase::~BIMAttributeDatabase() {} + + +/*-------------------------------------------------------------------- + Get a specified attribute + + attributeID: The ID of the target attribute + + return: The requested attribute (nullptr on failure) + --------------------------------------------------------------------*/ +Attribute::Unique BIMAttributeDatabase::getAttribute(const BIMRecordID& attributeID, std::optional tableID, + std::optional documentID) const { + return m_engine->getObject(attributeID, tableID, documentID); +} //BIMAttributeDatabase::getAttribute + + +/*-------------------------------------------------------------------- + Get all attributes + + return: All the attributes + --------------------------------------------------------------------*/ +Vector BIMAttributeDatabase::getAttributes() const { + return m_store->getObjects(); +} //BIMAttributeDatabase::getAttributes + + +/*-------------------------------------------------------------------- + Write an attribute to storage + + attribute: The attribute to write + --------------------------------------------------------------------*/ +void BIMAttributeDatabase::write(const Attribute& attribute) const { + m_store->write(attribute); +} //BIMAttributeDatabase::write + + +/*-------------------------------------------------------------------- + Erase an attribute + + attributeID: The ID of the attribute to erase + --------------------------------------------------------------------*/ +void BIMAttributeDatabase::erase(const Guid& attributeID) const { + m_store->erase(attributeID); +} //BIMAttributeDatabase::erase + + +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Get attribute data direct from the AC API. For internal use - avoid direct use + + link: A link to the required attribute + + return: The AC API attribute data + --------------------------------------------------------------------*/ +std::optional BIMAttributeDatabase::getAPIData(const BIMLink& link) const { + return m_engine->getAPIData(link); +} //BIMAttributeDatabase::getAPIData + + +/*-------------------------------------------------------------------- + Get storey data direct from the AC API. For internal use - avoid direct use + + link: A link to the required storey + + return: The AC API storey data + --------------------------------------------------------------------*/ +std::optional BIMAttributeDatabase::getAPIStorey(const BIMLink& link) const { + return m_engine->getAPIStorey(link); +} //BIMAttributeDatabase::getAPIData + + +/*-------------------------------------------------------------------- + Get the ID of a storey from a specified index + + index: The storey index + + return: The storey ID (nullopt on failure) + --------------------------------------------------------------------*/ +std::optional BIMAttributeDatabase::getStoreyID(short index) const { + return m_engine->getStoreyID(index); +} //BIMAttributeDatabase::getStoreyID +#endif diff --git a/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h new file mode 100644 index 0000000..17fe657 --- /dev/null +++ b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h @@ -0,0 +1,96 @@ +#ifndef CONNECTOR_DATABASE_BIM_ATTRIBUTE_DATABASE +#define CONNECTOR_DATABASE_BIM_ATTRIBUTE_DATABASE + +#include "Speckle/Database/Identity/BIMLink.h" +#include "Speckle/Record/Attribute/Attribute.h" +#include "Speckle/Utility/Guid.h" + +namespace active::event { + class Subscriber; +} + +namespace speckle::database { + + /*! + Database of model attributes relating to a specific project + */ + class BIMAttributeDatabase { + public: + + // MARK: - Constructors + + /*! + Constructor + */ + BIMAttributeDatabase(); + BIMAttributeDatabase(const BIMAttributeDatabase&) = delete; + /*! + Destructor + */ + ~BIMAttributeDatabase(); + + // MARK: - Functions (const) + + /*! + Get a specified attribute + @param attributeID The ID of the target attribute + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (when the object is bound to a specific document) + @return The requested attribute (nullptr on failure) + */ + record::attribute::Attribute::Unique getAttribute(const BIMRecordID& attributeID, std::optional tableID = std::nullopt, + std::optional documentID = std::nullopt) const; + /*! + Get a specified attribute + @param link A link to the target attribute + @return The requested attribute (nullptr on failure) + */ + record::attribute::Attribute::Unique getAttribute(const BIMLink& link) const { return getAttribute(link, link.tableID, link.docID); } + /*! + Get all model attributes + @return All the attributes + */ + active::container::Vector getAttributes() const; + /*! + Write an attribute to storage + @param attribute The attribute to write + */ + void write(const record::attribute::Attribute& attribute) const; + /*! + Erase an attribute + @param attributeID The ID of the attribute to erase + */ + void erase(const speckle::utility::Guid& attributeID) const; + +#ifdef ARCHICAD + /*! + Get attribute data direct from the AC API. For internal use - avoid direct use + @param link A link to the required attribute + @return The AC API attribute data + */ + std::optional getAPIData(const BIMLink& link) const; + /*! + Get storey data direct from the AC API. For internal use - avoid direct use + @param link A link to the required storey + @return The AC API storey data + */ + std::optional getAPIStorey(const BIMLink& link) const; + /*! + Get the ID of a storey from a specified index + @param index The storey index + @return The storey ID (nullopt on failure) + */ + std::optional getStoreyID(short index) const; +#endif + + private: + class Engine; + class Store; + ///Model attribute database storage + std::shared_ptr m_engine; + std::shared_ptr m_store; + }; + +} + +#endif //CONNECTOR_DATABASE_BIM_ATTRIBUTE_DATABASE diff --git a/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp b/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp new file mode 100644 index 0000000..9837c54 --- /dev/null +++ b/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp @@ -0,0 +1,227 @@ +#include "Speckle/Database/BIMElementDatabase.h" + +#include "Active/Database/Storage/Storage.h" +#include "Active/Serialise/UnboxedTransport.h" +#include "Speckle/Database/Identity/RecordID.h" +#include "Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h" +#include "Speckle/Record/Element/Element.h" +#include "Speckle/Record/Element/Memo.h" + +#include + +using namespace active::container; +using namespace active::database; +using namespace active::event; +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::record; +using namespace speckle::record::element; +using namespace speckle::database; +using namespace speckle::utility; + +namespace speckle::database { + + ///Define other platform engines here as required +#ifdef ARCHICAD + using ElementDatabaseEngine = ArchicadElementDBaseEngine; +#endif + + ///Element database engine declaration + class BIMElementDatabase::Engine : public ElementDatabaseEngine { + using base = ArchicadElementDBaseEngine; + using base::base; + }; + + ///Element database storage declaration + class BIMElementDatabase::Store : public Storage { + using base = Storage; + using base::base; + }; + +} + +namespace { + + ///The database storage identifier for elements + const char* elementDBaseName = "speckle::database::BIMElementDatabase"; + ///The primary model table, e.g. floor plan in Archicad + const char* modelTableName = "Model"; + +} + +/*-------------------------------------------------------------------- + Constructor + --------------------------------------------------------------------*/ +BIMElementDatabase::BIMElementDatabase() { + m_engine = std::make_shared(elementDBaseName, + //Schema + DBaseSchema{active::utility::String{elementDBaseName}, + //Tables + { + //Model element table + { + modelTableName, 0, 0, {} //The primary model. Additonal tables could be linked to other drawings/layouts in future + } + } + } + ); + m_store = std::make_shared(m_engine); +} //BIMElementDatabase::BIMElementDatabase + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +BIMElementDatabase::~BIMElementDatabase() {} + + +/*-------------------------------------------------------------------- + Get the available element tables + + targetType: An optional filtr for table type to retrieve, e.g. get all sections (nullopt = all table types) + + return: A list of available tables + --------------------------------------------------------------------*/ +BIMRecordIDList BIMElementDatabase::getTables(std::optional targetType) const { + return m_engine->getTables(targetType); +} //BIMElementDatabase::getTables + + +/*-------------------------------------------------------------------- + Get the default dbase table + + return: The default dbase table (nullopt if no table is available) + --------------------------------------------------------------------*/ +std::optional BIMElementDatabase::getDefaultTable() const { + return m_engine->getDefaultTable(); +} //BIMElementDatabase::getDefaultTable + + +/*-------------------------------------------------------------------- + Set the default dbase table + + tableID: The new default dbase table + --------------------------------------------------------------------*/ +void BIMElementDatabase::setDefaultTable(const BIMRecordID& tableID) const { + m_engine->setDefaultTable(tableID); +} //BIMElementDatabase::setDefaultTable + + +/*-------------------------------------------------------------------- + Bring the view of this database to the front (i.e. so the user sees it) + + tableID: The ID of the table to bring to the front + --------------------------------------------------------------------*/ +void BIMElementDatabase::bringViewToFront(BIMRecordID tableID) const { + m_engine->bringViewToFront(tableID); +} //BIMElementDatabase::bringViewToFront + + +/*-------------------------------------------------------------------- + Get the current user element selection + + return: A list of selected element IDs + --------------------------------------------------------------------*/ +BIMLinkList BIMElementDatabase::getSelection() const { + return m_engine->getSelection(); +} //BIMElementDatabase::getSelection + + +/*-------------------------------------------------------------------- + Set the element selection + --------------------------------------------------------------------*/ +void BIMElementDatabase::setSelection(const BIMLinkList& elementIDs) const { + m_engine->setSelection(elementIDs); +} //BIMElementDatabase::setSelection + + +/*-------------------------------------------------------------------- + Clear the element selection + --------------------------------------------------------------------*/ +void BIMElementDatabase::clearSelection() const { + m_engine->clearSelection(); +} //BIMElementDatabase::clearSelection + + +/*-------------------------------------------------------------------- + Find a filtered list of objects + + filter: The object filter (nullptr = find all objects) + tableID: Optional table ID (defaults to the first table) + documentID: Optional document ID (filter for this document only - nullopt = all objects) + + return: A list containing IDs of found elements (empty if none found) + --------------------------------------------------------------------*/ +BIMRecordIDList BIMElementDatabase::findElements(const Filter& filter, std::optional tableID, + std::optional documentID) const { + return m_engine->findObjects(filter, tableID, documentID); +} //BIMElementDatabase::findElements + + +/*-------------------------------------------------------------------- + Get a specified element + + elementID: The ID of the target element + tableID: Optional table ID (defaults to the first table) + documentID: Optional document ID (filter for this document only - nullopt = all objects) + + return: The requested element (nullptr on failure) + --------------------------------------------------------------------*/ +Element::Unique BIMElementDatabase::getElement(const BIMRecordID& elementID, std::optional tableID, + std::optional documentID) const { + return m_engine->getObject(elementID, tableID, documentID); +} //BIMElementDatabase::getElement + + +/*-------------------------------------------------------------------- + Get all elements + + tableID: Optional table ID (defaults to the first table) + documentID: Optional document ID (filter for this document only - nullopt = all objects) + + return: All the elements + --------------------------------------------------------------------*/ +Vector BIMElementDatabase::getElements(std::optional tableID, + std::optional documentID) const { + return m_store->getObjects(tableID, documentID); +} //BIMElementDatabase::getElements + + +/*-------------------------------------------------------------------- + Get memo memo (supplementary) data for a specified element + + elementID: The of the source element + filter: Filter for the required supplementary data + + return: The requested element memo data (nullptr on failure) + --------------------------------------------------------------------*/ +Memo::Unique BIMElementDatabase::getMemo(const BIMRecordID& elementID, Part::filter_bits filter) const { + //NB: The filter bits are passed as the source document ID + auto result = m_engine->getObject(elementID, ArchicadElementDBaseEngine::memoTable, Guid::fromInt(filter)); + if (auto memo = dynamic_cast(result.get()); memo != nullptr) { + result.release(); + return Memo::Unique{memo}; + } + return nullptr; +} //BIMElementDatabase::getMemo + + +/*-------------------------------------------------------------------- + Write an element to storage + + element: The element to write + --------------------------------------------------------------------*/ +void BIMElementDatabase::write(const Element& element) const { + m_store->write(element); +} //BIMElementDatabase::write + + +/*-------------------------------------------------------------------- + Erase an element + + elementID: The ID of the element to erase + --------------------------------------------------------------------*/ +void BIMElementDatabase::erase(const Guid& elementID) const { + m_store->erase(elementID); +} //BIMElementDatabase::erase diff --git a/SpeckleLib/Speckle/Database/BIMElementDatabase.h b/SpeckleLib/Speckle/Database/BIMElementDatabase.h new file mode 100644 index 0000000..000612e --- /dev/null +++ b/SpeckleLib/Speckle/Database/BIMElementDatabase.h @@ -0,0 +1,134 @@ +#ifndef CONNECTOR_DATABASE_BIM_ELEMENT_DATABASE +#define CONNECTOR_DATABASE_BIM_ELEMENT_DATABASE + +#include "Speckle/Database/Identity/BIMLink.h" +#include "Speckle/Database/Storage/Element/ElementStorage.h" +#include "Speckle/Record/Element/Element.h" +#include "Speckle/Record/Element/Interface/Part.h" +#include "Speckle/Utility/Guid.h" + +namespace active::event { + class Subscriber; +} + +namespace speckle::record::element { + class Memo; +} + +namespace speckle::database { + + /*! + Database of model elements relating to a specific project + */ + class BIMElementDatabase : public ElementStorage { + public: + + // MARK: - Constructors + + /*! + Constructor + */ + BIMElementDatabase(); + BIMElementDatabase(const BIMElementDatabase&) = delete; + /*! + Destructor + */ + ~BIMElementDatabase(); + + // MARK: - Functions (const) + + /*! + Get the available element tables + @param targetType An optional filtr for table type to retrieve, e.g. get all sections (nullopt = all table types) + @return A set of available tables + */ + BIMRecordIDList getTables(std::optional targetType) const; + /*! + Get the default dbase table + @return The default dbase table (nullopt if no table is available) + */ + std::optional getDefaultTable() const; + /*! + Set the default dbase table + @param tableID The new default dbase table + */ + void setDefaultTable(const BIMRecordID& tableID) const; + /*! + Bring the view of this database to the front (i.e. so the user sees it) + @param tableID The ID of the table to bring to the front + */ + void bringViewToFront(BIMRecordID tableID) const; + /*! + Get the current user element selection + @return A list of selected element IDs + */ + BIMLinkList getSelection() const; + /*! + Set the element selection + */ + void setSelection(const BIMLinkList& elementIDs) const; + /*! + Clear the element selection + */ + void clearSelection() const; + /*! + Find a filtered list of objects + @param filter The object filter (nullptr = find all objects) + @param tableID Optional table ID (defaults to the first table) + @param documentID Optional document ID (filter for this document only - nullopt = all objects) + @return A list containing IDs of found elements (empty if none found) + */ + BIMRecordIDList findElements(const Filter& filter = nullptr, std::optional tableID = std::nullopt, + std::optional documentID = std::nullopt) const; + /*! + Get a specified element + @param elementID The ID of the target element + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (when the object is bound to a specific document) + @return The requested element (nullptr on failure) + */ + std::unique_ptr getElement(const BIMRecordID& elementID, std::optional tableID = std::nullopt, + std::optional documentID = std::nullopt) const; + /*! + Get a specified element + @param link A link to the target element + @return The requested element (nullptr on failure) + */ + std::unique_ptr getElement(const BIMLink& link) const { return getElement(link, link.tableID, link.docID); } + /*! + Get all model elements + @param tableID Optional table ID (defaults to the first table) + @param documentID Optional document ID (filter for this document only - nullopt = all objects) + @return All the elements + */ + active::container::Vector getElements(std::optional tableID = std::nullopt, + std::optional documentID = std::nullopt) const; + /*! + Get memo memo (supplementary) data for a specified element + @param elementID The of the source element + @param filter Filter for the required supplementary data + @return The requested element memo data (nullptr on failure) + */ + std::unique_ptr getMemo(const BIMRecordID& elementID, record::element::Part::filter_bits filter) const; + /*! + Write an element to storage + @param element The element to write + */ + void write(const record::element::Element& element) const; + /*! + Erase an element + @param elementID The ID of the element to erase + */ + void erase(const speckle::utility::Guid& elementID) const; + + private: + class Engine; + class Store; + ///Model element database storage + std::shared_ptr m_engine; + std::shared_ptr m_store; + }; + +} + +#endif //CONNECTOR_DATABASE_BIM_ELEMENT_DATABASE diff --git a/SpeckleLib/Speckle/Database/BIMGroupDatabase.cpp b/SpeckleLib/Speckle/Database/BIMGroupDatabase.cpp new file mode 100644 index 0000000..2b653a5 --- /dev/null +++ b/SpeckleLib/Speckle/Database/BIMGroupDatabase.cpp @@ -0,0 +1,129 @@ +#include "Speckle/Database/BIMGroupDatabase.h" + +#include "Active/Database/Storage/Storage.h" +#include "Active/Serialise/UnboxedTransport.h" +#include "Speckle/Database/Identity/RecordID.h" +#include "Speckle/Database/Storage/ArchicadDBase/Property/ArchicadGroupDBaseEngine.h" +#include "Speckle/Record/Property/Setting.h" + +#include + +using namespace active::container; +using namespace active::database; +using namespace active::event; +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::record; +using namespace speckle::record::property; +using namespace speckle::database; +using namespace speckle::utility; + +namespace speckle::database { + + ///Define other platform engines here as required +#ifdef ARCHICAD + using GroupDatabaseEngine = ArchicadGroupDBaseEngine; +#endif + + ///Group database engine declaration + class BIMGroupDatabase::Engine : public GroupDatabaseEngine { + using base = ArchicadGroupDBaseEngine; + using base::base; + }; + + ///Group database storage declaration + class BIMGroupDatabase::Store : public Storage { + using base = Storage; + using base::base; + }; + +} + +namespace { + + ///The database storage identifier for groups + const char* groupDBaseName = "speckle::database::BIMGroupDatabase"; + ///The primary groups table + const char* groupTableName = "Groups"; + +} + +/*-------------------------------------------------------------------- + Constructor + --------------------------------------------------------------------*/ +BIMGroupDatabase::BIMGroupDatabase() { + m_engine = std::make_shared(groupDBaseName, + //Schema + DBaseSchema{active::utility::String{groupDBaseName}, + //Tables + { + //Model group table + { + groupTableName, 0, 0, {} + } + } + } + ); + m_store = std::make_shared(m_engine); +} //BIMGroupDatabase::BIMGroupDatabase + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +BIMGroupDatabase::~BIMGroupDatabase() {} + + +/*-------------------------------------------------------------------- + Get a specified group + + groupID: The ID of the target group + + return: The requested group (nullptr on failure) + --------------------------------------------------------------------*/ +Group::Unique BIMGroupDatabase::getGroup(const BIMRecordID& groupID, std::optional tableID, + std::optional documentID) const { + return m_engine->getObject(groupID, tableID, documentID); +} //BIMGroupDatabase::getGroup + + +/*-------------------------------------------------------------------- + Get a specified group + + link: A link to the target group + + return: The requested group (nullptr on failure) + --------------------------------------------------------------------*/ +Group::Unique BIMGroupDatabase::getGroup(const BIMLink& link) const { + return getGroup(link, link.tableID, link.docID); +} //BIMGroupDatabase::getGroup + + +/*-------------------------------------------------------------------- + Get all groups + + return: All the groups + --------------------------------------------------------------------*/ +Vector BIMGroupDatabase::getGroups() const { + return m_store->getObjects(); +} //BIMGroupDatabase::getGroups + + +/*-------------------------------------------------------------------- + Write an group to storage + + group: The group to write + --------------------------------------------------------------------*/ +void BIMGroupDatabase::write(const Group& group) const { + m_store->write(group); +} //BIMGroupDatabase::write + + +/*-------------------------------------------------------------------- + Erase an group + + groupID: The ID of the group to erase + --------------------------------------------------------------------*/ +void BIMGroupDatabase::erase(const Guid& groupID) const { + m_store->erase(groupID); +} //BIMGroupDatabase::erase diff --git a/SpeckleLib/Speckle/Database/BIMGroupDatabase.h b/SpeckleLib/Speckle/Database/BIMGroupDatabase.h new file mode 100644 index 0000000..df18e4f --- /dev/null +++ b/SpeckleLib/Speckle/Database/BIMGroupDatabase.h @@ -0,0 +1,77 @@ +#ifndef CONNECTOR_DATABASE_BIM_GROUP_DATABASE +#define CONNECTOR_DATABASE_BIM_GROUP_DATABASE + +#include "Speckle/Database/Identity/BIMLink.h" +#include "Speckle/Record/Property/Group.h" +#include "Speckle/Utility/Guid.h" + +namespace active::event { + class Subscriber; +} + +namespace speckle::database { + + /*! + Database of group templates relating to a specific project + + Note that this database manages just the group templates, not the values. Group values are attached to elements + */ + class BIMGroupDatabase { + public: + + // MARK: - Constructors + + /*! + Constructor + */ + BIMGroupDatabase(); + BIMGroupDatabase(const BIMGroupDatabase&) = delete; + /*! + Destructor + */ + ~BIMGroupDatabase(); + + // MARK: - Functions (const) + + /*! + Get a specified group + @param groupID The ID of the target group + @param tableID Optional table ID (defaults to the floor plan) + @param documentID Optional document ID (when the object is bound to a specific document) + @return The requested group (nullptr on failure) + */ + record::property::Group::Unique getGroup(const BIMRecordID& groupID, std::optional tableID = std::nullopt, + std::optional documentID = std::nullopt) const; + /*! + Get a specified group + @param link A link to the target group + @return The requested group (nullptr on failure) + */ + record::property::Group::Unique getGroup(const BIMLink& link) const; + /*! + Get all model groups + @return All the groups + */ + active::container::Vector getGroups() const; + /*! + Write an group to storage + @param group The group to write + */ + void write(const record::property::Group& group) const; + /*! + Erase an group + @param groupID The ID of the group to erase + */ + void erase(const speckle::utility::Guid& groupID) const; + + private: + class Engine; + class Store; + ///Model group database storage + std::shared_ptr m_engine; + std::shared_ptr m_store; + }; + +} + +#endif //CONNECTOR_DATABASE_BIM_GROUP_DATABASE diff --git a/SpeckleLib/Speckle/Database/BIMPropertyDatabase.cpp b/SpeckleLib/Speckle/Database/BIMPropertyDatabase.cpp new file mode 100644 index 0000000..5456f62 --- /dev/null +++ b/SpeckleLib/Speckle/Database/BIMPropertyDatabase.cpp @@ -0,0 +1,141 @@ +#include "Speckle/Database/BIMPropertyDatabase.h" + +#include "Active/Database/Storage/Storage.h" +#include "Active/Serialise/UnboxedTransport.h" +#include "Speckle/Database/Identity/RecordID.h" +#include "Speckle/Database/Storage/ArchicadDBase/Property/ArchicadPropertyDBaseEngine.h" +#include "Speckle/Record/Property/Setting.h" + +#include + +using namespace active::container; +using namespace active::database; +using namespace active::event; +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::record; +using namespace speckle::record::property; +using namespace speckle::database; +using namespace speckle::utility; + +namespace speckle::database { + + ///Define other platform engines here as required +#ifdef ARCHICAD + using PropertyDatabaseEngine = ArchicadPropertyDBaseEngine; +#endif + + ///Property database engine declaration + class BIMPropertyDatabase::Engine : public PropertyDatabaseEngine { + using base = ArchicadPropertyDBaseEngine; + using base::base; + }; + + ///Property database storage declaration + class BIMPropertyDatabase::Store : public Storage { + using base = Storage; + using base::base; + }; + +} + +namespace { + + ///The database storage identifier for properties + const char* propertyDBaseName = "speckle::database::BIMPropertyDatabase"; + ///The primary properties table + const char* propertyTableName = "Properties"; + +} + +/*-------------------------------------------------------------------- + Constructor + --------------------------------------------------------------------*/ +BIMPropertyDatabase::BIMPropertyDatabase() { + m_engine = std::make_shared(propertyDBaseName, + //Schema + DBaseSchema{active::utility::String{propertyDBaseName}, + //Tables + { + //Model property table + { + propertyTableName, 0, 0, {} + } + } + } + ); + m_store = std::make_shared(m_engine); +} //BIMPropertyDatabase::BIMPropertyDatabase + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +BIMPropertyDatabase::~BIMPropertyDatabase() {} + + +/*-------------------------------------------------------------------- + Get a specified property + + propertyID: The ID of the target property + + return: The requested property (nullptr on failure) + --------------------------------------------------------------------*/ +Template::Unique BIMPropertyDatabase::getProperty(const BIMRecordID& propertyID, std::optional tableID, + std::optional documentID) const { + return m_engine->getObject(propertyID, tableID, documentID); +} //BIMPropertyDatabase::getProperty + + +/*-------------------------------------------------------------------- + Get a specified property + + link: A link to the target property + + return: The requested property (nullptr on failure) + --------------------------------------------------------------------*/ +Template::Unique BIMPropertyDatabase::getProperty(const BIMLink& link) const { + return getProperty(link, link.tableID, link.docID); +} //BIMPropertyDatabase::getProperty + + +/*-------------------------------------------------------------------- + Get all properties + + return: All the properties + --------------------------------------------------------------------*/ +Vector