changeset 920:6435a3ad605a

Adds the feature to null the QtPtr object when the observed object is destroyed. Adds the ability to assign an ObserverPtr null.
author John Schneiderman <JohnMS@member.fsf.org>
date Mon, 07 Nov 2022 20:27:19 +0100
parents ba5b378e6f30
children 1ba4d30b337d
files src/conversion/unit-tests/CurrencyConverter-unit-tests.cpp src/desktop-ui/external/desktop-ui/CurrencyCodeWidget.h src/desktop-ui/external/desktop-ui/EventFrequencyEntryWidget.h src/desktop-ui/external/desktop-ui/MainWindow.cpp src/desktop-ui/external/desktop-ui/VerticalLabel.h src/desktop-ui/internal/AccountEntryWidget.h src/desktop-ui/internal/BankAccountsWidget.h src/desktop-ui/internal/BankEntryWidget.h src/desktop-ui/internal/BudgetItemsDueWidget.h src/desktop-ui/internal/ConfigureDialog.h src/desktop-ui/internal/DashboardWidget.h src/desktop-ui/internal/DebtEntryWidget.h src/desktop-ui/internal/GoalEntryWidget.h src/desktop-ui/internal/MonthlyTotalsWidget.h src/desktop-ui/internal/PostBudgetItemEntryWidget.h src/foundation/external/foundation/ObserverPtr.hpp src/foundation/external/foundation/QtMemory.hpp
diffstat 17 files changed, 72 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/src/conversion/unit-tests/CurrencyConverter-unit-tests.cpp	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/conversion/unit-tests/CurrencyConverter-unit-tests.cpp	Mon Nov 07 20:27:19 2022 +0100
@@ -30,6 +30,8 @@
 using drn::conversion::CurrencyConverter;
 #include <foundation/Error.h>
 using drn::foundation::Error;
+#include <foundation/QtMemory.hpp>
+using drn::foundation::QtPtr;
 
 
 namespace drn
@@ -41,6 +43,10 @@
 
 struct CurrencySourceTest : CurrencySource
 {
+	CurrencySourceTest(QtPtr<QObject> parent) :
+		CurrencySource{parent}
+	{}
+
 	QMOCK_MEMBER_FUNCTION(double, fetch, const Iso4217Codes&, const Iso4217Codes&)
 };
 
@@ -48,7 +54,7 @@
 {
 	Q_OBJECT
 
-	CurrencySourceTest source_;
+	CurrencySourceTest source_{nullptr};
 
 private slots:
 	//{ lookUp Tests
--- a/src/desktop-ui/external/desktop-ui/CurrencyCodeWidget.h	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/desktop-ui/external/desktop-ui/CurrencyCodeWidget.h	Mon Nov 07 20:27:19 2022 +0100
@@ -44,7 +44,7 @@
 {
 
 template<typename>
-struct QtPtr;;
+class QtPtr;
 
 }
 namespace desktop_ui
--- a/src/desktop-ui/external/desktop-ui/EventFrequencyEntryWidget.h	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/desktop-ui/external/desktop-ui/EventFrequencyEntryWidget.h	Mon Nov 07 20:27:19 2022 +0100
@@ -38,7 +38,7 @@
 {
 
 template<typename>
-struct QtPtr;;
+class QtPtr;
 
 }
 namespace desktop_ui
--- a/src/desktop-ui/external/desktop-ui/MainWindow.cpp	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/desktop-ui/external/desktop-ui/MainWindow.cpp	Mon Nov 07 20:27:19 2022 +0100
@@ -111,7 +111,7 @@
 
 const qint32 MainWindow::statusBarTimeOut_{5000};
 const QString MainWindow::budgetFileExtentionFilter_{
-	QObject::tr("Budget Files (%1);;All Files (*.*)").arg(budgetFileExtention_)
+	QObject::tr("Budget Files (%1);All Files (*.*)").arg(budgetFileExtention_)
 };
 
 void MainWindow::onShowAbout()
--- a/src/desktop-ui/external/desktop-ui/VerticalLabel.h	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/desktop-ui/external/desktop-ui/VerticalLabel.h	Mon Nov 07 20:27:19 2022 +0100
@@ -34,7 +34,7 @@
 {
 
 template<typename>
-struct QtPtr;;
+class QtPtr;
 
 }
 namespace desktop_ui
--- a/src/desktop-ui/internal/AccountEntryWidget.h	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/desktop-ui/internal/AccountEntryWidget.h	Mon Nov 07 20:27:19 2022 +0100
@@ -54,7 +54,7 @@
 {
 
 template<typename>
-struct QtPtr;;
+class QtPtr;
 
 }
 namespace desktop_ui
--- a/src/desktop-ui/internal/BankAccountsWidget.h	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/desktop-ui/internal/BankAccountsWidget.h	Mon Nov 07 20:27:19 2022 +0100
@@ -50,7 +50,7 @@
 template<typename>
 class Optional;
 template<typename>
-struct QtPtr;;
+class QtPtr;
 
 }
 namespace desktop_ui
