diff --git a/libgnucash/app-utils/gnc-option-impl.hpp b/libgnucash/app-utils/gnc-option-impl.hpp index 0abd8314f1..d2ae693dd7 100644 --- a/libgnucash/app-utils/gnc-option-impl.hpp +++ b/libgnucash/app-utils/gnc-option-impl.hpp @@ -500,7 +500,8 @@ operator>> (std::istream& iss, OptType& opt) using GncMultichoiceOptionEntry = std::tuple; + const std::string, + GncOptionMultichoiceKeyType>; using GncMultichoiceOptionIndexVec = std::vector; using GncMultichoiceOptionChoices = std::vector; @@ -575,7 +576,8 @@ public: if (vec.size() == 1) return std::get<0>(m_choices.at(vec[0])); else - return c_list_string; + throw std::length_error("Retrieving multiple values from a multichoice isn't implemented."); + } const std::string& get_default_value() const { @@ -671,6 +673,7 @@ public: 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; } + GncOptionMultichoiceKeyType get_keytype(unsigned i) const { return std::get<3>(m_choices.at(i)); } private: std::size_t find_key (const std::string& key) const noexcept { diff --git a/libgnucash/app-utils/gnc-option.hpp b/libgnucash/app-utils/gnc-option.hpp index 798e539a33..342cda4fad 100644 --- a/libgnucash/app-utils/gnc-option.hpp +++ b/libgnucash/app-utils/gnc-option.hpp @@ -63,6 +63,13 @@ using GncOptionVariant = std::variant, using GncOptionVariantPtr = std::unique_ptr; +enum class GncOptionMultichoiceKeyType +{ + SYMBOL, + STRING, + NUMBER, +}; + class GncOption { public: diff --git a/libgnucash/app-utils/gnc-optiondb.hpp b/libgnucash/app-utils/gnc-optiondb.hpp index de0f13aff3..0d05c1ab78 100644 --- a/libgnucash/app-utils/gnc-optiondb.hpp +++ b/libgnucash/app-utils/gnc-optiondb.hpp @@ -51,7 +51,8 @@ using GncOptionAccountList = std::vector; using GncOptionAccountTypeList = std::vector; using GncMultichoiceOptionEntry = std::tuple; + const std::string, + GncOptionMultichoiceKeyType>; using GncMultichoiceOptionChoices = std::vector; /** diff --git a/libgnucash/app-utils/gnc-optiondb.i b/libgnucash/app-utils/gnc-optiondb.i index 0626f105eb..95016fda8e 100644 --- a/libgnucash/app-utils/gnc-optiondb.i +++ b/libgnucash/app-utils/gnc-optiondb.i @@ -256,14 +256,34 @@ gnc_option_test_book_destroy(QofBook* book) %typemap(in) GncMultichoiceOptionChoices&& (GncMultichoiceOptionChoices choices) { + using KeyType = GncOptionMultichoiceKeyType; auto len = scm_to_size_t(scm_length($input)); for (std::size_t i = 0; i < len; ++i) { SCM vec = scm_list_ref($input, scm_from_size_t(i)); - std::string key{scm_to_utf8_string(SCM_SIMPLE_VECTOR_REF(vec, 0))}; + SCM keyval, v_ref_0 = SCM_SIMPLE_VECTOR_REF(vec, 0); + GncOptionMultichoiceKeyType keytype; + if (scm_is_symbol(v_ref_0)) + { + keyval = scm_symbol_to_string(SCM_SIMPLE_VECTOR_REF(vec, 0)); + keytype = KeyType::SYMBOL; + } + else if (scm_is_string(v_ref_0)) + { + keyval = SCM_SIMPLE_VECTOR_REF(vec, 0); + keytype = KeyType::STRING; + } + else if (scm_is_integer(v_ref_0)) + { + keyval = scm_number_to_string(v_ref_0, scm_from_uint(10u)); + keytype = KeyType::NUMBER; + } + else + throw std::invalid_argument("Unsupported key type in multichoice option."); + std::string key{scm_to_utf8_string(keyval)}; std::string name{scm_to_utf8_string(SCM_SIMPLE_VECTOR_REF(vec, 1))}; std::string desc{scm_to_utf8_string(SCM_SIMPLE_VECTOR_REF(vec, 2))}; - choices.push_back({std::move(key), std::move(name), std::move(desc)}); + choices.push_back({std::move(key), std::move(name), std::move(desc), keytype}); } $1 = &choices; } @@ -404,6 +424,45 @@ wrap_unique_ptr(GncOptionDBPtr, GncOptionDB); %ignore gnc_register_start_date_option(GncOptionDB*, const char*, const char*, const char*, const char*, bool); %ignore gnc_register_end_date_option(GncOptionDB*, const char*, const char*, const char*, const char*, bool); + +%ignore GncOptionMultichoiceKeyType; + /* Replace GncOptionMultichoiceValue::get_value with one that restores the keytype that Scheme sent it. */ +%inline %{ + SCM get_scm_value(const GncOptionMultichoiceValue& option) + { + using KeyType = GncOptionMultichoiceKeyType; + auto scm_value = [](const char* value, KeyType keytype) -> SCM { + auto scm_str{scm_from_utf8_string(value)}; + switch (keytype) + { + case KeyType::SYMBOL: + return scm_string_to_symbol(scm_str); + case KeyType::STRING: + return scm_str; + case KeyType::NUMBER: + return scm_string_to_number(scm_str, scm_from_int(10)); + }; + }; + + auto indexes = option.get_multiple(); + if (indexes.empty()) + indexes = option.get_default_multiple(); + if (indexes.empty()) + return SCM_BOOL_F; + if (indexes.size() == 1) // FIXME: Should use bool member to decide + return scm_value(option.permissible_value(indexes[0]), + option.get_keytype(indexes[0])); + auto values{scm_list_1(SCM_UNDEFINED)}; + for(auto index : indexes) + { + auto val{scm_list_1(scm_value(option.permissible_value(index), + option.get_keytype(index)))}; + values = scm_append(scm_list_2(val, values)); + } + return scm_reverse(values); + } + %} + %include "gnc-option-date.hpp" %include "gnc-option.hpp" %include "gnc-option-impl.hpp" @@ -421,6 +480,9 @@ wrap_unique_ptr(GncOptionDBPtr, GncOptionDB); SCM get_scm_value() { return std::visit([](const auto& option)->SCM { + if constexpr (std::is_same_v, + GncOptionMultichoiceValue>) + return get_scm_value(option); auto value{option.get_value()}; if constexpr (std::is_same_v, SCM>)