Skip to content

Commit

Permalink
App/Gui: implement a lightweight weak_ptr like class to work with Doc…
Browse files Browse the repository at this point in the history
…ument, DocumentObject and ViewProvider
  • Loading branch information
wwmayer committed Feb 19, 2020
1 parent e3b5b0b commit b34f0ae
Show file tree
Hide file tree
Showing 4 changed files with 418 additions and 1 deletion.
133 changes: 133 additions & 0 deletions src/App/DocumentObserver.cpp
Expand Up @@ -257,6 +257,7 @@ Property *DocumentObjectT::getProperty() const {
return obj->getPropertyByName(property.c_str());
return 0;
}

// -----------------------------------------------------------------------------

SubObjectT::SubObjectT()
Expand Down Expand Up @@ -387,6 +388,138 @@ std::vector<App::DocumentObject*> SubObjectT::getSubObjectList() const {
}

// -----------------------------------------------------------------------------

class DocumentWeakPtrT::Private {
public:
Private(App::Document* doc) : _document(doc) {
if (doc) {
connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(boost::bind
(&Private::deletedDocument, this, _1));
}
}

void deletedDocument(const App::Document& doc) {
if (_document == &doc)
reset();
}
void reset() {
connectApplicationDeletedDocument.disconnect();
_document = nullptr;
}

App::Document* _document;
typedef boost::signals2::scoped_connection Connection;
Connection connectApplicationDeletedDocument;
};

DocumentWeakPtrT::DocumentWeakPtrT(App::Document* doc) noexcept
: d(new Private(doc))
{
}

DocumentWeakPtrT::~DocumentWeakPtrT()
{
}

void DocumentWeakPtrT::reset() noexcept
{
d->reset();
}

bool DocumentWeakPtrT::expired() const noexcept
{
return (d->_document == nullptr);
}

App::Document* DocumentWeakPtrT::operator->() noexcept
{
return d->_document;
}

// -----------------------------------------------------------------------------

class DocumentObjectWeakPtrT::Private {
public:
Private(App::DocumentObject* obj) : object(obj), indocument(false) {
if (obj) {
indocument = true;
connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(boost::bind
(&Private::deletedDocument, this, _1));
App::Document* doc = obj->getDocument();
connectDocumentCreatedObject = doc->signalNewObject.connect(boost::bind
(&Private::createdObject, this, _1));
connectDocumentDeletedObject = doc->signalDeletedObject.connect(boost::bind
(&Private::deletedObject, this, _1));
}
}
void deletedDocument(const App::Document& doc) {
// When deleting document then there is no way to undo it
if (object && object->getDocument() == &doc) {
reset();
}
}
void createdObject(const App::DocumentObject& obj) {
// When undoing the removal
if (object == &obj) {
indocument = true;
}
}
void deletedObject(const App::DocumentObject& obj) {
if (object == &obj) {
indocument = false;
}
}
void reset() {
connectApplicationDeletedDocument.disconnect();
connectDocumentCreatedObject.disconnect();
connectDocumentDeletedObject.disconnect();
object = nullptr;
indocument = false;
}
App::DocumentObject* get() const {
return indocument ? object : nullptr;
}

App::DocumentObject* object;
bool indocument;
typedef boost::signals2::scoped_connection Connection;
Connection connectApplicationDeletedDocument;
Connection connectDocumentCreatedObject;
Connection connectDocumentDeletedObject;
};

DocumentObjectWeakPtrT::DocumentObjectWeakPtrT(App::DocumentObject* obj) noexcept
: d(new Private(obj))
{
}

DocumentObjectWeakPtrT::~DocumentObjectWeakPtrT()
{

}

App::DocumentObject* DocumentObjectWeakPtrT::_get() const noexcept
{
return d->get();
}

void DocumentObjectWeakPtrT::reset() noexcept
{
d->reset();
}

bool DocumentObjectWeakPtrT::expired() const noexcept
{
return !d->indocument;
}

App::DocumentObject* DocumentObjectWeakPtrT::operator->() noexcept
{
return d->get();
}

// -----------------------------------------------------------------------------