--- a/src/desktop-ui/internal/BankEntryWidget.h	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/desktop-ui/internal/BankEntryWidget.h	Mon Nov 07 20:27:19 2022 +0100
@@ -44,7 +44,7 @@
 {
 
 template<typename>
-struct QtPtr;;
+class QtPtr;
 
 }
 namespace desktop_ui
--- a/src/desktop-ui/internal/BudgetItemsDueWidget.h	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/desktop-ui/internal/BudgetItemsDueWidget.h	Mon Nov 07 20:27:19 2022 +0100
@@ -42,7 +42,7 @@
 {
 
 template<typename>
-struct QtPtr;;
+class QtPtr;
 
 }
 namespace desktop_ui
--- a/src/desktop-ui/internal/ConfigureDialog.h	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/desktop-ui/internal/ConfigureDialog.h	Mon Nov 07 20:27:19 2022 +0100
@@ -39,7 +39,7 @@
 {
 
 template<typename>
-struct QtPtr;;
+class QtPtr;
 
 }
 namespace desktop_ui
--- a/src/desktop-ui/internal/DashboardWidget.h	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/desktop-ui/internal/DashboardWidget.h	Mon Nov 07 20:27:19 2022 +0100
@@ -56,7 +56,7 @@
 {
 
 template<typename>
-struct QtPtr;;
+class QtPtr;
 
 }
 namespace desktop_ui
--- a/src/desktop-ui/internal/DebtEntryWidget.h	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/desktop-ui/internal/DebtEntryWidget.h	Mon Nov 07 20:27:19 2022 +0100
@@ -65,7 +65,7 @@
 {
 
 template<typename>
-struct QtPtr;;
+class QtPtr;
 
 }
 namespace desktop_ui
--- a/src/desktop-ui/internal/GoalEntryWidget.h	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/desktop-ui/internal/GoalEntryWidget.h	Mon Nov 07 20:27:19 2022 +0100
@@ -72,7 +72,7 @@
 {
 
 template<typename>
-struct QtPtr;;
+class QtPtr;
 
 }
 namespace desktop_ui
--- a/src/desktop-ui/internal/MonthlyTotalsWidget.h	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/desktop-ui/internal/MonthlyTotalsWidget.h	Mon Nov 07 20:27:19 2022 +0100
@@ -47,7 +47,7 @@
 {
 
 template<typename>
-struct QtPtr;;
+class QtPtr;
 
 }
 namespace desktop_ui
--- a/src/desktop-ui/internal/PostBudgetItemEntryWidget.h	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/desktop-ui/internal/PostBudgetItemEntryWidget.h	Mon Nov 07 20:27:19 2022 +0100
@@ -71,7 +71,7 @@
 template<typename>
 class Optional;
 template<typename>
-struct QtPtr;;
+class QtPtr;
 
 }
 namespace desktop_ui
--- a/src/foundation/external/foundation/ObserverPtr.hpp	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/foundation/external/foundation/ObserverPtr.hpp	Mon Nov 07 20:27:19 2022 +0100
@@ -49,6 +49,7 @@
 	ObserverPtr& operator=(const ObserverPtr&) = default;
 	ObserverPtr& operator=(ObserverPtr&&) = default;
 	ObserverPtr& operator=(ObservedType* const observe);
+	ObserverPtr& operator=(const std::nullptr_t);
 	bool operator==(const std::nullptr_t) const;
 	bool operator==(const ObserverPtr& other) const;
 	bool operator==(const ObservedType* observed) const;
@@ -69,7 +70,7 @@
 	 * @brief An accessor to the object being observed.
 	 */
 	ObservedType* observed() const;
-	// TODO: add operator&
+	// TODO: add operator& // TODO: then .observed is not needed in QtMemory.
 };
 
 template<typename ObservedType>
@@ -107,6 +108,15 @@
 }
 
 template<typename ObservedType>
