Added DocStoreSubscriber
Added DocStoreMergeEvent DocumentStoreCore now handles merge events Fixes to SelectionSubscriber
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include "Active/Utility/Memory.h"
|
||||
#include "Active/Utility/String.h"
|
||||
#include "Speckle/Environment/Addon.h"
|
||||
#include "Speckle/Event/Type/DocStoreMergeEvent.h"
|
||||
#include "Speckle/Utility/Guid.h"
|
||||
#include "Speckle/Utility/String.h"
|
||||
|
||||
@@ -14,6 +15,7 @@
|
||||
using namespace active::setting;
|
||||
using namespace speckle::database;
|
||||
using namespace speckle::environment;
|
||||
using namespace speckle::event;
|
||||
using namespace speckle::utility;
|
||||
|
||||
using enum DocumentStoreCore::Status;
|
||||
@@ -55,16 +57,27 @@ namespace {
|
||||
if (storeID.id)
|
||||
return true; //We must have a store if the ID is populated
|
||||
bool isStoreFound = false;
|
||||
#ifdef ARCHICAD
|
||||
API_Guid acID;
|
||||
if (auto statusCode = convertArchicadError(ACAPI_AddOnObject_GetObjectGuidFromName(String{storeID.name}, &acID)); statusCode != nominal)
|
||||
throw std::system_error(DocumentStoreCore::makeError(statusCode));
|
||||
storeID.id = Guid{acID};
|
||||
isStoreFound = true;
|
||||
#endif
|
||||
return isStoreFound;
|
||||
} //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
|
||||
@@ -111,6 +124,30 @@ std::error_code DocumentStoreCore::makeError(DocumentStoreCore::Status code) {
|
||||
} //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
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Read the data stored in the document
|
||||
|
||||
@@ -128,9 +165,7 @@ active::utility::Memory DocumentStoreCore::readStore() const {
|
||||
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
|
||||
auto storeSize = BMGetHandleSize(storedData);
|
||||
result.resize(storeSize);
|
||||
active::utility::Memory::copy(result.data(), *storedData, storeSize, storeSize);
|
||||
copyHandleToMemory(storedData, result);
|
||||
BMKillHandle(&storedData);
|
||||
#endif
|
||||
return result;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Active/Setting/SettingList.h"
|
||||
#include "Active/Database/Storage/DBaseSchema.h"
|
||||
#include "Active/Utility/NameID.h"
|
||||
#include "Speckle/Event/Subscriber/DocStoreSubscriber.h"
|
||||
|
||||
namespace speckle::database {
|
||||
|
||||
@@ -13,7 +14,7 @@ namespace speckle::database {
|
||||
|
||||
Currently implement for Archicad Add-On Objects
|
||||
*/
|
||||
class DocumentStoreCore {
|
||||
class DocumentStoreCore : public event::DocStoreSubscriber {
|
||||
public:
|
||||
|
||||
// MARK: - Types
|
||||
@@ -54,6 +55,15 @@ namespace speckle::database {
|
||||
*/
|
||||
const active::utility::NameID& getID() const { return m_id; }
|
||||
|
||||
// MARK: - Functions (mutating)
|
||||
|
||||
/*!
|
||||
Handle a document merge operation
|
||||
@param event The merge event
|
||||
@return True if the event should be closed
|
||||
*/
|
||||
bool handle(const event::DocStoreMergeEvent& event) override;
|
||||
|
||||
protected:
|
||||
/*!
|
||||
Read the data stored in the document (should be lazy-loading, only at the point where data is actually requested)
|
||||
@@ -73,9 +83,8 @@ namespace speckle::database {
|
||||
/*!
|
||||
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
|
||||
*/
|
||||
virtual active::utility::Memory mergeStore(const active::utility::Memory& toMerge) = 0;
|
||||
virtual void mergeStore(const active::utility::Memory& toMerge) = 0;
|
||||
/*!
|
||||
Reset the stored data (some external change has invalidated previous data, e.g. the document was closed)
|
||||
*/
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace speckle::database {
|
||||
@param toMerge The external stored data to merge
|
||||
@return The merged data to be stored
|
||||
*/
|
||||
active::utility::Memory mergeStore(const active::utility::Memory& toMerge) override;
|
||||
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)
|
||||
*/
|
||||
@@ -266,7 +266,7 @@ namespace speckle::database {
|
||||
--------------------------------------------------------------------*/
|
||||
template<typename Obj, typename Transport, typename ObjID>
|
||||
requires DocumentStorable<Obj, Transport>
|
||||
active::utility::Memory DocumentStoreEngine<Obj, Transport, ObjID>::mergeStore(const active::utility::Memory& toMerge) {
|
||||
void DocumentStoreEngine<Obj, Transport, ObjID>::mergeStore(const active::utility::Memory& toMerge) {
|
||||
//Import the incoming records from the data to merge
|
||||
Cache incoming;
|
||||
Transport().receive(std::forward<active::serialise::Cargo&&>(incoming), active::serialise::Identity{}, toMerge);
|
||||
@@ -275,7 +275,6 @@ namespace speckle::database {
|
||||
if (!cache)
|
||||
cache = std::make_unique<Cache>(); //We still want to export an empty cache object even if it contains no records
|
||||
cache->merge(incoming);
|
||||
return buildStore();
|
||||
} //DocumentStoreEngine<Obj, Transport, ObjID>::mergeStore
|
||||
|
||||
}
|
||||
|
||||
@@ -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 <ACAPinc.h>
|
||||
#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<API_AddonObject>& 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 selectEvent = dynamic_cast<const DocStoreMergeEvent*>(&event); selectEvent != nullptr)
|
||||
return handle(*selectEvent);
|
||||
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
|
||||
@@ -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 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
|
||||
@@ -4,6 +4,10 @@
|
||||
#include "Speckle/Database/Identity/Link.h"
|
||||
#include "Speckle/Event/Type/SelectionEvent.h"
|
||||
|
||||
#ifdef ARCHICAD
|
||||
#include <ACAPinc.h>
|
||||
#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
|
||||
|
||||
@@ -3,16 +3,12 @@
|
||||
|
||||
#include "Active/Event/Subscriber.h"
|
||||
|
||||
#ifdef ARCHICAD
|
||||
#include <ACAPinc.h>
|
||||
#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 {
|
||||
public:
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#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"
|
||||
#include "Speckle/Database/Identity/Link.h"
|
||||
|
||||
namespace speckle::event {
|
||||
|
||||
/*!
|
||||
Class representing a selection change event
|
||||
*/
|
||||
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<API_AddonObject>& incoming) : Event{ID} { objects = &incoming; }
|
||||
#endif
|
||||
|
||||
#ifdef ARCHICAD
|
||||
//Incoming document objects to merge
|
||||
const GS::Array<API_AddonObject>* objects = nullptr;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //SPECKLE_EVENT_DOC_STORE_MERGE_EVENT
|
||||
@@ -40,6 +40,8 @@
|
||||
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 */; };
|
||||
21D0BDBF2C90F36B0077E104 /* DocStoreMergeEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 21D0BDBE2C90F36B0077E104 /* DocStoreMergeEvent.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 */; };
|
||||
@@ -138,6 +140,9 @@
|
||||
21D0BDAC2C8F8AB60077E104 /* DocumentStoreCore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentStoreCore.cpp; sourceTree = "<group>"; };
|
||||
21D0BDAD2C8F8AB60077E104 /* DocumentStoreCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DocumentStoreCore.h; sourceTree = "<group>"; };
|
||||
21D0BDAE2C8F8AB60077E104 /* DocumentStoreEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DocumentStoreEngine.h; sourceTree = "<group>"; };
|
||||
21D0BDBA2C90F2830077E104 /* DocStoreSubscriber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DocStoreSubscriber.h; sourceTree = "<group>"; };
|
||||
21D0BDBB2C90F2830077E104 /* DocStoreSubscriber.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocStoreSubscriber.cpp; sourceTree = "<group>"; };
|
||||
21D0BDBE2C90F36B0077E104 /* DocStoreMergeEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DocStoreMergeEvent.h; sourceTree = "<group>"; };
|
||||
21F69F012C66C229008B6A06 /* Doxyfile */ = {isa = PBXFileReference; lastKnownFileType = text; name = Doxyfile; path = Documentation/Doxyfile; sourceTree = "<group>"; };
|
||||
21F69F192C6A0FE2008B6A06 /* JSBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBinding.h; sourceTree = "<group>"; };
|
||||
21F69F352C6AA9B3008B6A06 /* JSFunction.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSFunction.h; sourceTree = "<group>"; };
|
||||
@@ -254,6 +259,8 @@
|
||||
2193517A2C624FC100E5A69C /* Subscriber */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
21D0BDBB2C90F2830077E104 /* DocStoreSubscriber.cpp */,
|
||||
21D0BDBA2C90F2830077E104 /* DocStoreSubscriber.h */,
|
||||
219351782C624FC100E5A69C /* MenuSubscriber.cpp */,
|
||||
219351792C624FC100E5A69C /* MenuSubscriber.h */,
|
||||
219351992C6278D900E5A69C /* SelectionSubscriber.cpp */,
|
||||
@@ -265,6 +272,7 @@
|
||||
2193518A2C62655700E5A69C /* Type */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
21D0BDBE2C90F36B0077E104 /* DocStoreMergeEvent.h */,
|
||||
219351892C62655700E5A69C /* MenuEvent.h */,
|
||||
2193519C2C627E3100E5A69C /* SelectionEvent.h */,
|
||||
);
|
||||
@@ -462,6 +470,7 @@
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
21D0BDBF2C90F36B0077E104 /* DocStoreMergeEvent.h in Headers */,
|
||||
21D0BD212C86F0280077E104 /* AccountDatabase.h in Headers */,
|
||||
210CC86F2C7E879700610F58 /* ArgumentBase.h in Headers */,
|
||||
210CC8A02C81E34400610F58 /* Platform.h in Headers */,
|
||||
@@ -608,6 +617,7 @@
|
||||
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 */,
|
||||
|
||||
Reference in New Issue
Block a user