Skip to content

Commit

Permalink
Separate GncOptionAccountValue into GncOptionAccountListValue and Gnc…
Browse files Browse the repository at this point in the history
…OptionAccountSelValue.

They have different get_value() return types so can't cohabit comfortably.
  • Loading branch information
jralls committed Aug 1, 2021
1 parent dd8e8b4 commit 18997db
Show file tree
Hide file tree
Showing 10 changed files with 293 additions and 54 deletions.
106 changes: 104 additions & 2 deletions libgnucash/app-utils/gnc-option-impl.cpp
Expand Up @@ -37,7 +37,7 @@ const std::string GncOptionMultichoiceValue::c_empty_string{""};
const std::string GncOptionMultichoiceValue::c_list_string{"multiple values"};

bool
GncOptionAccountValue::validate(const GncOptionAccountList& values) const
GncOptionAccountListValue::validate(const GncOptionAccountList& values) const
{
if (values.empty())
return true;
Expand All @@ -54,6 +54,108 @@ GncOptionAccountValue::validate(const GncOptionAccountList& values) const
return true;
}

GncOptionAccountList
GncOptionAccountListValue::get_value() const
{
return !m_value.empty() ? m_value : get_default_value();
}

GncOptionAccountList
GncOptionAccountListValue::get_default_value() const
{
if (!m_default_value.empty())
return m_default_value;

/* If no default has been set and there's an allowed set then find the first
* account that matches one of the allowed account types.
*/
GncOptionAccountList retval{};
if (m_allowed.empty())
return retval;

auto root{gnc_get_current_root_account()};
auto account_list{gnc_account_get_descendants_sorted(root)};
if (!account_list)
return retval;

for (auto node = account_list; node; node = g_list_next (node))
if (std::find(m_allowed.begin(), m_allowed.end(),
xaccAccountGetType(GNC_ACCOUNT(node->data))) != m_allowed.end())
{
retval.push_back(GNC_ACCOUNT(node->data));
break;
}
g_list_free(account_list);
return retval;
}


/**
* Create a GList of account types to pass to gnc_account_sel_set_acct_filters.
* gnc_account_sel_set_acct_filters copies the list so the intermediary caller
* is responsible for freeing the list.
*
* @return an allocated GList* or nullptr if the list is empty.
*/
GList*
GncOptionAccountListValue::account_type_list() const noexcept
{
if (m_allowed.empty())
return nullptr;
GList* retval;
for (auto type : m_allowed)
retval = g_list_prepend(retval, GINT_TO_POINTER(type));
return g_list_reverse(retval);
}

bool
GncOptionAccountSelValue::validate(const Account* value) const
{
if (m_allowed.empty() || !value)
return true;
if (std::find(m_allowed.begin(), m_allowed.end(),
xaccAccountGetType(value)) == m_allowed.end())
return false;
return true;
}

const Account*
GncOptionAccountSelValue::get_value() const
{
return m_value ? m_value : get_default_value();
}

const Account*
GncOptionAccountSelValue::get_default_value() const
{

if (m_default_value)
return m_default_value;

/* If no default has been set and there's an allowed set then find the first
* account that matches one of the allowed account types.
*/
if (m_allowed.empty())
return nullptr;

const Account* retval{nullptr};
auto root{gnc_get_current_root_account()};
auto account_list{gnc_account_get_descendants_sorted(root)};
if (!account_list)
return nullptr;

for (auto node = account_list; node; node = g_list_next (node))
if (std::find(m_allowed.begin(), m_allowed.end(),
xaccAccountGetType(GNC_ACCOUNT(node->data))) != m_allowed.end())
{
retval = GNC_ACCOUNT(node->data);
break;
}
g_list_free(account_list);
return retval;
}


