diff --git a/SpeckleConnector/Connector.vcxproj b/SpeckleConnector/Connector.vcxproj index 96f0cbf..33d1e1d 100644 --- a/SpeckleConnector/Connector.vcxproj +++ b/SpeckleConnector/Connector.vcxproj @@ -175,6 +175,8 @@ + + @@ -206,6 +208,7 @@ + @@ -234,6 +237,8 @@ + + @@ -268,6 +273,7 @@ + diff --git a/SpeckleConnector/Connector.vcxproj.filters b/SpeckleConnector/Connector.vcxproj.filters index 2e2ca28..bf46e71 100644 --- a/SpeckleConnector/Connector.vcxproj.filters +++ b/SpeckleConnector/Connector.vcxproj.filters @@ -74,6 +74,12 @@ {1d9a10c3-cac6-4b15-afb9-f117b99b3a24} + + {896b7b9b-61d8-46e7-8432-cfbdab4918fb} + + + {f9330e8f-8242-4605-b25c-b1ba24451825} + @@ -98,9 +104,6 @@ - - Connector - Connector\Interface @@ -260,6 +263,18 @@ Connector\Interface\Browser\Bridge\Config + + Connector\Interface\Browser\Bridge\Receive + + + Connector\Interface\Browser\Bridge\Receive + + + Connector\Tool + + + Connector + @@ -445,5 +460,14 @@ Connector\Interface\Browser\Bridge\Config + + Connector\Interface\Browser\Bridge\Receive + + + Connector\Interface\Browser\Bridge\Receive + + + Connector\Tool + \ No newline at end of file diff --git a/SpeckleConnector/Connector.xcodeproj/project.pbxproj b/SpeckleConnector/Connector.xcodeproj/project.pbxproj index ee9d1a3..9236dd6 100644 --- a/SpeckleConnector/Connector.xcodeproj/project.pbxproj +++ b/SpeckleConnector/Connector.xcodeproj/project.pbxproj @@ -726,6 +726,18 @@ 21CE9B7B2CE627640076522F /* GSProfiler.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21CE9AEE2CE627640076522F /* GSProfiler.framework */; }; 21CE9B7C2CE627640076522F /* VBAttributeList.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21CE9AEF2CE627640076522F /* VBAttributeList.framework */; }; 21CE9B7D2CE627640076522F /* Property.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21CE9AF02CE627640076522F /* Property.framework */; }; + 21CE9B832CE69A230076522F /* Receive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21CE9B7E2CE69A230076522F /* Receive.cpp */; }; + 21CE9B842CE69A230076522F /* Receive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21CE9B7E2CE69A230076522F /* Receive.cpp */; }; + 21CE9B852CE69A230076522F /* Receive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21CE9B7E2CE69A230076522F /* Receive.cpp */; }; + 21CE9B862CE69A230076522F /* Receive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21CE9B7E2CE69A230076522F /* Receive.cpp */; }; + 21CE9B872CE69A230076522F /* ReceiveBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21CE9B802CE69A230076522F /* ReceiveBridge.cpp */; }; + 21CE9B882CE69A230076522F /* ReceiveBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21CE9B802CE69A230076522F /* ReceiveBridge.cpp */; }; + 21CE9B892CE69A230076522F /* ReceiveBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21CE9B802CE69A230076522F /* ReceiveBridge.cpp */; }; + 21CE9B8A2CE69A230076522F /* ReceiveBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21CE9B802CE69A230076522F /* ReceiveBridge.cpp */; }; + 21CE9B8E2CE75CFC0076522F /* ElementHighlighter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21CE9B8B2CE75CFC0076522F /* ElementHighlighter.cpp */; }; + 21CE9B8F2CE75CFC0076522F /* ElementHighlighter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21CE9B8B2CE75CFC0076522F /* ElementHighlighter.cpp */; }; + 21CE9B902CE75CFC0076522F /* ElementHighlighter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21CE9B8B2CE75CFC0076522F /* ElementHighlighter.cpp */; }; + 21CE9B912CE75CFC0076522F /* ElementHighlighter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21CE9B8B2CE75CFC0076522F /* ElementHighlighter.cpp */; }; 21D0BD602C89BFEA0077E104 /* SendBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BD5B2C89BFEA0077E104 /* SendBridge.cpp */; }; 21D0BD672C89D7410077E104 /* AccountTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BD642C89D7400077E104 /* AccountTests.cpp */; }; 21D0BD6A2C8A0DB40077E104 /* GetIsDevMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21D0BD682C8A0DB40077E104 /* GetIsDevMode.cpp */; }; @@ -1445,6 +1457,12 @@ 21CE9AEE2CE627640076522F /* GSProfiler.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GSProfiler.framework; path = "../../Archicad 26/Support/Frameworks/GSProfiler.framework"; sourceTree = ""; }; 21CE9AEF2CE627640076522F /* VBAttributeList.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VBAttributeList.framework; path = "../../Archicad 26/Support/Frameworks/VBAttributeList.framework"; sourceTree = ""; }; 21CE9AF02CE627640076522F /* Property.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Property.framework; path = "../../Archicad 26/Support/Frameworks/Property.framework"; sourceTree = ""; }; + 21CE9B7E2CE69A230076522F /* Receive.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Receive.cpp; sourceTree = ""; }; + 21CE9B7F2CE69A230076522F /* Receive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Receive.h; sourceTree = ""; }; + 21CE9B802CE69A230076522F /* ReceiveBridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReceiveBridge.cpp; sourceTree = ""; }; + 21CE9B812CE69A230076522F /* ReceiveBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReceiveBridge.h; sourceTree = ""; }; + 21CE9B8B2CE75CFC0076522F /* ElementHighlighter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ElementHighlighter.cpp; sourceTree = ""; }; + 21CE9B8C2CE75CFC0076522F /* ElementHighlighter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementHighlighter.h; sourceTree = ""; }; 21D0BD5B2C89BFEA0077E104 /* SendBridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendBridge.cpp; sourceTree = ""; }; 21D0BD5C2C89BFEA0077E104 /* SendBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendBridge.h; sourceTree = ""; }; 21D0BD642C89D7400077E104 /* AccountTests.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = AccountTests.cpp; sourceTree = ""; }; @@ -2785,6 +2803,26 @@ name = Archicad28; sourceTree = ""; }; + 21CE9B822CE69A230076522F /* Receive */ = { + isa = PBXGroup; + children = ( + 21CE9B7E2CE69A230076522F /* Receive.cpp */, + 21CE9B7F2CE69A230076522F /* Receive.h */, + 21CE9B802CE69A230076522F /* ReceiveBridge.cpp */, + 21CE9B812CE69A230076522F /* ReceiveBridge.h */, + ); + path = Receive; + sourceTree = ""; + }; + 21CE9B8D2CE75CFC0076522F /* Tool */ = { + isa = PBXGroup; + children = ( + 21CE9B8B2CE75CFC0076522F /* ElementHighlighter.cpp */, + 21CE9B8C2CE75CFC0076522F /* ElementHighlighter.h */, + ); + path = Tool; + sourceTree = ""; + }; 21D0BD5D2C89BFEA0077E104 /* Send */ = { isa = PBXGroup; children = ( @@ -2907,6 +2945,7 @@ 21F69F092C677BC0008B6A06 /* Event */, 21F69F0E2C677BC0008B6A06 /* Interface */, 21D0BDD82C9387E60077E104 /* Record */, + 21CE9B8D2CE75CFC0076522F /* Tool */, 21B67CBA2C774C6500FD64FC /* Version.h */, ); path = Connector; @@ -2929,6 +2968,7 @@ 21F69F852C70D2C4008B6A06 /* Account */, 21B67CAB2C77329800FD64FC /* Base */, 21F69FB82C762EF0008B6A06 /* Config */, + 21CE9B822CE69A230076522F /* Receive */, 21D0BD5D2C89BFEA0077E104 /* Send */, 21A890B92CC15C540087E732 /* Selection */, 21B67CD82C78C83800FD64FC /* Test */, @@ -3098,7 +3138,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1530; + LastUpgradeCheck = 1610; TargetAttributes = { 219F30342C768F0A009834E9 = { CreatedOnToolsVersion = 15.3; @@ -3376,6 +3416,7 @@ 2199BB7E2CDD3FA800A4BEEC /* HighlightObjects.cpp in Sources */, 21D0BD602C89BFEA0077E104 /* SendBridge.cpp in Sources */, 21D0BD972C8F13F30077E104 /* GetSendFilters.cpp in Sources */, + 21CE9B882CE69A230076522F /* ReceiveBridge.cpp in Sources */, 21B67CAC2C77329800FD64FC /* BaseBridge.cpp in Sources */, 2192460D2CA3469D00CF5703 /* ProjectCollection.cpp in Sources */, 21D0BD6A2C8A0DB40077E104 /* GetIsDevMode.cpp in Sources */, @@ -3402,7 +3443,9 @@ 2199BB552CDA4B1700A4BEEC /* ConnectorProject.cpp in Sources */, 21AEF9EF2CAB5720000B8681 /* SendObject.cpp in Sources */, 21384BCD2CD2EE7400D4602B /* OpenUrl.cpp in Sources */, + 21CE9B842CE69A230076522F /* Receive.cpp in Sources */, 21B67CDC2C78C88000FD64FC /* SayHi.cpp in Sources */, + 21CE9B8F2CE75CFC0076522F /* ElementHighlighter.cpp in Sources */, 215F082E2C94C5C000CD343B /* FilterMover.cpp in Sources */, 21F69F122C677BC0008B6A06 /* ConnectorMenu.cpp in Sources */, 21F69F8D2C70D7EE008B6A06 /* GetAccounts.cpp in Sources */, @@ -3446,6 +3489,7 @@ 21BD79952CE23E4D00526AD1 /* HighlightObjects.cpp in Sources */, 21BD79962CE23E4D00526AD1 /* SendBridge.cpp in Sources */, 21BD79972CE23E4D00526AD1 /* GetSendFilters.cpp in Sources */, + 21CE9B8A2CE69A230076522F /* ReceiveBridge.cpp in Sources */, 21BD79982CE23E4D00526AD1 /* BaseBridge.cpp in Sources */, 21BD79992CE23E4D00526AD1 /* ProjectCollection.cpp in Sources */, 21BD799A2CE23E4D00526AD1 /* GetIsDevMode.cpp in Sources */, @@ -3472,7 +3516,9 @@ 21BD79AF2CE23E4D00526AD1 /* ConnectorProject.cpp in Sources */, 21BD79B02CE23E4D00526AD1 /* SendObject.cpp in Sources */, 21BD79B12CE23E4D00526AD1 /* OpenUrl.cpp in Sources */, + 21CE9B862CE69A230076522F /* Receive.cpp in Sources */, 21BD79B22CE23E4D00526AD1 /* SayHi.cpp in Sources */, + 21CE9B912CE75CFC0076522F /* ElementHighlighter.cpp in Sources */, 21BD79B32CE23E4D00526AD1 /* FilterMover.cpp in Sources */, 21BD79B42CE23E4D00526AD1 /* ConnectorMenu.cpp in Sources */, 21BD79B52CE23E4D00526AD1 /* GetAccounts.cpp in Sources */, @@ -3507,6 +3553,7 @@ 21CE8AA72CE4F3370076522F /* HighlightObjects.cpp in Sources */, 21CE8AA82CE4F3370076522F /* SendBridge.cpp in Sources */, 21CE8AA92CE4F3370076522F /* GetSendFilters.cpp in Sources */, + 21CE9B892CE69A230076522F /* ReceiveBridge.cpp in Sources */, 21CE8AAA2CE4F3370076522F /* BaseBridge.cpp in Sources */, 21CE8AAB2CE4F3370076522F /* ProjectCollection.cpp in Sources */, 21CE8AAC2CE4F3370076522F /* GetIsDevMode.cpp in Sources */, @@ -3533,7 +3580,9 @@ 21CE8AC12CE4F3370076522F /* ConnectorProject.cpp in Sources */, 21CE8AC22CE4F3370076522F /* SendObject.cpp in Sources */, 21CE8AC32CE4F3370076522F /* OpenUrl.cpp in Sources */, + 21CE9B852CE69A230076522F /* Receive.cpp in Sources */, 21CE8AC42CE4F3370076522F /* SayHi.cpp in Sources */, + 21CE9B902CE75CFC0076522F /* ElementHighlighter.cpp in Sources */, 21CE8AC52CE4F3370076522F /* FilterMover.cpp in Sources */, 21CE8AC62CE4F3370076522F /* ConnectorMenu.cpp in Sources */, 21CE8AC72CE4F3370076522F /* GetAccounts.cpp in Sources */, @@ -3568,6 +3617,7 @@ 21CE8DE72CE5137C0076522F /* HighlightObjects.cpp in Sources */, 21CE8DE82CE5137C0076522F /* SendBridge.cpp in Sources */, 21CE8DE92CE5137C0076522F /* GetSendFilters.cpp in Sources */, + 21CE9B872CE69A230076522F /* ReceiveBridge.cpp in Sources */, 21CE8DEA2CE5137C0076522F /* BaseBridge.cpp in Sources */, 21CE8DEB2CE5137C0076522F /* ProjectCollection.cpp in Sources */, 21CE8DEC2CE5137C0076522F /* GetIsDevMode.cpp in Sources */, @@ -3594,7 +3644,9 @@ 21CE8E012CE5137C0076522F /* ConnectorProject.cpp in Sources */, 21CE8E022CE5137C0076522F /* SendObject.cpp in Sources */, 21CE8E032CE5137C0076522F /* OpenUrl.cpp in Sources */, + 21CE9B832CE69A230076522F /* Receive.cpp in Sources */, 21CE8E042CE5137C0076522F /* SayHi.cpp in Sources */, + 21CE9B8E2CE75CFC0076522F /* ElementHighlighter.cpp in Sources */, 21CE8E052CE5137C0076522F /* FilterMover.cpp in Sources */, 21CE8E062CE5137C0076522F /* ConnectorMenu.cpp in Sources */, 21CE8E072CE5137C0076522F /* GetAccounts.cpp in Sources */, @@ -3689,6 +3741,7 @@ "\"$(HEADER_PATH_5)/Frameworks\"", "\"$(HEADER_PATH_5)/Lib\"", ); + MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_CPLUSPLUSFLAGS = ( "-Wno-multichar", "-Wno-ctor-dtor-privacy", @@ -3753,6 +3806,7 @@ "\"$(HEADER_PATH_5)/Frameworks\"", "\"$(HEADER_PATH_5)/Lib\"", ); + MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_CPLUSPLUSFLAGS = ( "-Wno-multichar", "-Wno-ctor-dtor-privacy", diff --git a/SpeckleConnector/Connector.xcodeproj/xcshareddata/xcschemes/Connector-AC25-Debug.xcscheme b/SpeckleConnector/Connector.xcodeproj/xcshareddata/xcschemes/Connector-AC25-Debug.xcscheme index 19b567d..a6da887 100644 --- a/SpeckleConnector/Connector.xcodeproj/xcshareddata/xcschemes/Connector-AC25-Debug.xcscheme +++ b/SpeckleConnector/Connector.xcodeproj/xcshareddata/xcschemes/Connector-AC25-Debug.xcscheme @@ -1,6 +1,6 @@ @@ -55,7 +55,7 @@ diff --git a/SpeckleConnector/Connector/Connector.cpp b/SpeckleConnector/Connector/Connector.cpp index 9321923..c63157b 100644 --- a/SpeckleConnector/Connector/Connector.cpp +++ b/SpeckleConnector/Connector/Connector.cpp @@ -4,12 +4,21 @@ #include "Connector/Environment/ConnectorProject.h" #include "Connector/Interface/ConnectorMenu.h" #include "Connector/Interface/ConnectorPalette.h" +#include "Connector/Tool/ElementHighlighter.h" #include "Speckle/Database/AccountDatabase.h" #include "Speckle/Environment/Addon.h" #include "Speckle/Utility/String.h" #include +#ifdef WINDOWS + //NB: VS is ignoring template specialisations unless they are explicitly used in the top-level project +#include "Active/Setting/Values/GuidValue.h" +#include "Active/Setting/Values/TimeValue.h" +#include "Active/Setting/Values/StringValue.h" +using namespace active::setting; +#endif + using namespace active::file; using namespace active::environment; using namespace connector; @@ -42,6 +51,7 @@ namespace { //Define the connector UI components add(); add(); + add(); } // MARK: Functions (const) @@ -84,6 +94,18 @@ namespace { return std::nullopt; return Directory{*appData, speckleDataDirName, true}; } //getAppDataDirectory + +#ifdef WINDOWS + //NB: VS is ignoring template specialisations unless they are explicitly used in the top-level project + void invokeSpecialisation() { + StringValue stringValue; + active::utility::String unusedString = stringValue; + GuidValue guidValue; + active::utility::Guid unusedGuid = guidValue; + TimeValue timeValue; + active::utility::Time unusedTime = timeValue; + } +#endif } @@ -93,6 +115,9 @@ namespace { name: The add-on name --------------------------------------------------------------------*/ ConnectorAddon::ConnectorAddon(const speckle::utility::String& name) : Addon{name} { +#ifdef WINDOWS + invokeSpecialisation(); +#endif } //ConnectorAddon::ConnectorAddon diff --git a/SpeckleConnector/Connector/ConnectorResource.h b/SpeckleConnector/Connector/ConnectorResource.h index 17e4482..7a31c72 100755 --- a/SpeckleConnector/Connector/ConnectorResource.h +++ b/SpeckleConnector/Connector/ConnectorResource.h @@ -29,6 +29,7 @@ enum TitleString { addonNameID = 1, addonDescriptionID, noStoreyID, + showLayersID, }; @@ -44,6 +45,7 @@ enum GeneralString { //Notification strings (advice displayed in alerts) enum NotifyString { + showHiddenLayersID = 1, }; diff --git a/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp b/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp index 9a2f0b3..032ac1f 100644 --- a/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp +++ b/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp @@ -96,7 +96,7 @@ Vector ModelCardDatabase::getCards() const { card: The card to write --------------------------------------------------------------------*/ -void ModelCardDatabase::write(const ModelCard& card) const { +void ModelCardDatabase::write(ModelCard& card) const { m_store->write(card); } //ModelCardDatabase::write diff --git a/SpeckleConnector/Connector/Database/ModelCardDatabase.h b/SpeckleConnector/Connector/Database/ModelCardDatabase.h index 2f1e080..29a697b 100644 --- a/SpeckleConnector/Connector/Database/ModelCardDatabase.h +++ b/SpeckleConnector/Connector/Database/ModelCardDatabase.h @@ -43,7 +43,7 @@ namespace connector::database { Write a card to storage @param card The card to write */ - void write(const record::ModelCard& card) const; + void write(record::ModelCard& card) const; /*! Erase a card @param cardID The ID of the card to erase diff --git a/SpeckleConnector/Connector/Event/ConnectorEventID.h b/SpeckleConnector/Connector/Event/ConnectorEventID.h index 6cad8aa..aebff0b 100755 --- a/SpeckleConnector/Connector/Event/ConnectorEventID.h +++ b/SpeckleConnector/Connector/Event/ConnectorEventID.h @@ -9,10 +9,14 @@ inline const active::utility::NameID toggleConnectorPaletteID{"toggleConnectorPalette"}; //Identifier for event signalling the connector palette has changed (state carried with event) inline const active::utility::NameID reflectPaletteVisibilityID{"setConnectorMenuCheck"}; + //Identifier for event signalling the that an attached list of elements should be highlighted +inline const active::utility::NameID setElementHighlight{"setElementHighlight"}; // MARK: - Event setting identities - //Identifier for event signalling the connector palette visibility state + //Identifier for setting carrying a menu state inline const active::utility::NameID paletteVisibilityStateID{"menuCheckState"}; + //Identifier for setting carrying a list of element links +inline const active::utility::NameID recordLinks{"recordLinks"}; #endif //CONNECTOR_EVENT_ID diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.cpp index 741dc51..626c03b 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/AddModel.cpp @@ -29,6 +29,8 @@ void AddModel::run(const ModelCard& card) const { auto connectorProject = dynamic_cast(project.get()); if (!connectorProject) return; - if (auto modelCardDBase = connectorProject->getModelCardDatabase(); modelCardDBase != nullptr) - modelCardDBase->write(card); + if (auto modelCardDBase = connectorProject->getModelCardDatabase(); modelCardDBase != nullptr) { + auto newCard = clone(card); + modelCardDBase->write(*newCard); + } } //AddModel::run diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightModel.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightModel.cpp index 724aa59..ee6f7d3 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightModel.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightModel.cpp @@ -1,7 +1,11 @@ +#include "Active/Setting/ValueSetting.h" +#include "Active/Setting/Values/GuidValue.h" +#include "Active/Event/Event.h" #include "Connector/Interface/Browser/Bridge/Base/HighlightModel.h" #include "Connector/Connector.h" #include "Connector/ConnectorResource.h" #include "Connector/Environment/ConnectorProject.h" +#include "Connector/Event/ConnectorEventID.h" #include "Connector/Database/ModelCardDatabase.h" #include "Connector/Interface/Browser/Bridge/Send/Arg/SendError.h" #include "Connector/Record/Model/SenderModelCard.h" @@ -12,6 +16,8 @@ #include "Speckle/Environment/Host.h" #include "Speckle/Environment/Project.h" +using namespace active::event; +using namespace active::setting; using namespace connector::environment; using namespace connector::interfac::browser::bridge; using namespace connector::record; @@ -46,13 +52,9 @@ void HighlightModel::run(const String& modelCardID) const { return; } if (auto senderCard = dynamic_cast(modelCard.get())) { - auto modelCardSelection = senderCard->getFilter().getElementIDs(); - auto project = connector()->getActiveProject().lock(); - if (!project) - return; // TODO: is this OK? should this throw? - auto elementDatabase = project->getElementDatabase(); - elementDatabase->clearSelection(); - elementDatabase->setSelection(modelCardSelection); - host()->zoomToFit(true); + ValueSetting elementIDs{recordLinks}; + for (const auto& elementID : senderCard->getFilter().getElementIDs()) + elementIDs.emplace_back(GuidValue{elementID}); + connector()->publish(Event{setElementHighlight, { elementIDs }}); } } //HighlightModel::run diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightObjects.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightObjects.cpp index 1fa87ae..a977c74 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightObjects.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/HighlightObjects.cpp @@ -1,12 +1,13 @@ #include "Connector/Interface/Browser/Bridge/Base/HighlightObjects.h" +#include "Active/Setting/ValueSetting.h" +#include "Active/Event/Event.h" #include "Connector/Connector.h" -#include "Connector/Environment/ConnectorProject.h" -#include "Speckle/Database/BIMElementDatabase.h" -#include "Speckle/Environment/Host.h" -#include "Speckle/Environment/Project.h" +#include "Connector/Event/ConnectorEventID.h" -using namespace connector::environment; +using namespace active::event; +using namespace active::setting; +using namespace connector; using namespace connector::interfac::browser::bridge; using namespace speckle::database; using namespace speckle::environment; @@ -26,18 +27,5 @@ HighlightObjects::HighlightObjects() : BridgeMethod{"HighlightObjects", [&](cons objectIDs: List of object IDs to be highlighted --------------------------------------------------------------------*/ void HighlightObjects::run(const StringList& objectIDs) const { - BIMLinkList objectSelection; - for (const auto& text : objectIDs) - if (Guid guid{text}; !guid.empty()) - objectSelection.emplace_back(guid); - if (objectSelection.empty()) - return; - auto project = connector()->getActiveProject().lock(); - auto connectorProject = dynamic_cast(project.get()); - if (!connectorProject) - return; - auto elementDatabase = project->getElementDatabase(); - elementDatabase->clearSelection(); - elementDatabase->setSelection(objectSelection); - host()->zoomToFit(true); + connector()->publish(Event{setElementHighlight, { ValueSetting{objectIDs, recordLinks} }}); } //HighlightObjects::run diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.cpp index 6472d95..59c41e7 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/UpdateModel.cpp @@ -36,6 +36,8 @@ void UpdateModel::run(const ModelCard& card) const { auto connectorProject = dynamic_cast(project.get()); if (!connectorProject) return; - if (auto modelCardDBase = connectorProject->getModelCardDatabase(); modelCardDBase != nullptr) - modelCardDBase->write(card); + if (auto modelCardDBase = connectorProject->getModelCardDatabase(); modelCardDBase != nullptr) { + auto newCard = clone(card); + modelCardDBase->write(*newCard); + } } //UpdateModel::run diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Receive/Receive.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Receive/Receive.cpp new file mode 100644 index 0000000..c25ac58 --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Receive/Receive.cpp @@ -0,0 +1,46 @@ +#include "Connector/Interface/Browser/Bridge/Receive/Receive.h" + +#include "Active/Serialise/CargoHold.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Connector/Connector.h" +#include "Connector/ConnectorResource.h" +#include "Connector/Database/ModelCardDatabase.h" +#include "Connector/Environment/ConnectorProject.h" +#include "Connector/Record/Collection/ProjectCollection.h" +#include "Connector/Record/Model/ReceiverModelCard.h" +#include "Speckle/Database/AccountDatabase.h" +#include "Speckle/Database/BIMElementDatabase.h" +#include "Speckle/Database/Content/BIMRecord.h" +#include "Speckle/Environment/Project.h" +#include "Speckle/Environment/Host.h" +#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h" +#include "Speckle/Record/Credentials/Account.h" +#include "Speckle/Record/Element/Element.h" +#include "Speckle/Serialise/Detached/Storage/DetachedMemoryStore.h" +#include "Speckle/Utility/Exception.h" + +using namespace active::serialise; +using namespace connector::environment; +using namespace connector::interfac::browser::bridge; +using namespace connector::record; +using namespace speckle::database; +using namespace speckle::environment; +using namespace speckle::record::element; +using namespace speckle::serialise; +using namespace speckle::utility; + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +Receive::Receive() : BridgeMethod{"Receive", [&](const ReceiveArgs& args) { + run(args); +}} {} + + +/*-------------------------------------------------------------------- + Receive a specified model + + modelCardID: The ID of the model card identifying the objects to receive + --------------------------------------------------------------------*/ +void Receive::run(const String& modelCardID) const { +} //Receive::run diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Receive/Receive.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Receive/Receive.h new file mode 100644 index 0000000..a90b534 --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Receive/Receive.h @@ -0,0 +1,39 @@ +#ifndef CONNECTOR_INTERFACE_BRIDGE_RECEIVE +#define CONNECTOR_INTERFACE_BRIDGE_RECEIVE + +#include "Active/Serialise/CargoHold.h" +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Speckle/Interface/Browser/Bridge/BridgeMethod.h" + +namespace connector::interfac::browser::bridge { + + ///Argument parameter for a string + using StringHold = active::serialise::CargoHold, speckle::utility::String>; + ///Argument type for this method + using ReceiveArgs = speckle::interfac::browser::bridge::JSArgType; + + /*! + JS Function class to receive a specified model + */ + class Receive : public speckle::interfac::browser::bridge::BridgeMethod { + public: + + // MARK: - Constructors + + /*! + Constructor + */ + Receive(); + + // MARK: - Functions (const) + + /*! + Receive a specified model + @param modelCardID The ID of the model card identifying the objects to receive + */ + void run(const speckle::utility::String& modelCardID) const; + }; + +} + +#endif //CONNECTOR_INTERFACE_BRIDGE_RECEIVE diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Receive/ReceiveBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Receive/ReceiveBridge.cpp new file mode 100644 index 0000000..659d817 --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Receive/ReceiveBridge.cpp @@ -0,0 +1,30 @@ +#include "Connector/Interface/Browser/Bridge/Receive/ReceiveBridge.h" +#include "Connector/Interface/Browser/Bridge/Receive/Receive.h" +#include "Connector/Connector.h" +#include "Connector/ConnectorResource.h" +#include "Connector/Database/ModelCardDatabase.h" +#include "Connector/Environment/ConnectorProject.h" +#include "Speckle/Event/Type/ElementEvent.h" +#include "Speckle/Record/Element/Element.h" +#include "Speckle/Database/BIMElementDatabase.h" +#include "Speckle/Environment/Project.h" +#include "Speckle/Database/Identity/RecordID.h" +#include "Active/Serialise/CargoHold.h" +#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" +#include "Connector/Record/Model/ReceiverModelCard.h" + +using namespace speckle::database; +using namespace connector::environment; +using namespace connector::interfac::browser::bridge; +using namespace speckle::utility; +using namespace speckle::event; +using namespace active::serialise; +using namespace connector::record; + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +ReceiveBridge::ReceiveBridge() : BrowserBridge{"receiveBinding"} { + //Add bridge methods + addMethod(); +} //ReceiveBridge::ReceiveBridge diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Receive/ReceiveBridge.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Receive/ReceiveBridge.h new file mode 100644 index 0000000..dbeac58 --- /dev/null +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Receive/ReceiveBridge.h @@ -0,0 +1,29 @@ +#ifndef CONNECTOR_INTERFACE_BRIDGE_RECEIVE_BRIDGE +#define CONNECTOR_INTERFACE_BRIDGE_RECEIVE_BRIDGE + +#include "Speckle/Interface/Browser/Bridge/BrowserBridge.h" + +namespace connector::interfac::browser::bridge { + + /*! + A browser bridge to support receiving model data from a Speckle server + */ + class ReceiveBridge : public speckle::interfac::browser::bridge::BrowserBridge { + public: + + // MARK: - Types + + using base = speckle::interfac::browser::bridge::BrowserBridge; + + // MARK: - Constructors + + using base::base; + /*! + Default constructor + */ + ReceiveBridge(); + }; + +} + +#endif //CONNECTOR_INTERFACE_BRIDGE_RECEIVE_BRIDGE diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp index cb05aed..559cc96 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Selection/SelectionBridge.cpp @@ -24,7 +24,7 @@ SelectionBridge::SelectionBridge() : BrowserBridge{"selectionBinding"} { --------------------------------------------------------------------*/ bool SelectionBridge::handle(const speckle::event::SelectionEvent& event) { auto selectionInfo = std::make_unique(); - auto wrapped = std::make_unique>(std::move(selectionInfo)); + auto wrapped = std::make_unique>(std::move(selectionInfo)); sendEvent("setSelection", std::move(wrapped)); return true; } //SelectionBridge::handle diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp index 397089f..93a681d 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/Send.cpp @@ -76,7 +76,7 @@ void Send::run(const String& modelCardID) const { } //Get the selected elements from the modelcard auto elementDatabase = project->getElementDatabase(); - ElementIDList selected{}; + BIMRecordIDList selected{}; if (auto senderCard = dynamic_cast(modelCard.get())) selected = senderCard->getFilter().getElementIDs(); //Build a collection from the selected elements diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.cpp index 6d8ae7e..bd96353 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.cpp @@ -59,10 +59,9 @@ bool SendBridge::handle(const ElementEvent& event) { // POC: this is probably not efficient, should test, review and refactor it RecordIDList expiredModelCardIds; for (const auto& modelCard : modelCards) { - if (auto senderCard = dynamic_cast(modelCard.get())) { - auto modelCardSelection = senderCard->getFilter().getElementIDs(); - for (const auto& elemId : modelCardSelection) { - if (std::find(m_changedElements.begin(), m_changedElements.end(), elemId) != m_changedElements.end()) { + if (auto senderCard = dynamic_cast(modelCard.get()); senderCard) { + for (const auto& recordID : m_changedElements) { + if (senderCard->contains(recordID)) { expiredModelCardIds.push_back(modelCard->getID()); break; } @@ -76,8 +75,8 @@ bool SendBridge::handle(const ElementEvent& event) { break; } case changeElem: case editElem: case deleteElem: { - if (event.getElmentID()) - m_changedElements.push_back(*event.getElmentID()); + if (event.getElementID()) + m_changedElements.insert(*event.getElementID()); break; } default: diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.h index 391cb57..47bf942 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Send/SendBridge.h @@ -31,6 +31,10 @@ namespace connector::interfac::browser::bridge { @return True if the event should be closed */ bool handle(const speckle::event::ElementEvent& event) override; + + private: + ///List of changed element IDs + speckle::database::BIMRecordIDList m_changedElements; }; } diff --git a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp index 4f923e9..e8883f9 100644 --- a/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp +++ b/SpeckleConnector/Connector/Interface/ConnectorPalette.cpp @@ -11,6 +11,7 @@ #include "Connector/Interface/Browser/Bridge/Account/AccountBridge.h" #include "Connector/Interface/Browser/Bridge/Base/BaseBridge.h" #include "Connector/Interface/Browser/Bridge/Config/ConfigBridge.h" +#include "Connector/Interface/Browser/Bridge/Receive/ReceiveBridge.h" #include "Connector/Interface/Browser/Bridge/Send/SendBridge.h" #include "Connector/Interface/Browser/Bridge/Selection/SelectionBridge.h" #include "Connector/Interface/Browser/Bridge/Test/TestBridge.h" @@ -213,6 +214,7 @@ BrowserPalette::BrowserPalette() : } } install(); + install(); if (auto ref = install(); ref) { if (auto sendBridgeRef = std::dynamic_pointer_cast(ref); sendBridgeRef) { connector::connector()->addWeak(sendBridgeRef); diff --git a/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.cpp b/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.cpp index b413ef4..3f22e2c 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.cpp +++ b/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.cpp @@ -56,7 +56,7 @@ Cargo::Unique DirectSelectionSendFilter::getCargo(const Inventory::Item& item) c using namespace active::serialise; switch (item.index) { case selectedElemID: - return std::make_unique>(m_selectedElements, false, fieldID[selectedElemID].name); + return std::make_unique>(m_selectedElements, false, fieldID[selectedElemID].name); default: return nullptr; //Requested an unknown index } diff --git a/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.h b/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.h index f2e64a5..3cb9d39 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.h +++ b/SpeckleConnector/Connector/Record/Model/Filter/DirectSelectionSendFilter.h @@ -32,11 +32,17 @@ namespace connector::record { // MARK: - Functions (const) + /*! + Determine if the send filter contains a specified record ID + @param recordID The record ID to search for + @return True if the filter contains the record ID + */ + virtual bool contains(const speckle::database::BIMRecordID& recordID) const override { return m_selectedElements.contains(recordID); } /*! Get the filtered element IDs @return The filter elements */ - const speckle::database::ElementIDList& getElementIDs() const override { return m_selectedElements; } + const speckle::database::BIMRecordIDList& getElementIDs() const override { return m_selectedElements; } // MARK: - Serialisation @@ -59,7 +65,7 @@ namespace connector::record { private: ///A list of selected element IDs - speckle::database::ElementIDList m_selectedElements; + speckle::database::BIMRecordIDList m_selectedElements; }; } diff --git a/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.cpp b/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.cpp index 00a49aa..b5eb6eb 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.cpp +++ b/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.cpp @@ -58,7 +58,7 @@ Cargo::Unique EverythingSendFilter::getCargo(const Inventory::Item& item) const using namespace active::serialise; switch (item.index) { case selectedElemID: - return std::make_unique>(m_emptyList); + return std::make_unique>(m_emptyList); default: return nullptr; //Requested an unknown index } diff --git a/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.h b/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.h index 4cd604e..da1eb51 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.h +++ b/SpeckleConnector/Connector/Record/Model/Filter/EverythingSendFilter.h @@ -32,17 +32,23 @@ namespace connector::record { // MARK: - Functions (const) + /*! + Determine if the send filter contains a specified record ID + @param recordID The record ID to search for + @return True if the filter contains the record ID + */ + virtual bool contains(const speckle::database::BIMRecordID& recordID) const override { return true; } /*! Get the filtered element IDs @return The filter elements */ - const speckle::database::ElementIDList& getElementIDs() const override { return m_emptyList; } + const speckle::database::BIMRecordIDList& 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 speckle::database::ElementIDList& changed) const override { return true; } + virtual bool checkExpiry(const speckle::database::BIMRecordIDList& changed) const override { return true; } // MARK: - Serialisation @@ -65,7 +71,7 @@ namespace connector::record { private: ///Enables a const empty list to be returned - speckle::database::ElementIDList m_emptyList; + speckle::database::BIMRecordIDList m_emptyList; }; } diff --git a/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.cpp b/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.cpp index 8b42cc8..67ba1ca 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.cpp +++ b/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.cpp @@ -34,12 +34,10 @@ namespace { 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)); +bool SendFilter::checkExpiry(const BIMRecordIDList& changed) const { + BIMRecordIDList intersect; + BIMRecordIDList mine{getElementIDs()}, theirs{changed}; + std::set_intersection(mine.begin(), mine.end(), theirs.begin(), theirs.end(), std::inserter(intersect, intersect.begin())); return !intersect.empty(); } //SendFilter::checkExpiry diff --git a/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.h b/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.h index cedfc56..3f21839 100644 --- a/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.h +++ b/SpeckleConnector/Connector/Record/Model/Filter/SendFilter.h @@ -4,6 +4,7 @@ #include "Active/Serialise/Package/Package.h" #include "Active/Utility/Cloner.h" #include "Speckle/Database/Identity/RecordID.h" +#include "Speckle/Database/Identity/BIMRecordID.h" #include "Speckle/Utility/String.h" namespace connector::record { @@ -55,17 +56,23 @@ namespace connector::record { @return True if this is the default filter */ bool isDefault() const { return m_isDefault; }; + /*! + Determine if the send filter contains a specified record ID + @param recordID The record ID to search for + @return True if the filter contains the record ID + */ + virtual bool contains(const speckle::database::BIMRecordID& recordID) const = 0; /*! Get the filtered element IDs @return The filter elements */ - virtual const speckle::database::ElementIDList& getElementIDs() const = 0; + virtual const speckle::database::BIMRecordIDList& 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 speckle::database::ElementIDList& changed) const; + virtual bool checkExpiry(const speckle::database::BIMRecordIDList& changed) const; // MARK: - Serialisation diff --git a/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.cpp b/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.cpp index 55bb8c8..17152bc 100644 --- a/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.cpp +++ b/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.cpp @@ -2,6 +2,7 @@ #include "Active/Serialise/Item/Wrapper/ValueWrap.h" #include "Active/Serialise/Package/Wrapper/ContainerWrap.h" +#include "Speckle/Database/Identity/BIMRecordID.h" #include @@ -81,7 +82,7 @@ Cargo::Unique ReceiverModelCard::getCargo(const Inventory::Item& item) const { case warningDismissedID: return std::make_unique(m_hasDismissedUpdateWarning); case bakedObjectsID: - return std::make_unique>(m_bakedObjectIDs); + return std::make_unique>(m_bakedObjectIDs); default: return nullptr; //Requested an unknown index } diff --git a/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.h b/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.h index e13acdb..9e369dd 100644 --- a/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.h +++ b/SpeckleConnector/Connector/Record/Model/ReceiverModelCard.h @@ -1,7 +1,7 @@ #ifndef CONNECTOR_RECORD_RECEIVER_MODEL_CARD #define CONNECTOR_RECORD_RECEIVER_MODEL_CARD -#include "Speckle/Database/Identity/RecordID.h" +#include "Speckle/Database/Identity/BIMRecordID.h" #include "Connector/Record/Model/ModelCard.h" namespace connector::record { @@ -37,7 +37,7 @@ namespace connector::record { const speckle::database::RecordID& modelID, const speckle::utility::String& modelName, const speckle::database::RecordID& selectedVersion, const speckle::database::RecordID& latestVersion, const speckle::database::RecordID& accountID, const speckle::utility::String& serverURL, - bool hasDimissedWarning, speckle::database::ElementIDList&& bakedObjects, const SettingList& settings) : + bool hasDimissedWarning, speckle::database::BIMRecordIDList&& bakedObjects, const SettingList& settings) : ModelCard{modelID, projectID, accountID, serverURL, settings}, m_projectName{projectName}, m_modelName{modelName}, m_selectedVersionID{selectedVersion}, m_latestVersionID{latestVersion}, m_hasDismissedUpdateWarning{hasDimissedWarning}, m_bakedObjectIDs{bakedObjects} {} @@ -78,7 +78,7 @@ namespace connector::record { Get the IDs of objects accepted in the receive @return The accepted object IDs */ - const speckle::database::ElementIDList& getBakedObjectIDs() const { return m_bakedObjectIDs; } + const speckle::database::BIMRecordIDList& getBakedObjectIDs() const { return m_bakedObjectIDs; } // MARK: - Serialisation @@ -111,7 +111,7 @@ namespace connector::record { ///True if the user has already dismissed an alert to update bool m_hasDismissedUpdateWarning = false; ///IDs of objects accepted in the receive - speckle::database::ElementIDList m_bakedObjectIDs; + speckle::database::BIMRecordIDList m_bakedObjectIDs; }; } diff --git a/SpeckleConnector/Connector/Record/Model/SenderModelCard.cpp b/SpeckleConnector/Connector/Record/Model/SenderModelCard.cpp index e122cc3..42dd8aa 100644 --- a/SpeckleConnector/Connector/Record/Model/SenderModelCard.cpp +++ b/SpeckleConnector/Connector/Record/Model/SenderModelCard.cpp @@ -61,6 +61,18 @@ SenderModelCard::~SenderModelCard() { } //SenderModelCard::~SenderModelCard +/*-------------------------------------------------------------------- + Determine if the send filter contains a specified record ID + + recordID: The record ID to search for + + return: True if the filter contains the record ID + --------------------------------------------------------------------*/ +bool SenderModelCard::contains(const speckle::database::BIMRecordID& recordID) const { + return m_filter->contains(recordID); +} //SenderModelCard::contains + + /*-------------------------------------------------------------------- Fill an inventory with the package items diff --git a/SpeckleConnector/Connector/Record/Model/SenderModelCard.h b/SpeckleConnector/Connector/Record/Model/SenderModelCard.h index 0b3e010..c802632 100644 --- a/SpeckleConnector/Connector/Record/Model/SenderModelCard.h +++ b/SpeckleConnector/Connector/Record/Model/SenderModelCard.h @@ -2,6 +2,7 @@ #define CONNECTOR_RECORD_SENDER_MODEL_CARD #include "Connector/Record/Model/ModelCard.h" +#include "Speckle/Database/Identity/BIMRecordID.h" namespace connector::record { @@ -46,6 +47,12 @@ namespace connector::record { // MARK: - Functions (const) + /*! + Determine if the send filter contains a specified record ID + @param recordID The record ID to search for + @return True if the filter contains the record ID + */ + bool contains(const speckle::database::BIMRecordID& recordID) const; /*! Get the filter applied when the model was sent @return The model filter diff --git a/SpeckleConnector/Connector/Tool/ElementHighlighter.cpp b/SpeckleConnector/Connector/Tool/ElementHighlighter.cpp new file mode 100644 index 0000000..13fb5f9 --- /dev/null +++ b/SpeckleConnector/Connector/Tool/ElementHighlighter.cpp @@ -0,0 +1,123 @@ +#include "Connector/Tool/ElementHighlighter.h" + +#include "Active/Database/Transaction.h" +#include "Active/Event/Event.h" +#include "Connector/Connector.h" +#include "Connector/ConnectorResource.h" +#include "Connector/Environment/ConnectorProject.h" +#include "Connector/Event/ConnectorEventID.h" +#include "Speckle/Database/BIMAttributeDatabase.h" +#include "Speckle/Database/BIMElementDatabase.h" +#include "Speckle/Database/Identity/BIMLink.h" +#include "Speckle/Environment/Host.h" +#include "Speckle/Record/Filter/ElementVisibilityCollector.h" +#include "Speckle/Utility/Guid.h" + +using namespace active::database; +using namespace active::event; +using namespace active::setting; +using namespace connector; +using namespace connector::environment; +using namespace speckle::database; +using namespace speckle::environment; +using namespace speckle::record; +using namespace speckle::utility; + +namespace { + + /*! + Transaction to make a selection of layers visible + */ + class ShowLayers : public Transaction { + public: + /*! + Constructor + @param project The target project + @param layers The layers in the project to be made visible + */ + ShowLayers(Project::Shared project, ElementVisibilityCollector::Layers& layers) : + Transaction{connector::connector()->getLocalString(titleString, showLayersID)}, m_project{project}, m_layers{layers} {} + + protected: + + //MARK: - Functions (App management) + + /*! + Perform the transaction. Database writes can be performed. NB: this function is not called if the prepare phase was unsuccessful) + @return True if the transaction was successfully performed + */ + bool perform() override { + auto attributeDatabase = m_project->getAttributeDatabase(); + for (auto& layer : m_layers) { + if (layer.second.isHidden()) { + layer.second.setHidden(false); + attributeDatabase->write(layer.second); + } + } + return true; + } + + private: + ///The target project for showing layers + Project::Shared m_project; + ///The layers to be made visible + ElementVisibilityCollector::Layers& m_layers; + }; + +} + +/*-------------------------------------------------------------------- + Get the event subscription list + + return: The subscription list (an empty list will put the subscriber into a suspended state) + --------------------------------------------------------------------*/ +Subscriber::Subscription ElementHighlighter::subscription() const { + return Subscription{setElementHighlight}; +} //ElementHighlighter::subscription + + +/*-------------------------------------------------------------------- + Receive a subscribed event + + event: The incoming event + + return: True if the event should be closed + --------------------------------------------------------------------*/ +bool ElementHighlighter::receive(const active::event::Event& event) { + //Collect the IDs of elements to be highlighted + ValueSetting* elementIDs = nullptr; + if (elementIDs = event.findValue(recordLinks); elementIDs == nullptr) + return false; + BIMLinkList elementSelection; + for (const auto& value : *elementIDs) + if (Guid guid{value->operator active::utility::Guid()}; guid) + elementSelection.emplace_back(guid); + if (elementSelection.empty()) + return false; + auto project = connector()->getActiveProject().lock(); + auto connectorProject = dynamic_cast(project.get()); + if (!connectorProject) + return false; + auto elementDatabase = project->getElementDatabase(); + //Collect the layers assigned to the model card elements + ElementVisibilityCollector collector; + BIMElementDatabase::Filter filter = [&collector](const speckle::record::element::Element& elem) { return collector(elem); }; + elementDatabase->findElements(&filter, elementSelection); + //If any collected layers are hidden, the useer is prompted to show them (otherwise they may see nothing happen when a model card is clicked) + for (const auto& layer : collector.getLayers()) { + if (layer.second.isHidden()) { + //If a hidden layer is found, ask the user before taking any action + if (host()->displayConfirmation(addon()->getLocalString(notifyString, showHiddenLayersID))) { + //Run a transaction to ensure all layers are visible + ShowLayers showLayers{project, collector.getLayers()}; + connector()->makeTransaction(showLayers); + } + break; + } + } + host()->makeModelViewActive(); + elementDatabase->clearSelection(); + elementDatabase->setSelection(elementSelection); + host()->zoomToFit(true); + return false; +} //ElementHighlighter::receive diff --git a/SpeckleConnector/Connector/Tool/ElementHighlighter.h b/SpeckleConnector/Connector/Tool/ElementHighlighter.h new file mode 100644 index 0000000..b4b6d28 --- /dev/null +++ b/SpeckleConnector/Connector/Tool/ElementHighlighter.h @@ -0,0 +1,28 @@ +#ifndef CONNECTOR_ELEMENT_HIGHLIGHTER +#define CONNECTOR_ELEMENT_HIGHLIGHTER + +#include "Active/Event/Subscriber.h" + +namespace connector { + + class ElementHighlighter : public active::event::Subscriber { + public: + /*! + 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; + }; + +} + +#endif //CONNECTOR_ELEMENT_HIGHLIGHTER diff --git a/SpeckleConnector/RINT/Connector.grc b/SpeckleConnector/RINT/Connector.grc index 24aba3e..9e938ff 100644 --- a/SpeckleConnector/RINT/Connector.grc +++ b/SpeckleConnector/RINT/Connector.grc @@ -2,8 +2,15 @@ /* [ 1] */ "Speckle Connector" /* [ 2] */ "Connector to share model content with Speckle" /* [ 3] */ "No level" +/* [ 4] */ "Show Layers" } + +'STR#' 32602 "Notify strings" { +/* [ 1] */ "Some elements published with the selected model card are on hidden layers - do you wish to make these layers visible?" +} + + 'STR#' 32604 "Error strings" { /* [ 1] */ "No objects were found to convert. Please update your publish filter!" /* [ 2] */ "The specified model card cannot be found. Try another card or create a new one" diff --git a/SpeckleLib/RINT/Speckle.grc b/SpeckleLib/RINT/Speckle.grc index aa8eab1..0edb61a 100644 --- a/SpeckleLib/RINT/Speckle.grc +++ b/SpeckleLib/RINT/Speckle.grc @@ -2,4 +2,9 @@ /* [ 1] */ "Untitled" /* [ 2] */ "Unknown" /* [ 3] */ "Converting elements" +/* [ 4] */ "Notification" +/* [ 5] */ "Confirm" +/* [ 6] */ "Yes" +/* [ 7] */ "No" +/* [ 8] */ "OK" } diff --git a/SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp index 2fbf967..ad81693 100644 --- a/SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp +++ b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.cpp @@ -27,7 +27,7 @@ namespace speckle::database { ///Attribute database engine declaration class BIMAttributeDatabase::Engine : public AttributeDatabaseEngine { - using base = ArchicadAttributeDBaseEngine; + using base = AttributeDatabaseEngine; using base::base; }; @@ -102,7 +102,7 @@ Vector BIMAttributeDatabase::getAttributes() const { attribute: The attribute to write --------------------------------------------------------------------*/ -void BIMAttributeDatabase::write(const Attribute& attribute) const { +void BIMAttributeDatabase::write(Attribute& attribute) const { m_store->write(attribute); } //BIMAttributeDatabase::write diff --git a/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h index 17fe657..6ca63fc 100644 --- a/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h +++ b/SpeckleLib/Speckle/Database/BIMAttributeDatabase.h @@ -55,7 +55,7 @@ namespace speckle::database { Write an attribute to storage @param attribute The attribute to write */ - void write(const record::attribute::Attribute& attribute) const; + void write(record::attribute::Attribute& attribute) const; /*! Erase an attribute @param attributeID The ID of the attribute to erase diff --git a/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp b/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp index 9837c54..408144f 100644 --- a/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp +++ b/SpeckleLib/Speckle/Database/BIMElementDatabase.cpp @@ -148,14 +148,15 @@ void BIMElementDatabase::clearSelection() const { Find a filtered list of objects filter: The object filter (nullptr = find all objects) + subset: A subset of the database content to search (specified by record ID) tableID: Optional table ID (defaults to the first table) documentID: Optional document ID (filter for this document only - nullopt = all objects) return: A list containing IDs of found elements (empty if none found) --------------------------------------------------------------------*/ -BIMRecordIDList BIMElementDatabase::findElements(const Filter& filter, std::optional tableID, - std::optional documentID) const { - return m_engine->findObjects(filter, tableID, documentID); +BIMRecordIDList BIMElementDatabase::findElements(const Filter* filter, const BIMRecordIDList& subset, std::optional tableID, + std::optional documentID) const { + return m_engine->findObjects(filter, subset, tableID, documentID); } //BIMElementDatabase::findElements @@ -212,7 +213,7 @@ Memo::Unique BIMElementDatabase::getMemo(const BIMRecordID& elementID, Part::fil element: The element to write --------------------------------------------------------------------*/ -void BIMElementDatabase::write(const Element& element) const { +void BIMElementDatabase::write(Element& element) const { m_store->write(element); } //BIMElementDatabase::write diff --git a/SpeckleLib/Speckle/Database/BIMElementDatabase.h b/SpeckleLib/Speckle/Database/BIMElementDatabase.h index 000612e..d1a692c 100644 --- a/SpeckleLib/Speckle/Database/BIMElementDatabase.h +++ b/SpeckleLib/Speckle/Database/BIMElementDatabase.h @@ -74,12 +74,13 @@ namespace speckle::database { /*! Find a filtered list of objects @param filter The object filter (nullptr = find all objects) + @param subset A subset of the database content to search (specified by record ID) @param tableID Optional table ID (defaults to the first table) @param documentID Optional document ID (filter for this document only - nullopt = all objects) @return A list containing IDs of found elements (empty if none found) */ - BIMRecordIDList findElements(const Filter& filter = nullptr, std::optional tableID = std::nullopt, - std::optional documentID = std::nullopt) const; + BIMRecordIDList findElements(const Filter* filter = nullptr, const BIMRecordIDList& subset = {}, + std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const; /*! Get a specified element @param elementID The ID of the target element @@ -114,7 +115,7 @@ namespace speckle::database { Write an element to storage @param element The element to write */ - void write(const record::element::Element& element) const; + void write(record::element::Element& element) const; /*! Erase an element @param elementID The ID of the element to erase diff --git a/SpeckleLib/Speckle/Database/BIMGroupDatabase.cpp b/SpeckleLib/Speckle/Database/BIMGroupDatabase.cpp index 2b653a5..62e9460 100644 --- a/SpeckleLib/Speckle/Database/BIMGroupDatabase.cpp +++ b/SpeckleLib/Speckle/Database/BIMGroupDatabase.cpp @@ -114,7 +114,7 @@ Vector BIMGroupDatabase::getGroups() const { group: The group to write --------------------------------------------------------------------*/ -void BIMGroupDatabase::write(const Group& group) const { +void BIMGroupDatabase::write(Group& group) const { m_store->write(group); } //BIMGroupDatabase::write diff --git a/SpeckleLib/Speckle/Database/BIMGroupDatabase.h b/SpeckleLib/Speckle/Database/BIMGroupDatabase.h index df18e4f..fdca3eb 100644 --- a/SpeckleLib/Speckle/Database/BIMGroupDatabase.h +++ b/SpeckleLib/Speckle/Database/BIMGroupDatabase.h @@ -57,7 +57,7 @@ namespace speckle::database { Write an group to storage @param group The group to write */ - void write(const record::property::Group& group) const; + void write(record::property::Group& group) const; /*! Erase an group @param groupID The ID of the group to erase diff --git a/SpeckleLib/Speckle/Database/BIMPropertyDatabase.cpp b/SpeckleLib/Speckle/Database/BIMPropertyDatabase.cpp index 5456f62..d99f66f 100644 --- a/SpeckleLib/Speckle/Database/BIMPropertyDatabase.cpp +++ b/SpeckleLib/Speckle/Database/BIMPropertyDatabase.cpp @@ -126,7 +126,7 @@ std::vector> BIMPropertyDatabase::findTemplatesByClass property: The property to write --------------------------------------------------------------------*/ -void BIMPropertyDatabase::write(const Template& property) const { +void BIMPropertyDatabase::write(Template& property) const { m_store->write(property); } //BIMPropertyDatabase::write diff --git a/SpeckleLib/Speckle/Database/BIMPropertyDatabase.h b/SpeckleLib/Speckle/Database/BIMPropertyDatabase.h index 8496c96..eec7aba 100644 --- a/SpeckleLib/Speckle/Database/BIMPropertyDatabase.h +++ b/SpeckleLib/Speckle/Database/BIMPropertyDatabase.h @@ -63,7 +63,7 @@ namespace speckle::database { Write an property to storage @param property The property to write */ - void write(const record::property::Template& property) const; + void write(record::property::Template& property) const; /*! Erase an property @param propertyID The ID of the property to erase diff --git a/SpeckleLib/Speckle/Database/Identity/BIMLink.cpp b/SpeckleLib/Speckle/Database/Identity/BIMLink.cpp index 24c033c..a416269 100644 --- a/SpeckleLib/Speckle/Database/Identity/BIMLink.cpp +++ b/SpeckleLib/Speckle/Database/Identity/BIMLink.cpp @@ -13,9 +13,28 @@ using namespace speckle::utility; BIMLink::BIMLink(const API_Neig& selected, const BIMRecordID& tableID) : base{Guid{selected.guid}, tableID} { //More info should be extracted from API_Neig in future (as required) - extract into link settings, e.g. selection target etc } //Link::Link +#endif -BIMLinkList::BIMLinkList(const ElementIDList& elementIDList) { + +/*-------------------------------------------------------------------- + Constructor + + elementIDList: BIM record IDs to populate the links + --------------------------------------------------------------------*/ +BIMLinkList::BIMLinkList(const BIMRecordIDList& elementIDList) { for (const auto& id : elementIDList) push_back(id); -} -#endif +} //BIMLinkList::BIMLinkList + + +/*-------------------------------------------------------------------- + Conversion operator + + return: A list of BIM record IDs from this list + --------------------------------------------------------------------*/ +BIMLinkList::operator BIMRecordIDList() const { + BIMRecordIDList result; + for (const auto& link : *this) + result.insert(BIMRecordID{link}); + return result; +} //BIMLinkList::operator BIMRecordIDList diff --git a/SpeckleLib/Speckle/Database/Identity/BIMLink.h b/SpeckleLib/Speckle/Database/Identity/BIMLink.h index 4eeb5b6..90ea960 100644 --- a/SpeckleLib/Speckle/Database/Identity/BIMLink.h +++ b/SpeckleLib/Speckle/Database/Identity/BIMLink.h @@ -41,18 +41,35 @@ namespace speckle::database { #endif }; - //A list of links to BIM records - //using BIMLinkList = std::vector; + /*! + A list of links to BIM records + */ class BIMLinkList : public std::vector { public: - + + // MARK: - Types + using base = std::vector; - + + // MARK: - Constructors + using base::base; BIMLinkList() = default; - BIMLinkList(const ElementIDList& elementIDList); + /*! + Constructor + @param elementIDList BIM record IDs to populate the links + */ + BIMLinkList(const BIMRecordIDList& elementIDList); + + // MARK: - Operators + + /*! + Conversion operator + @return A list of BIM record IDs from this list + */ + operator BIMRecordIDList() const; }; } diff --git a/SpeckleLib/Speckle/Database/Identity/RecordID.h b/SpeckleLib/Speckle/Database/Identity/RecordID.h index 312ca44..2bc266e 100644 --- a/SpeckleLib/Speckle/Database/Identity/RecordID.h +++ b/SpeckleLib/Speckle/Database/Identity/RecordID.h @@ -15,12 +15,6 @@ namespace speckle::database { //A list of record IDs using RecordIDList = std::vector; - - //BIM element record identifier - using ElementID = speckle::utility::Guid; - - //A list of element IDs - using ElementIDList = std::vector; } diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.cpp b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.cpp index 5848954..cc1f741 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.cpp +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.cpp @@ -33,7 +33,7 @@ namespace { return: An equivalent status code --------------------------------------------------------------------*/ - ArchicadDBaseCore::Status convertArchicadError(long acErrorCode) { + ArchicadDBaseCore::Status convertArchicadError(GSErrCode acErrorCode) { using enum ArchicadDBaseCore::Status; switch (acErrorCode) { case NoError: @@ -92,4 +92,16 @@ std::error_code ArchicadDBaseCore::makeError(ArchicadDBaseCore::Status code) { return std::error_code(static_cast(code), instance); } //ArchicadDBaseCore::makeError + +/*-------------------------------------------------------------------- + Make an error code for ArchicadElementDBase processing + + code: An Archicad API error code + + return: An STL error code + --------------------------------------------------------------------*/ +std::error_code ArchicadDBaseCore::makeError(GSErrCode code) { + return makeError(convertArchicadError(code)); +} //ArchicadDBaseCore::makeError + #endif diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h index fb6f0fa..dae78e2 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/ArchicadDBaseCore.h @@ -9,6 +9,8 @@ #include "Active/Utility/NameID.h" #include "Speckle/Event/Subscriber/ProjectSubscriber.h" +#include + namespace speckle::database { using ArchicadDBaseSchema = active::database::DBaseSchema<>; @@ -35,9 +37,16 @@ namespace speckle::database { /*! Make an error code for ArchicadElementDBase processing + @param code An ArchicadDBaseCore status code @return An STL error code */ static std::error_code makeError(ArchicadDBaseCore::Status code); + /*! + Make an error code for ArchicadElementDBase processing + @param code An Archicad API error code + @return An STL error code + */ + static std::error_code makeError(GSErrCode code); // MARK: - Constructors diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp index ff23dbc..85d2e57 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.cpp @@ -221,9 +221,26 @@ active::container::Vector ArchicadAttributeDBaseEngine::getObjects(co tableID: Optional table ID (defaults to the floor plan) documentID: Optional document ID (when the object is bound to a specific document) --------------------------------------------------------------------*/ -void ArchicadAttributeDBaseEngine::write(const Attribute& object, const BIMRecordID& objID, std::optional objDocID, - std::optional tableID, std::optional documentID) const { - //TODO: Implement +void ArchicadAttributeDBaseEngine::write(Attribute& object, const BIMRecordID& objID, std::optional objDocID, + std::optional tableID, std::optional documentID) const { + auto attributeData = object.getDataOut(); + //An record with no index has not been written (and needs to be created in the dbase) + GSErrCode status = NoError; +#ifdef ServerMainVers_2700 + if (attributeData.header.index.GenerateHashValue() == 0) +#else + if (attributeData.header.index == 0) +#endif + { + status = ACAPI_Attribute_CreateExt(&attributeData, nullptr); //TODO: Handle attribute extended definition + //Archicad assigns record guids - we need to capture this for the caller + object.setBIMID(attributeData.header.guid); + } else + status = ACAPI_Attribute_ModifyExt(&attributeData, nullptr); + if (status != NoError) + throw std::system_error(makeError(status)); + //Archicad modifies record headers on write - need to capture this data for the caller + object.getHead() = attributeData.header; } //ArchicadAttributeDBaseEngine::write diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h index 6b13c59..cf66b6b 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Attribute/ArchicadAttributeDBaseEngine.h @@ -55,11 +55,13 @@ namespace speckle::database { /*! Find a filtered list of objects @param filter The object filter (nullptr = find all objects) + @param subset A subset of the database content to search (specified by record ID) @param tableID Optional table ID (defaults to the first table) @param documentID Optional document ID (filter for this document only - nullopt = all objects) @return A list containing IDs of found elements (empty if none found) */ - virtual ObjIDList findObjects(const Filter& filter = nullptr, std::optional tableID = std::nullopt, + virtual ObjIDList findObjects(const Filter* filter = nullptr, const ObjIDList& subset = {}, + std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override { return {}; } //Implement when required /*! Get an object by ID @@ -101,7 +103,7 @@ namespace speckle::database { @param tableID Optional table ID (defaults to the floor plan) @param documentID Optional document ID (when the object is bound to a specific document) */ - void write(const Attribute& object, const BIMRecordID& objID, std::optional objDocID = std::nullopt, + void write(Attribute& object, const BIMRecordID& objID, std::optional objDocID = std::nullopt, std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override; /*! Erase an object by index diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp index a0a4353..ad00cef 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.cpp @@ -96,6 +96,21 @@ namespace { } //setActiveTable + /*! + Find indices of all elements in an Archicad database. NB: It is assumed that the active database has already been set + @return A list of all element IDs in the active database + */ + BIMRecordIDList getAllElementIDs() { + GS::Array found; + if ((ACAPI_Element_GetElemList({}, &found) != NoError) || found.IsEmpty()) + return {}; + BIMRecordIDList result; + for (const auto& item : found) + result.insert(item); + return result; + } //getAllElementIDs + + /*! Make a new element object @param elementData The API element representation @@ -287,28 +302,38 @@ void ArchicadElementDBaseEngine::setDefaultTable(const BIMRecordID& tableID) con Find a filtered list of objects filter: The object filter (nullptr = find all objects) + subset: A subset of the database content to search (specified by record ID) tableID: Optional table ID (defaults to the first table) documentID: Optional document ID (filter for this document only - nullopt = all objects) return: A list containing IDs of found elements (empty if none found) --------------------------------------------------------------------*/ -BIMRecordIDList ArchicadElementDBaseEngine::findObjects(const Filter& filter, std::optional tableID, - std::optional documentID) const { +BIMRecordIDList ArchicadElementDBaseEngine::findObjects(const Filter* filter, const BIMRecordIDList& subset, std::optional tableID, + std::optional documentID) const { //Switch to the target table (when specified). Otherwise the currently active table will be used if (tableID) setActiveTable(*tableID); //First check for no filter (in which case we return all objects) if (filter == nullptr) { - GS::Array found; - if ((ACAPI_Element_GetElemList({}, &found) != NoError) || found.IsEmpty()) - return {}; - BIMRecordIDList result; - for (const auto& item : found) - result.insert(item); - return result; + if (!subset.empty()) + return subset; + return getAllElementIDs(); } - //Implement other filtering as required - ideally identify characteristics supported by API, e.g. filter by type/renovation etc - return {}; + BIMRecordIDList buffer, result; + //Pick either all records or the specified subset + auto source = ⊂ + if (subset.empty()) { + buffer = getAllElementIDs(); + source = &buffer; + } + //Run the filter on the specified elements + for (const auto& elemID : *source) { + if (auto element = getObject(elemID); element) { + if ((*filter)(*element)) + result.insert(elemID); + } + } + return result; } //ArchicadElementDBaseEngine::findObjects @@ -423,7 +448,7 @@ active::container::Vector ArchicadElementDBaseEngine::getObjects(const tableID: Optional table ID (defaults to the floor plan) documentID: Optional document ID (when the object is bound to a specific document) --------------------------------------------------------------------*/ -void ArchicadElementDBaseEngine::write(const Element& object, const BIMRecordID& objID, std::optional objDocID, +void ArchicadElementDBaseEngine::write(Element& object, const BIMRecordID& objID, std::optional objDocID, std::optional tableID, std::optional documentID) const { } //ArchicadElementDBaseEngine::write diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h index ef50f8c..a8679b5 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Element/ArchicadElementDBaseEngine.h @@ -92,12 +92,14 @@ namespace speckle::database { /*! Find a filtered list of objects @param filter The object filter (nullptr = find all objects) + @param subset A subset of the database content to search (specified by record ID) @param tableID Optional table ID (defaults to the first table) @param documentID Optional document ID (filter for this document only - nullopt = all objects) @return A list containing IDs of found elements (empty if none found) */ - virtual BIMRecordIDList findObjects(const Filter& filter = nullptr, std::optional tableID = std::nullopt, - std::optional documentID = std::nullopt) const override; + virtual BIMRecordIDList findObjects(const Filter* filter = nullptr, const BIMRecordIDList& subset = {}, + std::optional tableID = std::nullopt, + std::optional documentID = std::nullopt) const override; /*! Get an object by index @param objID The object ID @@ -138,7 +140,7 @@ namespace speckle::database { @param tableID Optional table ID (defaults to the floor plan) @param documentID Optional document ID (when the object is bound to a specific document) */ - void write(const Element& object, const BIMRecordID& objID, std::optional objDocID = std::nullopt, + void write(Element& object, const BIMRecordID& objID, std::optional objDocID = std::nullopt, std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override; /*! Erase an object by index diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Property/ArchicadGroupDBaseEngine.cpp b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Property/ArchicadGroupDBaseEngine.cpp index 18b1123..d05b292 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Property/ArchicadGroupDBaseEngine.cpp +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Property/ArchicadGroupDBaseEngine.cpp @@ -154,7 +154,7 @@ active::container::Vector ArchicadGroupDBaseEngine::getObjects(const Filt tableID: Optional table ID (defaults to the floor plan) documentID: Optional document ID (when the object is bound to a specific document) --------------------------------------------------------------------*/ -void ArchicadGroupDBaseEngine::write(const Group& object, const BIMRecordID& objID, std::optional objDocID, +void ArchicadGroupDBaseEngine::write(Group& object, const BIMRecordID& objID, std::optional objDocID, std::optional tableID, std::optional documentID) const { //TODO: Implement } //ArchicadGroupDBaseEngine::write diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Property/ArchicadGroupDBaseEngine.h b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Property/ArchicadGroupDBaseEngine.h index 629ad0b..59c96c5 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Property/ArchicadGroupDBaseEngine.h +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Property/ArchicadGroupDBaseEngine.h @@ -50,11 +50,13 @@ namespace speckle::database { /*! Find a filtered list of objects @param filter The object filter (nullptr = find all objects) + @param subset A subset of the database content to search (specified by record ID) @param tableID Optional table ID (defaults to the first table) @param documentID Optional document ID (filter for this document only - nullopt = all objects) @return A list containing IDs of found elements (empty if none found) */ - virtual ObjIDList findObjects(const Filter& filter = nullptr, std::optional tableID = std::nullopt, + virtual ObjIDList findObjects(const Filter* filter = nullptr, const ObjIDList& subset = {}, + std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override { return {}; } //Implement when required /*! Get an object by ID @@ -96,7 +98,7 @@ namespace speckle::database { @param tableID Optional table ID (default selected based on record type) @param documentID Optional document ID (when the object is bound to a specific document) */ - void write(const Group& object, const BIMRecordID& objID, std::optional objDocID = std::nullopt, + void write(Group& object, const BIMRecordID& objID, std::optional objDocID = std::nullopt, std::optional tableID = std::nullopt, std::optional documentID = std::nullopt) const override; /*! Erase an object by index diff --git a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Property/ArchicadPropertyDBaseEngine.cpp b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Property/ArchicadPropertyDBaseEngine.cpp index 27e9bd6..f5d77fe 100644 --- a/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Property/ArchicadPropertyDBaseEngine.cpp +++ b/SpeckleLib/Speckle/Database/Storage/ArchicadDBase/Property/ArchicadPropertyDBaseEngine.cpp @@ -178,7 +178,7 @@ active::container::Vector