+drn::foundation::ObserverPtr<ObservedType>& drn::foundation::ObserverPtr<ObservedType>::operator=(
+	const std::nullptr_t
+)
+{
+	this->observed_ = nullptr;
+	return *this;
+}
+
+template<typename ObservedType>
 bool drn::foundation::ObserverPtr<ObservedType>::operator==(const std::nullptr_t) const
 {
 	return this->observed_ == nullptr;
--- a/src/foundation/external/foundation/QtMemory.hpp	Wed Nov 02 20:50:10 2022 +0100
+++ b/src/foundation/external/foundation/QtMemory.hpp	Mon Nov 07 20:27:19 2022 +0100
@@ -20,6 +20,7 @@
 #ifndef DRN_FOUNDATION_QTMEMORY_HPP_
 #define DRN_FOUNDATION_QTMEMORY_HPP_
 
+#include <QMetaObject>
 #include <QObject>
 
 #include <cassert>
@@ -38,9 +39,15 @@
 struct UniqueQtPtr;
 
 template<typename ObjectType>
-struct QtPtr : ObserverPtr<ObjectType>
+class QtPtr : public ObserverPtr<ObjectType>
 {
-	QtPtr(ObjectType* const observe = nullptr);
+	QMetaObject::Connection connection_;
+
+public:
+	QtPtr(
+		ObjectType* const observe = nullptr,
+		QMetaObject::Connection connection = {}
+	);
 	// TODO: this should not be used instead the UniqueQtPtr should be only available.
 	QtPtr(const std::unique_ptr<ObjectType>& observe);
 	QtPtr(const UniqueQtPtr<ObjectType>& observe);
@@ -48,6 +55,7 @@
 	QtPtr(QtPtr&&) noexcept = default;
 	QtPtr& operator=(const QtPtr&) = default;
 	QtPtr& operator=(QtPtr&&) noexcept = default;
+	~QtPtr();
 	using ObserverPtr<ObjectType>::observed;
 	using ObserverPtr<ObjectType>::operator*;
 	using ObserverPtr<ObjectType>::operator->;
@@ -107,35 +115,31 @@
 }}
 
 template<typename ObjectType>
-drn::foundation::QtPtr<ObjectType>::QtPtr(ObjectType* const observe) :
-	ObserverPtr<ObjectType>{observe}
-{
-	// TODO:
-	// ::QObject::connect(
-	// 	observe,
-	// 	&::QObject::destroyed,
-	// 	this,
-	// 	[this] (::QObject* obj)
-	// 	{
-	// 		assert(
-	// 			dynamic_cast<::QObject*>(this->observed()) == obj
-	// 			&& "Should be the same object being destroyed.");
-	// 		*this = nullptr;
-	// 	}
-	// );
-}
+drn::foundation::QtPtr<ObjectType>::QtPtr(
+	ObjectType* const observe,
+	QMetaObject::Connection connection
+) :
+	ObserverPtr<ObjectType>{observe},
+	connection_{connection}
+{}
 
 template<typename ObjectType>
 drn::foundation::QtPtr<ObjectType>::QtPtr(const std::unique_ptr<ObjectType>& observe) :
-	drn::foundation::QtPtr<ObjectType>{observe.get()}
+	drn::foundation::QtPtr<ObjectType>{observe.get()} // TODO: setup connection
 {}
 
 template<typename ObjectType>
 drn::foundation::QtPtr<ObjectType>::QtPtr(const UniqueQtPtr<ObjectType>& observe) :
-	drn::foundation::QtPtr<ObjectType>{observe.observed()}
+	drn::foundation::QtPtr<ObjectType>{observe.observed()} // TODO: setup connection
 {}
 
 template<typename ObjectType>
+drn::foundation::QtPtr<ObjectType>::~QtPtr()
+{
+	QObject::disconnect(this->connection_);
+}
+
+template<typename ObjectType>
 drn::foundation::UniqueQtPtr<ObjectType>::UniqueQtPtr(ObjectType* const obj) :
 	std::unique_ptr<ObjectType, void(*)(ObjectType*)>{
 		obj,
@@ -172,7 +176,22 @@
 	drn::foundation::QtPtr<BaseType>
 >::type drn::foundation::makeQtPtr(ObjectArgTypes&& ... objectArgs)
 {
+	static_assert(
+		std::is_base_of<::QObject, ObjectType>::value,
+		"Only pointers to Qt objects that can be released by Qt are allowed."
+	);
 	QtPtr<BaseType> obj{new ObjectType{std::forward<ObjectArgTypes>(objectArgs)...}};
+	auto connection{
+		::QObject::connect(
+			obj.observed(),
+			&::QObject::destroyed,
+			[obj] (::QObject* o) mutable
+			{
+				assert(obj.observed() == o && "Should be the same object being destroyed.");
+				obj = nullptr;
+			}
+		)
+	};
 	assert(obj->parent() != nullptr && "All Qt objects must have a parent.");
 	return obj;
 }