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