Files
speckle-cpp-connectors/SpeckleLib/Speckle/Environment/Addon.cpp
T
Ralph Wessel 4fadcaf466 Added Project class
Addon class now manages an active project instance that can be accessed with getActiveProject
GetDocumentInfo now uses information extracted from the active project
Updated ProjectSubscriber and ProjectEvent accordingly
"Send" bridge method now throws exception reporting no selected elements (placeholder until we implement a real send process)
2024-09-18 15:48:20 +01:00

219 lines
6.9 KiB
C++

#include "Speckle/Environment/Addon.h"
#include "Speckle/Environment/Project.h"
#include "Speckle/Event/Type/ProjectEvent.h"
#include <limits>
#ifdef ARCHICAD
#include <ACAPinc.h>
#endif
using namespace speckle::environment;
using namespace speckle::event;
using namespace speckle::utility;
namespace {
//An object representing the active addon
Addon* m_addonInstance = nullptr;
}
/*--------------------------------------------------------------------
Constructor (NB: this object is assumed to be the active instance)
identity: Optional name/ID for the subscriber
--------------------------------------------------------------------*/
Addon::Addon(const active::utility::NameID& identity) : App{identity, true} {
m_addonInstance = this;
} //Addon::Addon
/*--------------------------------------------------------------------
Destructor
--------------------------------------------------------------------*/
Addon::~Addon() {
m_addonInstance = nullptr;
} //Addon::~Addon
/*--------------------------------------------------------------------
Get a localised string from the add-on resources
itemIndex: The index of the string item in the resource
resourceIndex: The resource index
return: The localised string
--------------------------------------------------------------------*/
String Addon::getLocalString(short itemIndex, short resourceIndex) const {
#ifdef ARCHICAD
GS::UniString string;
RSGetIndString(&string, itemIndex, resourceIndex, ACAPI_GetOwnResModule());
return string;
#else
return String{};
#endif
} //Addon::getLocalString
/*--------------------------------------------------------------------
Get the active project
return: The active project (nullptr = no open project)
--------------------------------------------------------------------*/
std::weak_ptr<Project> Addon::getActiveProject() const {
if (m_activeProject)
return m_activeProject;
return std::weak_ptr<Project>{};
} //Addon::getActiveProject
/*--------------------------------------------------------------------
Publish an event from an external source to subscribers
event: The event to publish
--------------------------------------------------------------------*/
void Addon::publishExternal(const active::event::Event& event) {
if (!logCallback())
return;
try {
preprocessEvent(event);
publish(event);
postprocessEvent(event);
} catch (...) {
//Add error logging in future
}
} //Addon::publishExternal
/*--------------------------------------------------------------------
Audit the participant environment to ensure it can function
return: True if the participant is able to function
--------------------------------------------------------------------*/
bool Addon::audit() {
#ifdef ARCHICAD
ACAPI_KeepInMemory(true);
#endif
return App::audit();
} //Addon::audit
/*--------------------------------------------------------------------
Attach participant components to the app (as required)
return: True if the participant is able to function
--------------------------------------------------------------------*/
bool Addon::attach() {
#ifdef ARCHICAD
ACAPI_KeepInMemory(true);
#endif
return App::attach();
} //Addon::attach
/*--------------------------------------------------------------------
Initialise the participant operation
return: True if the participant is able to continue
--------------------------------------------------------------------*/
bool Addon::start() {
//Add add-on functionality as required
return App::start();
} //Addon::start
/*--------------------------------------------------------------------
Shut down event handling
--------------------------------------------------------------------*/
void Addon::stop() {
//Add add-on functionality as required
App::stop();
} //Addon::stop
/*--------------------------------------------------------------------
Get an object representing the parent process/application
return: The active application instance
--------------------------------------------------------------------*/
speckle::environment::Addon* speckle::environment::addon() {
return m_addonInstance;
} //speckle::environment::addon
/*--------------------------------------------------------------------
Log a callback into the add-on (allows checking of re-entry)
initialise: True to force this callback to be treated as the initial call (not re-entry)
return: True if the callback can continue (false on error)
--------------------------------------------------------------------*/
bool Addon::logCallback(bool initialise) {
if (initialise)
m_callDepth = 1;
else
++m_callDepth;
try {
#ifdef ARCHICAD
ACAPI_KeepInMemory(true);
#endif
//Add additional house-keeping functionality as required, e.g. retrieval of preferences
} catch (...) {
return false;
}
return true;
} //Addon::publishExternalEvent
/*--------------------------------------------------------------------
Preprocess an external event (allowing key add-on operations to act before other subscribers)
event: An incoming event
return: True if the event should be closed, i.e. not passed to other subscribers
--------------------------------------------------------------------*/
bool Addon::preprocessEvent(const active::event::Event& event) {
if (auto projectEvent = dynamic_cast<const ProjectEvent*>(&event); projectEvent != nullptr) {
using enum ProjectEvent::Type;
switch (projectEvent->getType()) {
case newDocument: case newAndReset: case open:
m_activeProject = makeProject(); //Ensure a project object is available
default:
break;
}
}
return false;
} //Addon::preprocessEvent
/*--------------------------------------------------------------------
Postprocess an external event (allowing key add-on operations to act after all other subscribers are complete)
event: An incoming (completed) event
--------------------------------------------------------------------*/
void Addon::postprocessEvent(const active::event::Event& event) {
if (auto projectEvent = dynamic_cast<const ProjectEvent*>(&event); projectEvent != nullptr) {
using enum ProjectEvent::Type;
switch (projectEvent->getType()) {
case close: case quit:
m_activeProject.reset(); //Release the active project on close/quit
default:
break;
}
}
} //Addon::postprocessEvent
/*--------------------------------------------------------------------
Make a new new project. Allows Addon subclasses to define a Project subclass with additional functions/databases
return: A new project instance
--------------------------------------------------------------------*/
std::shared_ptr<Project> Addon::makeProject() const {
auto project = new Project; //make_shared can't use protected constructor
return std::shared_ptr<Project>{project};
} //Addon::makeProject