From 77006658310f647a58648f07409ff3a4e980f3d9 Mon Sep 17 00:00:00 2001 From: James DeLisle Date: Tue, 28 Feb 2023 16:31:13 -0500 Subject: Update the bindable properties example - Fix the number of months in each duration - Move the user Country enum to use QLocale::Territory - Properly calculate the cost per month to match the UI label - Use QLocale to format the price display text - Fix some misspellings and grammar in the doc Change-Id: I78a64f344073070cd94d5cb4a8a4c7c13afa337f Reviewed-by: Paul Wicking (cherry picked from commit ed6a3ce0afe639fb40eb6f032b85e90fe35f1cb3) Reviewed-by: Qt Cherry-pick Bot --- .../bindablesubscription/bindablesubscription.cpp | 6 ++-- .../bindablesubscription/bindablesubscription.h | 2 +- .../bindablesubscription/bindableuser.h | 11 +++----- .../bindablesubscription/main.cpp | 9 +++--- .../doc/src/bindableproperties.qdoc | 32 +++++++++++----------- .../bindableproperties/subscription/main.cpp | 9 +++--- .../subscription/subscription.cpp | 6 ++-- .../bindableproperties/subscription/subscription.h | 2 +- .../corelib/bindableproperties/subscription/user.h | 13 ++++----- 9 files changed, 43 insertions(+), 47 deletions(-) (limited to 'examples') diff --git a/examples/corelib/bindableproperties/bindablesubscription/bindablesubscription.cpp b/examples/corelib/bindableproperties/bindablesubscription/bindablesubscription.cpp index 14b28b3fae..e9c57a2d29 100644 --- a/examples/corelib/bindableproperties/bindablesubscription/bindablesubscription.cpp +++ b/examples/corelib/bindableproperties/bindablesubscription/bindablesubscription.cpp @@ -60,7 +60,7 @@ BindableSubscription::BindableSubscription(BindableUser *user) : m_user(user) m_price.setBinding([this] { return qRound(calculateDiscount() * m_duration * basePrice()); }); m_isValid.setBinding([this] { - return m_user->country() != BindableUser::None && m_user->age() > 12; + return m_user->country() != BindableUser::Country::AnyCountry && m_user->age() > 12; }); } @@ -91,8 +91,8 @@ double BindableSubscription::calculateDiscount() const int BindableSubscription::basePrice() const { - if (m_user->country() == BindableUser::None) + if (m_user->country() == BindableUser::Country::AnyCountry) return 0; - return (m_user->country() == BindableUser::Norway) ? 100 : 80; + return (m_user->country() == BindableUser::Country::Norway) ? 100 : 80; } diff --git a/examples/corelib/bindableproperties/bindablesubscription/bindablesubscription.h b/examples/corelib/bindableproperties/bindablesubscription/bindablesubscription.h index 763864d627..5fab4bc91f 100644 --- a/examples/corelib/bindableproperties/bindablesubscription/bindablesubscription.h +++ b/examples/corelib/bindableproperties/bindablesubscription/bindablesubscription.h @@ -61,7 +61,7 @@ class BindableUser; class BindableSubscription { public: - enum Duration { Monthly = 1, Quarterly = 4, Yearly = 12 }; + enum Duration { Monthly = 1, Quarterly = 3, Yearly = 12 }; BindableSubscription(BindableUser *user); BindableSubscription(const BindableSubscription &) = delete; diff --git a/examples/corelib/bindableproperties/bindablesubscription/bindableuser.h b/examples/corelib/bindableproperties/bindablesubscription/bindableuser.h index 65541e6ac1..d2ab4a2d42 100644 --- a/examples/corelib/bindableproperties/bindablesubscription/bindableuser.h +++ b/examples/corelib/bindableproperties/bindablesubscription/bindableuser.h @@ -51,6 +51,7 @@ #ifndef BINDABLEUSER_H #define BINDABLEUSER_H +#include #include //! [bindable-user-class] @@ -58,13 +59,9 @@ class BindableUser { public: - enum Country { - None, - Finland, - Germany, - Norway, - }; + using Country = QLocale::Territory; +public: BindableUser() = default; BindableUser(const BindableUser &) = delete; @@ -77,7 +74,7 @@ public: QBindable bindableAge() { return &m_age; } private: - QProperty m_country { None }; + QProperty m_country { QLocale::AnyTerritory }; QProperty m_age { 0 }; }; diff --git a/examples/corelib/bindableproperties/bindablesubscription/main.cpp b/examples/corelib/bindableproperties/bindablesubscription/main.cpp index df935679ad..86f7149648 100644 --- a/examples/corelib/bindableproperties/bindablesubscription/main.cpp +++ b/examples/corelib/bindableproperties/bindablesubscription/main.cpp @@ -84,15 +84,15 @@ int main(int argc, char *argv[]) // Initialize user data QPushButton *germany = w.findChild("btnGermany"); QObject::connect(germany, &QPushButton::clicked, [&] { - user.setCountry(BindableUser::Germany); + user.setCountry(BindableUser::Country::Germany); }); QPushButton *finland = w.findChild("btnFinland"); QObject::connect(finland, &QPushButton::clicked, [&] { - user.setCountry(BindableUser::Finland); + user.setCountry(BindableUser::Country::Finland); }); QPushButton *norway = w.findChild("btnNorway"); QObject::connect(norway, &QPushButton::clicked, [&] { - user.setCountry(BindableUser::Norway); + user.setCountry(BindableUser::Country::Norway); }); QSpinBox *ageSpinBox = w.findChild("ageSpinBox"); @@ -105,7 +105,8 @@ int main(int argc, char *argv[]) // Track price changes //! [update-ui] auto priceChangeHandler = subscription.bindablePrice().subscribe([&] { - priceDisplay->setText(QString::number(subscription.price())); + QLocale lc{QLocale::AnyLanguage, user.country()}; + priceDisplay->setText(lc.toCurrencyString(subscription.price() / subscription.duration())); }); auto priceValidHandler = subscription.bindableIsValid().subscribe([&] { diff --git a/examples/corelib/bindableproperties/doc/src/bindableproperties.qdoc b/examples/corelib/bindableproperties/doc/src/bindableproperties.qdoc index 8c36921ff8..40bfe9db2a 100644 --- a/examples/corelib/bindableproperties/doc/src/bindableproperties.qdoc +++ b/examples/corelib/bindableproperties/doc/src/bindableproperties.qdoc @@ -39,7 +39,7 @@ \image bindable_properties_example.png - \section1 Modelling Subscription System with Signal/Slot Approach + \section1 Modeling Subscription System with Signal/Slot Approach Let's first consider the usual pre-Qt 6 implementation. To model the subscription service the \c Subscription class is used: @@ -72,7 +72,7 @@ \note Both methods need to check if the data is actually changed and only then emit the signals. \c setDuration() also needs to recalculate - the price, when the duration has changed. + the price when the duration has changed. The \c Subscription is not valid unless the user has a valid country and age, so the validity is updated in the following way: @@ -87,25 +87,25 @@ \snippet bindableproperties/subscription/user.cpp user-setters In the \c main() function we initialize instances of \c User and - \c Subsrcription: + \c Subscription: \snippet bindableproperties/subscription/main.cpp init - And do the proper signal-slot connections, to update the \c user and - \c subsrcription data when UI elements change. That is straightforward, + And do the proper signal-slot connections to update the \c user and + \c subscription data when UI elements change. That is straightforward, so we will skip this part. - Next, we connect to \c Subscription::priceChanged(), to update the price + Next, we connect to \c Subscription::priceChanged() to update the price in the UI when the price changes. \snippet bindableproperties/subscription/main.cpp connect-price-changed - We also connect to \c Subscription::isValidChanged(), to disable the price + We also connect to \c Subscription::isValidChanged() to disable the price display if the subscription isn't valid. \snippet bindableproperties/subscription/main.cpp connect-validity-changed - Because the subsrcription price and validity also depend on the user's + Because the subscription price and validity also depend on the user's country and age, we also need to connect to the \c User::countryChanged() and \c User::ageChanged() signals and update \c subscription accordingly. @@ -114,12 +114,12 @@ This works, but there are some problems: \list - \li There's a lot of boilerplate code for the signal-slot connections, - to be able to react to changes to \c user or \c subscription. If any of - the dependencies of the price changes, we need to remember to emit the - corresponding notifier signals, to recalculate the price and update it in + \li There's a lot of boilerplate code for the signal-slot connections + in order to properly track changes to both \c user and \c subscription. + If any of the dependencies of the price changes, we need to remember to emit the + corresponding notifier signals, recalculate the price, and update it in the UI. - \li If more dependencies for price calculation are added in future, we'll + \li If more dependencies for price calculation are added in the future, we'll need to add more signal-slot connections and make sure all the dependencies are properly updated whenever any of them changes. The overall complexity will grow, and the code will become harder to maintain. @@ -133,7 +133,7 @@ Now let's see how the \l {Qt Bindable Properties} can help to solve the same problem. First, let's have a look at the \c BindableSubscription class, - which is similar to the \c Subscription class, but is implemented using the + which is similar to the \c Subscription class, but is implemented using bindable properties: \snippet bindableproperties/bindablesubscription/bindablesubscription.h bindable-subscription-class @@ -180,7 +180,7 @@ changes the value. The subscriptions will stay alive as long as the corresponding handlers are alive. - Also note that the copy constructors of both \c BindableSubsrciption and + Also note that the copy constructors of both \c BindableSubscription and \c BindableUser are disabled, since it's not defined what should happen with their bindings when copying. @@ -190,7 +190,7 @@ \list \li The boilerplate code for the signal-slot connections is removed, the dependencies are now tracked automatically. - \li The code is easier to maintain. Adding more dependencies in future + \li The code is easier to maintain. Adding more dependencies in the future will only require adding the corresponding bindable properties and setting the binding expressions that reflect the relationships between each other. \li The \c Subscription and \c User classes don't depend on the metaobject diff --git a/examples/corelib/bindableproperties/subscription/main.cpp b/examples/corelib/bindableproperties/subscription/main.cpp index 6ff0c960f1..3252d5ebad 100644 --- a/examples/corelib/bindableproperties/subscription/main.cpp +++ b/examples/corelib/bindableproperties/subscription/main.cpp @@ -87,15 +87,15 @@ int main(int argc, char *argv[]) // Initialize user data QPushButton *germany = w.findChild("btnGermany"); QObject::connect(germany, &QPushButton::clicked, &user, [&] { - user.setCountry(User::Germany); + user.setCountry(User::Country::Germany); }); QPushButton *finland = w.findChild("btnFinland"); QObject::connect(finland, &QPushButton::clicked, &user, [&] { - user.setCountry(User::Finland); + user.setCountry(User::Country::Finland); }); QPushButton *norway = w.findChild("btnNorway"); QObject::connect(norway, &QPushButton::clicked, &user, [&] { - user.setCountry(User::Norway); + user.setCountry(User::Country::Norway); }); QSpinBox *ageSpinBox = w.findChild("ageSpinBox"); @@ -112,7 +112,8 @@ int main(int argc, char *argv[]) //! [connect-price-changed] QObject::connect(&subscription, &Subscription::priceChanged, [&] { - priceDisplay->setText(QString::number(subscription.price())); + QLocale lc{QLocale::AnyLanguage, user.country()}; + priceDisplay->setText(lc.toCurrencyString(subscription.price() / subscription.duration())); }); //! [connect-price-changed] diff --git a/examples/corelib/bindableproperties/subscription/subscription.cpp b/examples/corelib/bindableproperties/subscription/subscription.cpp index 20efe825f3..109bd16959 100644 --- a/examples/corelib/bindableproperties/subscription/subscription.cpp +++ b/examples/corelib/bindableproperties/subscription/subscription.cpp @@ -104,10 +104,10 @@ double Subscription::calculateDiscount() const int Subscription::basePrice() const { - if (m_user->country() == User::None) + if (m_user->country() == User::Country::AnyTerritory) return 0; - return (m_user->country() == User::Norway) ? 100 : 80; + return (m_user->country() == User::Country::Norway) ? 100 : 80; } //! [calculate-base-price] @@ -117,7 +117,7 @@ int Subscription::basePrice() const void Subscription::updateValidity() { bool isValid = m_isValid; - m_isValid = m_user->country() != User::None && m_user->age() > 12; + m_isValid = m_user->country() != User::Country::AnyTerritory && m_user->age() > 12; if (m_isValid != isValid) emit isValidChanged(); diff --git a/examples/corelib/bindableproperties/subscription/subscription.h b/examples/corelib/bindableproperties/subscription/subscription.h index 41d052e86f..d3121c0d26 100644 --- a/examples/corelib/bindableproperties/subscription/subscription.h +++ b/examples/corelib/bindableproperties/subscription/subscription.h @@ -62,7 +62,7 @@ class Subscription : public QObject { Q_OBJECT public: - enum Duration { Monthly = 1, Quarterly = 4, Yearly = 12 }; + enum Duration { Monthly = 1, Quarterly = 3, Yearly = 12 }; Subscription(User *user); diff --git a/examples/corelib/bindableproperties/subscription/user.h b/examples/corelib/bindableproperties/subscription/user.h index 8c9ebb1009..223e660f62 100644 --- a/examples/corelib/bindableproperties/subscription/user.h +++ b/examples/corelib/bindableproperties/subscription/user.h @@ -51,6 +51,7 @@ #ifndef USER_H #define USER_H +#include #include //! [user-class] @@ -60,13 +61,9 @@ class User : public QObject Q_OBJECT public: - enum Country { - None, - Finland, - Germany, - Norway, - }; + using Country = QLocale::Territory; +public: Country country() const { return m_country; } void setCountry(Country country); @@ -78,8 +75,8 @@ signals: void ageChanged(); private: - Country m_country = Country::None; - int m_age = 0; + Country m_country { QLocale::AnyTerritory }; + int m_age { 0 }; }; //! [user-class] -- cgit v1.2.3