/**
* Create a GList of account types to pass to gnc_account_sel_set_acct_filters.
* gnc_account_sel_set_acct_filters copies the list so the intermediary caller
Expand All @@ -62,7 +164,7 @@ GncOptionAccountValue::validate(const GncOptionAccountList& values) const
* @return an allocated GList* or nullptr if the list is empty.
*/
GList*
GncOptionAccountValue::account_type_list() const noexcept
GncOptionAccountSelValue::account_type_list() const noexcept
{
if (m_allowed.empty())
return nullptr;
Expand Down
149 changes: 136 additions & 13 deletions libgnucash/app-utils/gnc-option-impl.hpp
Expand Up @@ -908,30 +908,30 @@ using GncOptionAccountTypeList = std::vector<GNCAccountType>;
*/

class GncOptionAccountValue : public OptionClassifier
class GncOptionAccountListValue : public OptionClassifier
{
public:
GncOptionAccountValue(const char* section, const char* name,
GncOptionAccountListValue(const char* section, const char* name,
const char* key, const char* doc_string,
GncOptionUIType ui_type, bool multi=true) :
OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
m_value{}, m_default_value{}, m_allowed{}, m_multiselect{multi} {}

GncOptionAccountValue(const char* section, const char* name,
GncOptionAccountListValue(const char* section, const char* name,
const char* key, const char* doc_string,
GncOptionUIType ui_type,
const GncOptionAccountList& value, bool multi=true) :
OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
m_value{value}, m_default_value{std::move(value)}, m_allowed{},
m_multiselect{multi} {}
GncOptionAccountValue(const char* section, const char* name,
GncOptionAccountListValue(const char* section, const char* name,
const char* key, const char* doc_string,
GncOptionUIType ui_type,
GncOptionAccountTypeList&& allowed, bool multi=true) :
OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
m_value{}, m_default_value{}, m_allowed{std::move(allowed)},
m_multiselect{multi} {}
GncOptionAccountValue(const char* section, const char* name,
GncOptionAccountListValue(const char* section, const char* name,
const char* key, const char* doc_string,
GncOptionUIType ui_type,
const GncOptionAccountList& value,
Expand All @@ -945,8 +945,8 @@ class GncOptionAccountValue : public OptionClassifier
m_default_value = std::move(value);
}

const GncOptionAccountList& get_value() const { return m_value; }
const GncOptionAccountList& get_default_value() const { return m_default_value; }
GncOptionAccountList get_value() const;
GncOptionAccountList get_default_value() const;
bool validate (const GncOptionAccountList& values) const;
void set_value (const GncOptionAccountList& values) {
if (validate(values))
Expand All @@ -973,8 +973,8 @@ class GncOptionAccountValue : public OptionClassifier
};

template<> inline std::ostream&
operator<< <GncOptionAccountValue>(std::ostream& oss,
const GncOptionAccountValue& opt)
operator<< <GncOptionAccountListValue>(std::ostream& oss,
const GncOptionAccountListValue& opt)
{
auto values{opt.get_value()};
bool first = true;
Expand All @@ -990,8 +990,8 @@ operator<< <GncOptionAccountValue>(std::ostream& oss,
}

template<> inline std::istream&
operator>> <GncOptionAccountValue>(std::istream& iss,
GncOptionAccountValue& opt)
operator>> <GncOptionAccountListValue>(std::istream& iss,
GncOptionAccountListValue& opt)
{
GncOptionAccountList values;
while (true)
Expand All @@ -1010,7 +1010,7 @@ operator>> <GncOptionAccountValue>(std::istream& iss,

template<class OptType,
typename std::enable_if_t<std::is_same_v<std::decay_t<OptType>,
GncOptionAccountValue>,
GncOptionAccountListValue>,
int> = 0>
inline std::ostream&
gnc_option_to_scheme(std::ostream& oss, const OptType& opt)
Expand All @@ -1032,7 +1032,7 @@ gnc_option_to_scheme(std::ostream& oss, const OptType& opt)

template<class OptType,
typename std::enable_if_t<std::is_same_v<std::decay_t<OptType>,
GncOptionAccountValue>,
GncOptionAccountListValue>,
int> = 0>
inline std::istream&
gnc_option_from_scheme(std::istream& iss, OptType& opt)
Expand All @@ -1056,6 +1056,129 @@ gnc_option_from_scheme(std::istream& iss, OptType& opt)
return iss;
}

class GncOptionAccountSelValue : public OptionClassifier
{
public:
GncOptionAccountSelValue(const char* section, const char* name,
const char* key, const char* doc_string,
GncOptionUIType ui_type) :
OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
m_value{}, m_default_value{}, m_allowed{} {}

GncOptionAccountSelValue(const char* section, const char* name,
const char* key, const char* doc_string,
GncOptionUIType ui_type,
const Account* value) :
OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
m_value{const_cast<Account*>(value)},
m_default_value{const_cast<Account*>(value)}, m_allowed{} {}
GncOptionAccountSelValue(const char* section, const char* name,
const char* key, const char* doc_string,
GncOptionUIType ui_type,
GncOptionAccountTypeList&& allowed) :
OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
m_value{}, m_default_value{}, m_allowed{std::move(allowed)} {}
GncOptionAccountSelValue(const char* section, const char* name,
const char* key, const char* doc_string,
GncOptionUIType ui_type,
const Account* value,
GncOptionAccountTypeList&& allowed) :
OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
m_value{}, m_default_value{}, m_allowed{std::move(allowed)} {
if (!validate(value))
throw std::invalid_argument("Supplied Value not in allowed set.");
m_value = const_cast<Account*>(value);
m_default_value = const_cast<Account*>(value);
}

const Account* get_value() const;
const Account* get_default_value() const;
bool validate (const Account* value) const;
void set_value (const Account* value) {
if (validate(value))
//throw!
m_value = const_cast<Account*>(value);
}
void set_default_value (const Account* value) {
if (validate(value))
//throw!
m_value = m_default_value = const_cast<Account*>(value);
}
GList* account_type_list() const noexcept;
void reset_default_value() { m_value = m_default_value; }
bool is_changed() const noexcept { return m_value != m_default_value; }
GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
private:
GncOptionUIType m_ui_type;
Account* m_value;
Account* m_default_value;
GncOptionAccountTypeList m_allowed;
};

template<> inline std::ostream&
operator<< <GncOptionAccountSelValue>(std::ostream& oss,
const GncOptionAccountSelValue& opt)
{
auto value{opt.get_value()};
oss << qof_instance_to_string(QOF_INSTANCE(value));
return oss;
}

template<> inline std::istream&
operator>> <GncOptionAccountSelValue>(std::istream& iss,
GncOptionAccountSelValue& opt)
{
const Account* value;
std::string str;
std::getline(iss, str, ' ');
if (!str.empty())
value = (Account*)qof_instance_from_string(str, opt.get_ui_type());
opt.set_value(value);
iss.clear();
return iss;
}

template<class OptType,
typename std::enable_if_t<std::is_same_v<std::decay_t<OptType>,
GncOptionAccountSelValue>,
int> = 0>
inline std::ostream&
gnc_option_to_scheme(std::ostream& oss, const OptType& opt)
{
auto value{opt.get_value()};
oss << "'(\"";
oss << qof_instance_to_string(QOF_INSTANCE(value)) << '"';
oss << ')';
return oss;
}

template<class OptType,
typename std::enable_if_t<std::is_same_v<std::decay_t<OptType>,
GncOptionAccountSelValue>,
int> = 0>
inline std::istream&
gnc_option_from_scheme(std::istream& iss, OptType& opt)
{
const Account* value;
iss.ignore(3, '"');
while (true)
{
std::string str;
std::getline(iss, str, '"');
if (!str.empty())
{
value = (Account*)qof_instance_from_string(str, opt.get_ui_type());
iss.ignore(2, '"');
}
else
break;
}
opt.set_value(value);
iss.ignore(1, ')');
return iss;
}

/** Date options
* A legal date value is a pair of either and a RelativeDatePeriod, the absolute
* flag and a time64, or for legacy purposes the absolute flag and a timespec.
Expand Down
8 changes: 4 additions & 4 deletions libgnucash/app-utils/gnc-option.cpp
Expand Up @@ -279,7 +279,7 @@ GncOption::is_multiselect() const noexcept
{
return std::visit([](const auto& option)->bool {
if constexpr (std::is_same_v<std::decay_t<decltype(option)>,
GncOptionAccountValue>)
GncOptionAccountListValue>)
return option.is_multiselect();
else
return false;
Expand Down Expand Up @@ -367,7 +367,7 @@ GncOption::account_type_list() const noexcept
{
return std::visit([] (const auto& option) -> GList* {
if constexpr (std::is_same_v<std::decay_t<decltype(option)>,
GncOptionAccountValue>)
GncOptionAccountListValue>)
return option.account_type_list();
else
return nullptr;
Expand Down Expand Up @@ -423,7 +423,7 @@ GncOption::to_scheme(std::ostream& oss) const
return std::visit([&oss](auto& option) ->std::ostream& {
if constexpr
((std::is_same_v<std::decay_t<decltype(option)>,
GncOptionAccountValue>) ||
GncOptionAccountListValue>) ||
(std::is_same_v<std::decay_t<decltype(option)>,
GncOptionMultichoiceValue>) ||
std::is_same_v<std::decay_t<decltype(option)>,
Expand Down Expand Up @@ -464,7 +464,7 @@ GncOption::from_scheme(std::istream& iss)
return std::visit([&iss](auto& option) -> std::istream& {
if constexpr
((std::is_same_v<std::decay_t<decltype(option)>,
GncOptionAccountValue>) ||
GncOptionAccountListValue>) ||
(std::is_same_v<std::decay_t<decltype(option)>,
GncOptionMultichoiceValue>) ||
std::is_same_v<std::decay_t<decltype(option)>,
Expand Down
6 changes: 4 additions & 2 deletions libgnucash/app-utils/gnc-option.hpp
Expand Up @@ -49,7 +49,8 @@ using QofQuery = _QofQuery;
struct QofInstance_s;
using QofInstance = QofInstance_s;
template <typename ValueType> class GncOptionValue;
class GncOptionAccountValue;
class GncOptionAccountListValue;
class GncOptionAccountSelValue;
class GncOptionMultichoiceValue;
template <typename ValueType> class GncOptionRangeValue;
template <typename ValueType> class GncOptionValidatedValue;
Expand All @@ -62,7 +63,8 @@ using GncOptionVariant = std::variant<GncOptionValue<std::string>,
GncOptionValue<const QofQuery*>,
GncOptionValue<const GncOwner*>,
GncOptionValue<SCM>,
GncOptionAccountValue,
GncOptionAccountListValue,
GncOptionAccountSelValue,
GncOptionMultichoiceValue,
GncOptionRangeValue<int>,
GncOptionRangeValue<double>,
Expand Down

0 comments on commit 18997db

Please sign in to comment.