KDDockWidgets API Documentation 2.1
Loading...
Searching...
No Matches
property.h
Go to the documentation of this file.
1/*
2 This file is part of KDBindings.
3
4 SPDX-FileCopyrightText: 2021-2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5 Author: Sean Harmer <sean.harmer@kdab.com>
6
7 SPDX-License-Identifier: MIT
8
9 Contact KDAB at <info@kdab.com> for commercial licensing options.
10*/
11
12#pragma once
13
15#include <kdbindings/signal.h>
16
17#include <iostream>
18#include <memory>
19#include <type_traits>
20
21namespace KDBindings {
22
30namespace Private {
31
32template<typename X, typename Y, typename = void>
33struct are_equality_comparable : std::false_type {
34};
35
36template<typename X, typename Y>
39 std::is_same<
40 std::decay_t<
41 decltype(std::equal_to<>{}(std::declval<X>(), std::declval<Y>()))>,
42 bool>::value>> : std::true_type {
43};
44
45template<typename X, typename Y>
47
48} // namespace Private
49
56struct ReadOnlyProperty : std::runtime_error {
57 ReadOnlyProperty() = delete;
58
59 using std::runtime_error::runtime_error;
60};
61
77template<typename T>
78struct equal_to {
86 auto operator()(const T &x, const T &y) const noexcept
87 -> std::enable_if_t<Private::are_equality_comparable_v<T, T>, bool>
88 {
89 return std::equal_to<>{}(x, y);
90 }
91
99 template<typename X, typename Y>
100 auto operator()(const X &, const Y &) const noexcept
101 -> std::enable_if_t<!Private::are_equality_comparable_v<X, Y>, bool>
102 {
103 return false;
104 }
105};
106
107// This forwrad declaration is required so that
108// Property can declare PropertyNode as a friend
109// class.
110namespace Private {
111 template<typename PropertyType>
112 class PropertyNode;
113}
114
136template<typename T>
138{
139public:
140 typedef T valuetype;
141
147 Property() = default;
148
153 {
154 m_destroyed.emit();
155 }
156
160 explicit Property(T value) noexcept(std::is_nothrow_move_constructible<T>::value)
161 : m_value{ std::move(value) }
162 {
163 }
164
168 Property(Property<T> const &other) = delete;
169 Property &operator=(Property<T> const &other) = delete;
170
180 Property(Property<T> &&other) noexcept(std::is_nothrow_move_constructible<T>::value)
181 : m_value(std::move(other.m_value))
182 , m_valueAboutToChange(std::move(other.m_valueAboutToChange))
183 , m_valueChanged(std::move(other.m_valueChanged))
184 , m_destroyed(std::move(other.m_destroyed))
185 , m_updater(std::move(other.m_updater))
186 {
187 // We do not move the m_moved signal yet so that objects interested in the moved-into
188 // property can recreate any connections they need.
189
190 // If we have an updater, let it know how to update our internal value
191 if (m_updater) {
192 using namespace std::placeholders;
193 m_updater->setUpdateFunction(
194 std::bind(&Property<T>::setHelper, this, _1));
195 }
196
197 // Emit the moved signals for the moved from and moved to properties
198 m_moved.emit(*this);
199 other.m_moved.emit(*this);
200 m_moved = std::move(other.m_moved);
201 }
202
206 Property &operator=(Property<T> &&other) noexcept(std::is_nothrow_move_assignable<T>::value)
207 {
208 // We do not move the m_moved signal yet so that objects interested in the moved-into
209 // property can recreate any connections they need.
210 m_value = std::move(other.m_value);
211 m_valueAboutToChange = std::move(other.m_valueAboutToChange);
212 m_valueChanged = std::move(other.m_valueChanged);
213 m_destroyed = std::move(other.m_destroyed);
214 m_updater = std::move(other.m_updater);
215
216 // If we have an updater, let it know how to update our internal value
217 if (m_updater) {
218 using namespace std::placeholders;
219 m_updater->setUpdateFunction(
220 std::bind(&Property<T>::setHelper, this, _1));
221 }
222
223 // Emit the moved signals for the moved from and moved to properties
224 m_moved.emit(*this);
225 other.m_moved.emit(*this);
226 m_moved = std::move(other.m_moved);
227
228 return *this;
229 }
230
237 template<typename UpdaterT>
238 explicit Property(std::unique_ptr<UpdaterT> &&updater)
239 {
240 *this = std::move(updater);
241 }
242
254 template<typename UpdaterT>
255 Property &operator=(std::unique_ptr<UpdaterT> &&updater)
256 {
257 m_updater = std::move(updater);
258
259 // Let the updater know how to update our internal value
260 using namespace std::placeholders;
261 m_updater->setUpdateFunction(
262 std::bind(&Property<T>::setHelper, this, _1));
263
264 // Now synchronise our value with whatever the updator has right now.
265 setHelper(m_updater->get());
266
267 return *this;
268 }
269
278 void reset()
279 {
280 m_updater.reset();
281 }
282
289 Signal<const T &, const T &> &valueAboutToChange() const { return m_valueAboutToChange; }
290
296 Signal<const T &> &valueChanged() const { return m_valueChanged; }
297
301 Signal<> &destroyed() const { return m_destroyed; }
302
317 void set(T value)
318 {
319 if (m_updater) {
320 throw ReadOnlyProperty{
321 "Cannot set value on a read-only property. This property likely holds the result of a binding expression."
322 };
323 }
324 setHelper(std::move(value));
325 }
326
330 T const &get() const
331 {
332 return m_value;
333 }
334
340 Property<T> &operator=(T const &rhs)
341 {
342 set(std::move(rhs));
343 return *this;
344 }
345
351 T const &operator()() const
352 {
353 return Property<T>::get();
354 }
355
356private:
357 void setHelper(T value)
358 {
359 if (equal_to<T>{}(value, m_value))
360 return;
361
362 m_valueAboutToChange.emit(m_value, value);
363 m_value = std::move(value);
364 m_valueChanged.emit(m_value);
365 }
366
367 T m_value;
368 // the signals in a property are mutable, as a property
369 // being "const" should mean that it's value or binding does
370 // not change, not that nobody can listen to it anymore.
371 mutable Signal<const T &, const T &> m_valueAboutToChange;
372 mutable Signal<const T &> m_valueChanged; // By const ref so we can emit the signal for move-only types of T e.g. std::unique_ptr<int>
373
374 // The PropertyNode needs to be a friend class of the Property, as it needs
375 // access to the m_moved Signal.
376 // The decision to make this Signal private was made after the suggestion by
377 // @jm4R who reported issues with the move constructors noexcept guarantee.
378 // (https://github.com/KDAB/KDBindings/issues/24)
379 // Ideally we would like to figure out a way to remove the moved signal entirely
380 // at some point. However currently it is still needed for Property bindings to
381 // keep track of moved Properties.
382 template<typename PropertyType>
384 Signal<Property<T> &> m_moved;
385
386 mutable Signal<> m_destroyed;
387 std::unique_ptr<PropertyUpdater<T>> m_updater;
388};
389
393template<typename T>
394std::ostream &operator<<(std::ostream &stream, Property<T> const &property)
395{
396 stream << property.get();
397 return stream;
398}
399
404template<typename T>
405std::istream &operator>>(std::istream &stream, Property<T> &prop)
406{
407 T temp;
408 stream >> temp;
409 prop.set(std::move(temp));
410 return stream;
411}
412
413namespace Private {
414
415template<typename T>
416struct is_property_helper : std::false_type {
417};
418
419template<typename T>
420struct is_property_helper<Property<T>> : std::true_type {
421};
422
423template<typename T>
424struct is_property : is_property_helper<std::decay_t<T>> {
425};
426
427} // namespace Private
428
455} // namespace KDBindings
A property represents a value that can be part of or the result of data binding.
Definition property.h:138
Property & operator=(std::unique_ptr< UpdaterT > &&updater)
Definition property.h:255
Property(Property< T > const &other)=delete
void reset()
Disconnects the binding from this Property.
Definition property.h:278
void set(T value)
Definition property.h:317
Signal< const T &, const T & > & valueAboutToChange() const
Definition property.h:289
Signal< const T & > & valueChanged() const
Definition property.h:296
T const & get() const
Definition property.h:330
Property & operator=(Property< T > const &other)=delete
Signal & destroyed() const
Definition property.h:301
Property< T > & operator=(T const &rhs)
Definition property.h:340
Property(Property< T > &&other) noexcept(std::is_nothrow_move_constructible< T >::value)
Properties are movable.
Definition property.h:180
Property(std::unique_ptr< UpdaterT > &&updater)
Definition property.h:238
T const & operator()() const
Definition property.h:351
Property(T value) noexcept(std::is_nothrow_move_constructible< T >::value)
Definition property.h:160
Property & operator=(Property< T > &&other) noexcept(std::is_nothrow_move_assignable< T >::value)
Definition property.h:206
A Signal provides a mechanism for communication between objects.
Definition signal.h:218
void emit(Args... p) const
Definition signal.h:491
constexpr bool are_equality_comparable_v
Definition property.h:46
typename operator_node_result< Operator, Ts... >::type operator_node_result_t
Definition make_node.h:57
The main namespace of the KDBindings library.
Definition binding.h:21
std::ostream & operator<<(std::ostream &stream, Property< T > const &property)
Definition property.h:394
std::istream & operator>>(std::istream &stream, Property< T > &prop)
Definition property.h:405
Definition utils.h:161
An instance of the KDBindings::equal_to struct is used to decide whether two values of type T are equ...
Definition property.h:78
auto operator()(const T &x, const T &y) const noexcept -> std::enable_if_t< Private::are_equality_comparable_v< T, T >, bool >
Definition property.h:86
auto operator()(const X &, const Y &) const noexcept -> std::enable_if_t<!Private::are_equality_comparable_v< X, Y >, bool >
Definition property.h:100

© Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
KDDockWidgets
Advanced Dock Widget Framework for Qt
https://www.kdab.com/development-resources/qt-tools/kddockwidgets/
Generated by doxygen 1.9.8