DocumentObserver::DocumentObserver() : _document(0)
{
this->connectApplicationCreatedDocument = App::GetApplication().signalNewDocument.connect(boost::bind
Expand Down
79 changes: 78 additions & 1 deletion src/App/DocumentObserver.h
Expand Up @@ -27,6 +27,7 @@
#include <Base/BaseClass.h>
#include <boost/signals2.hpp>
#include <set>
#include <memory>

namespace App
{
Expand Down Expand Up @@ -144,7 +145,7 @@ class AppExport DocumentObjectT
std::string property;
};

class AppExport SubObjectT: public DocumentObjectT
class AppExport SubObjectT : public DocumentObjectT
{
public:
/*! Constructor */
Expand Down Expand Up @@ -205,6 +206,82 @@ class AppExport SubObjectT: public DocumentObjectT
std::string subname;
};

/**
* @brief The DocumentWeakPtrT class
*/
class AppExport DocumentWeakPtrT
{
public:
DocumentWeakPtrT(App::Document*) noexcept;
~DocumentWeakPtrT();

/*!
* \brief reset
* Releases the reference to the managed object. After the call *this manages no object.
*/
void reset() noexcept;
/*!
* \brief expired
* \return true if the managed object has already been deleted, false otherwise.
*/
bool expired() const noexcept;
/*!
* \brief operator ->
* \return pointer to the document
*/
App::Document* operator->() noexcept;

private:
// disable
DocumentWeakPtrT(const DocumentWeakPtrT&);
DocumentWeakPtrT& operator=(const DocumentWeakPtrT&);

class Private;
std::unique_ptr<Private> d;
};

/**
* @brief The DocumentObjectWeakPtrT class
*/
class AppExport DocumentObjectWeakPtrT
{
public:
DocumentObjectWeakPtrT(App::DocumentObject*) noexcept;
~DocumentObjectWeakPtrT();

/*!
* \brief reset
* Releases the reference to the managed object. After the call *this manages no object.
*/
void reset() noexcept;
/*!
* \brief expired
* \return true if the managed object has already been deleted, false otherwise.
*/
bool expired() const noexcept;
/*!
* \brief operator ->
* \return pointer to the document
*/
App::DocumentObject* operator->() noexcept;
/*! Get a pointer to the object or 0 if it doesn't exist any more or the type doesn't match. */
template<typename T>
inline T* get() const noexcept
{
return Base::freecad_dynamic_cast<T>(_get());
}

private:
App::DocumentObject* _get() const noexcept;
// disable
DocumentObjectWeakPtrT(const DocumentObjectWeakPtrT&);
DocumentObjectWeakPtrT& operator=(const DocumentObjectWeakPtrT&);

private:
class Private;
std::unique_ptr<Private> d;
};

/**
* The DocumentObserver class simplfies the step to write classes that listen
* to what happens inside a document.
Expand Down
131 changes: 131 additions & 0 deletions src/Gui/DocumentObserver.cpp
Expand Up @@ -199,6 +199,137 @@ std::string ViewProviderT::getObjectPython() const

// -----------------------------------------------------------------------------

class DocumentWeakPtrT::Private {
public:
Private(Gui::Document* doc) : _document(doc) {
if (doc) {
connectApplicationDeletedDocument = doc->signalDeleteDocument.connect(boost::bind
(&Private::deletedDocument, this, _1));
}
}

void deletedDocument(const Gui::Document& doc) {
if (_document == &doc)
reset();
}
void reset() {
connectApplicationDeletedDocument.disconnect();
_document = nullptr;
}

Gui::Document* _document;
typedef boost::signals2::scoped_connection Connection;
Connection connectApplicationDeletedDocument;
};

DocumentWeakPtrT::DocumentWeakPtrT(Gui::Document* doc) noexcept
: d(new Private(doc))
{
}

DocumentWeakPtrT::~DocumentWeakPtrT()
{
}

void DocumentWeakPtrT::reset() noexcept
{
d->reset();
}

bool DocumentWeakPtrT::expired() const noexcept
{
return (d->_document == nullptr);
}

Gui::Document* DocumentWeakPtrT::operator->() noexcept
{
return d->_document;
}

// -----------------------------------------------------------------------------

class ViewProviderWeakPtrT::Private {
public:
Private(ViewProviderDocumentObject* obj) : object(obj), indocument(false) {
if (obj) {
indocument = true;
Gui::Document* doc = obj->getDocument();
connectApplicationDeletedDocument = doc->signalDeleteDocument.connect(boost::bind
(&Private::deletedDocument, this, _1));
connectDocumentCreatedObject = doc->signalNewObject.connect(boost::bind
(&Private::createdObject, this, _1));
connectDocumentDeletedObject = doc->signalDeletedObject.connect(boost::bind
(&Private::deletedObject, this, _1));
}
}
void deletedDocument(const Gui::Document& doc) {
// When deleting document then there is no way to undo it
if (object && object->getDocument() == &doc) {
reset();
}
}
void createdObject(const Gui::ViewProvider& obj) {
// When undoing the removal
if (object == &obj) {
indocument = true;
}
}
void deletedObject(const Gui::ViewProvider& obj) {
if (object == &obj) {
indocument = false;
}
}
void reset() {
connectApplicationDeletedDocument.disconnect();
connectDocumentCreatedObject.disconnect();
connectDocumentDeletedObject.disconnect();
object = nullptr;
indocument = false;
}
ViewProviderDocumentObject* get() const {
return indocument ? object : nullptr;
}

Gui::ViewProviderDocumentObject* object;
bool indocument;
typedef boost::signals2::scoped_connection Connection;
Connection connectApplicationDeletedDocument;
Connection connectDocumentCreatedObject;
Connection connectDocumentDeletedObject;
};

ViewProviderWeakPtrT::ViewProviderWeakPtrT(ViewProviderDocumentObject* obj) noexcept
: d(new Private(obj))
{
}

ViewProviderWeakPtrT::~ViewProviderWeakPtrT()
{

}

ViewProviderDocumentObject* ViewProviderWeakPtrT::_get() const noexcept
{
return d->get();
}

void ViewProviderWeakPtrT::reset() noexcept
{
d->reset();
}

bool ViewProviderWeakPtrT::expired() const noexcept
{
return !d->indocument;
}

ViewProviderDocumentObject* ViewProviderWeakPtrT::operator->() noexcept
{
return d->get();
}

// -----------------------------------------------------------------------------

DocumentObserver::DocumentObserver()
{
}
Expand Down

0 comments on commit b34f0ae

Please sign in to comment.