diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp index 55cbfc6590b..fd4e5f42cf4 100644 --- a/libgnucash/engine/Account.cpp +++ b/libgnucash/engine/Account.cpp @@ -2482,7 +2482,28 @@ xaccAccountSetDescription (Account *acc, const char *str) } static void -set_kvp_string_path (Account *acc, std::vector const & path, +set_kvp_gnc_numeric_path (Account *acc, const std::vector& path, + std::optional value) +{ + g_return_if_fail(GNC_IS_ACCOUNT(acc)); + + xaccAccountBeginEdit(acc); + if (value.has_value()) + { + GValue v = G_VALUE_INIT; + g_value_init (&v, GNC_TYPE_NUMERIC); + g_value_set_boxed (&v, &*value); + qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, path); + g_value_unset (&v); + } + else + qof_instance_set_path_kvp (QOF_INSTANCE (acc), nullptr, path); + mark_account (acc); + xaccAccountCommitEdit(acc); +} + +static void +set_kvp_string_path (Account *acc, const std::vector& path, const char *value) { g_return_if_fail(GNC_IS_ACCOUNT(acc)); @@ -2510,6 +2531,19 @@ set_kvp_string_tag (Account *acc, const char *tag, const char *value) set_kvp_string_path (acc, {tag}, value); } +static std::optional +get_kvp_gnc_numeric_path (const Account *acc, const std::vector& path) +{ + g_return_val_if_fail (acc, std::nullopt); + GValue v = G_VALUE_INIT; + qof_instance_get_path_kvp (QOF_INSTANCE (acc), &v, path); + if (!G_VALUE_HOLDS_BOXED (&v)) return std::nullopt; + auto val = static_cast(g_value_get_boxed (&v)); + auto rv = gnc_numeric_check (*val) ? std::nullopt : std::make_optional(*val); + g_value_unset (&v); + return rv; +} + static const char* get_kvp_string_path (const Account *acc, std::vector const & path, GValue *v) @@ -4827,196 +4861,86 @@ xaccAccountSetLastNum (Account *acc, const char *num) /********************************************************************\ \********************************************************************/ -gboolean -xaccAccountGetHigherBalanceLimit (const Account *acc, - gnc_numeric *balance) +static bool +get_balance_limit (const Account* acc, gnc_numeric* balance, const std::string& key, + std::optional>& priv_limit) { g_return_val_if_fail (GNC_IS_ACCOUNT(acc), false); + g_return_val_if_fail (balance, false); - if (GET_PRIVATE(acc)->higher_balance_limit.has_value()) + if (priv_limit.has_value()) { - *balance = GET_PRIVATE(acc)->higher_balance_limit.value(); - - if (gnc_numeric_check (*balance) == 0) - return true; - else - return false; + auto limit = *priv_limit; + if (limit) *balance = *limit; + return limit.has_value(); } - else + else if (auto priv_limit = get_kvp_gnc_numeric_path (acc, { KEY_BALANCE_LIMIT, key })) { - gnc_numeric bal = gnc_numeric_create (1,0); - GValue v = G_VALUE_INIT; - gboolean retval = false; - - qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {KEY_BALANCE_LIMIT, - KEY_BALANCE_HIGHER_LIMIT_VALUE}); - if (G_VALUE_HOLDS_BOXED(&v)) - { - bal = *(gnc_numeric*)g_value_get_boxed (&v); - if (bal.denom) - { - if (balance) - *balance = bal; - retval = true; - } - } - g_value_unset (&v); - - GET_PRIVATE(acc)->higher_balance_limit = bal; - return retval; + *balance = *priv_limit; + return true; } + return false; } -gboolean -xaccAccountGetLowerBalanceLimit (const Account *acc, - gnc_numeric *balance) +static void +set_balance_limit (Account *acc, std::optional balance, const std::string& key, + std::optional>& priv_limit) { - g_return_val_if_fail (GNC_IS_ACCOUNT(acc), false); - - if (GET_PRIVATE(acc)->lower_balance_limit.has_value()) - { - *balance = GET_PRIVATE(acc)->lower_balance_limit.value(); - - if (gnc_numeric_check (*balance) == 0) - return true; - else - return false; - } - else - { - gnc_numeric bal = gnc_numeric_create (1,0); - GValue v = G_VALUE_INIT; - gboolean retval = false; - - qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {KEY_BALANCE_LIMIT, - KEY_BALANCE_LOWER_LIMIT_VALUE}); - if (G_VALUE_HOLDS_BOXED(&v)) - { - bal = *(gnc_numeric*)g_value_get_boxed (&v); - if (bal.denom) - { - if (balance) - *balance = bal; - retval = true; - } - } - g_value_unset (&v); - - GET_PRIVATE(acc)->lower_balance_limit = bal; - return retval; - } + g_return_if_fail (GNC_IS_ACCOUNT(acc)); + if (balance && gnc_numeric_check (*balance)) + return; + set_kvp_gnc_numeric_path (acc, { KEY_BALANCE_LIMIT, key }, balance); + priv_limit = std::make_optional>(balance); } - -static void -set_balance_limits (Account *acc, gnc_numeric balance, gboolean higher) +gboolean +xaccAccountGetHigherBalanceLimit (const Account *acc, + gnc_numeric *balance) { - gnc_numeric balance_limit; - gboolean balance_limit_valid; - std::vector path {KEY_BALANCE_LIMIT}; - - if (higher) - { - path.push_back (KEY_BALANCE_HIGHER_LIMIT_VALUE); - balance_limit_valid = xaccAccountGetHigherBalanceLimit (acc, &balance_limit); - } - else - { - path.push_back (KEY_BALANCE_LOWER_LIMIT_VALUE); - balance_limit_valid = xaccAccountGetLowerBalanceLimit (acc, &balance_limit); - } - - if (!balance_limit_valid || gnc_numeric_compare (balance, balance_limit) != 0) - { - GValue v = G_VALUE_INIT; - g_value_init (&v, GNC_TYPE_NUMERIC); - g_value_set_boxed (&v, &balance); - xaccAccountBeginEdit (acc); + if (!GNC_IS_ACCOUNT (acc)) return false; + return get_balance_limit (acc, balance, KEY_BALANCE_HIGHER_LIMIT_VALUE, + GET_PRIVATE(acc)->higher_balance_limit); +} - qof_instance_set_path_kvp (QOF_INSTANCE(acc), &v, path); - if (higher) - { - GET_PRIVATE(acc)->higher_balance_limit = balance; - } - else - { - GET_PRIVATE(acc)->lower_balance_limit = balance; - } - mark_account (acc); - xaccAccountCommitEdit (acc); - g_value_unset (&v); - } +gboolean +xaccAccountGetLowerBalanceLimit (const Account *acc, + gnc_numeric *balance) +{ + if (!GNC_IS_ACCOUNT (acc)) return false; + return get_balance_limit (acc, balance, KEY_BALANCE_LOWER_LIMIT_VALUE, + GET_PRIVATE(acc)->lower_balance_limit); } void xaccAccountSetHigherBalanceLimit (Account *acc, gnc_numeric balance) { - g_return_if_fail (GNC_IS_ACCOUNT(acc)); - - if (gnc_numeric_check (balance) != 0) - return; - - set_balance_limits (acc, balance, true); + if (!GNC_IS_ACCOUNT (acc)) return; + set_balance_limit (acc, balance, KEY_BALANCE_HIGHER_LIMIT_VALUE, + GET_PRIVATE(acc)->higher_balance_limit); } void xaccAccountSetLowerBalanceLimit (Account *acc, gnc_numeric balance) { - g_return_if_fail (GNC_IS_ACCOUNT(acc)); - - if (gnc_numeric_check (balance) != 0) - return; - - set_balance_limits (acc, balance, false); -} - - -static void -clear_balance_limits (Account *acc, gboolean higher) -{ - gnc_numeric balance_limit; - gboolean balance_limit_valid; - std::vector path {KEY_BALANCE_LIMIT}; - - if (higher) - { - path.push_back (KEY_BALANCE_HIGHER_LIMIT_VALUE); - balance_limit_valid = xaccAccountGetHigherBalanceLimit (acc, &balance_limit); - } - else - { - path.push_back (KEY_BALANCE_LOWER_LIMIT_VALUE); - balance_limit_valid = xaccAccountGetLowerBalanceLimit (acc, &balance_limit); - } - - if (balance_limit_valid) - { - xaccAccountBeginEdit (acc); - qof_instance_set_path_kvp (QOF_INSTANCE(acc), nullptr, path); - qof_instance_slot_path_delete_if_empty (QOF_INSTANCE(acc), {KEY_BALANCE_LIMIT}); - if (higher) - GET_PRIVATE(acc)->higher_balance_limit.reset(); - else - GET_PRIVATE(acc)->lower_balance_limit.reset(); - mark_account (acc); - xaccAccountCommitEdit (acc); - } + if (!GNC_IS_ACCOUNT (acc)) return; + set_balance_limit (acc, balance, KEY_BALANCE_LOWER_LIMIT_VALUE, + GET_PRIVATE(acc)->lower_balance_limit); } void xaccAccountClearHigherBalanceLimit (Account *acc) { - g_return_if_fail (GNC_IS_ACCOUNT(acc)); - - clear_balance_limits (acc, true); + if (!GNC_IS_ACCOUNT (acc)) return; + set_balance_limit (acc, {}, KEY_BALANCE_HIGHER_LIMIT_VALUE, + GET_PRIVATE(acc)->higher_balance_limit); } void xaccAccountClearLowerBalanceLimit (Account *acc) { - g_return_if_fail (GNC_IS_ACCOUNT(acc)); - - clear_balance_limits (acc, false); + if (!GNC_IS_ACCOUNT (acc)) return; + set_balance_limit (acc, {}, KEY_BALANCE_LOWER_LIMIT_VALUE, + GET_PRIVATE(acc)->lower_balance_limit); } gboolean diff --git a/libgnucash/engine/AccountP.hpp b/libgnucash/engine/AccountP.hpp index 64e6f09bf39..408fbe52f98 100644 --- a/libgnucash/engine/AccountP.hpp +++ b/libgnucash/engine/AccountP.hpp @@ -113,8 +113,10 @@ typedef struct AccountPrivate gnc_numeric cleared_balance; gnc_numeric reconciled_balance; - std::optional higher_balance_limit; - std::optional lower_balance_limit; + // outer optional to denote if balance_limit is cached + // inner optional to denote if balance_limit exists + std::optional> higher_balance_limit; + std::optional> lower_balance_limit; std::optional include_sub_account_balances; gboolean balance_dirty; /* balances in splits incorrect */