From 454fe91c3c4573b3a4139d984c742eeba968af68 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 19 Feb 2020 19:58:34 +0100 Subject: [PATCH] App/Gui: implement a lightweight weak_ptr like class to work with Document, DocumentObject and ViewProvider --- src/App/DocumentObserver.cpp | 133 +++++++++++++++++++++++++++++++++++ src/App/DocumentObserver.h | 79 ++++++++++++++++++++- src/Gui/DocumentObserver.cpp | 131 ++++++++++++++++++++++++++++++++++ src/Gui/DocumentObserver.h | 76 ++++++++++++++++++++ 4 files changed, 418 insertions(+), 1 deletion(-) diff --git a/src/App/DocumentObserver.cpp b/src/App/DocumentObserver.cpp index c88043d628..e6650d5060 100644 --- a/src/App/DocumentObserver.cpp +++ b/src/App/DocumentObserver.cpp @@ -257,6 +257,7 @@ Property *DocumentObjectT::getProperty() const { return obj->getPropertyByName(property.c_str()); return 0; } + // ----------------------------------------------------------------------------- SubObjectT::SubObjectT() @@ -387,6 +388,138 @@ std::vector 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 diff --git a/src/App/DocumentObserver.h b/src/App/DocumentObserver.h index dcf7936304..eae3295755 100644 --- a/src/App/DocumentObserver.h +++ b/src/App/DocumentObserver.h @@ -27,6 +27,7 @@ #include #include #include +#include namespace App { @@ -144,7 +145,7 @@ private: std::string property; }; -class AppExport SubObjectT: public DocumentObjectT +class AppExport SubObjectT : public DocumentObjectT { public: /*! Constructor */ @@ -205,6 +206,82 @@ private: 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 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 + inline T* get() const noexcept + { + return Base::freecad_dynamic_cast(_get()); + } + +private: + App::DocumentObject* _get() const noexcept; + // disable + DocumentObjectWeakPtrT(const DocumentObjectWeakPtrT&); + DocumentObjectWeakPtrT& operator=(const DocumentObjectWeakPtrT&); + +private: + class Private; + std::unique_ptr d; +}; + /** * The DocumentObserver class simplfies the step to write classes that listen * to what happens inside a document. diff --git a/src/Gui/DocumentObserver.cpp b/src/Gui/DocumentObserver.cpp index 7de3ccf928..2267c5dc95 100644 --- a/src/Gui/DocumentObserver.cpp +++ b/src/Gui/DocumentObserver.cpp @@ -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() { } diff --git a/src/Gui/DocumentObserver.h b/src/Gui/DocumentObserver.h index 9f62ed4532..c25d8841dc 100644 --- a/src/Gui/DocumentObserver.h +++ b/src/Gui/DocumentObserver.h @@ -118,6 +118,82 @@ private: std::string object; }; +/** + * @brief The DocumentWeakPtrT class + */ +class GuiExport DocumentWeakPtrT +{ +public: + DocumentWeakPtrT(Gui::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 + */ + Gui::Document* operator->() noexcept; + +private: + // disable + DocumentWeakPtrT(const DocumentWeakPtrT&); + DocumentWeakPtrT& operator=(const DocumentWeakPtrT&); + + class Private; + std::unique_ptr d; +}; + +/** + * @brief The ViewProviderWeakPtrT class + */ +class AppExport ViewProviderWeakPtrT +{ +public: + ViewProviderWeakPtrT(ViewProviderDocumentObject*) noexcept; + ~ViewProviderWeakPtrT(); + + /*! + * \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 + */ + ViewProviderDocumentObject* operator->() noexcept; + /*! Get a pointer to the object or 0 if it doesn't exist any more or the type doesn't match. */ + template + inline T* get() const noexcept + { + return Base::freecad_dynamic_cast(_get()); + } + +private: + ViewProviderDocumentObject* _get() const noexcept; + // disable + ViewProviderWeakPtrT(const ViewProviderWeakPtrT&); + ViewProviderWeakPtrT& operator=(const ViewProviderWeakPtrT&); + +private: + class Private; + std::unique_ptr d; +}; + /** * The DocumentObserver class simplifies the step to write classes that listen * to what happens inside a document.