From 41ef2c5d44ba8a9667fb9393cd89945c22f432c3 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Fri, 20 Sep 2019 13:56:54 -0700 Subject: [PATCH] Add OptionUIItem composition class to GncOption. Provides a type and a raw pointer member with accessors. The type is one of enum GncOptionIUType and is either VOID (for internal options that don't get UI items) or one of the widget types specified in dialog-option.c or business-options-gnome.c. --- libgnucash/app-utils/gnc-option.hpp | 126 +++++++++++++++++- .../app-utils/test/gtest-gnc-option.cpp | 33 +++++ 2 files changed, 152 insertions(+), 7 deletions(-) diff --git a/libgnucash/app-utils/gnc-option.hpp b/libgnucash/app-utils/gnc-option.hpp index 6752c8562e..d8400084b7 100644 --- a/libgnucash/app-utils/gnc-option.hpp +++ b/libgnucash/app-utils/gnc-option.hpp @@ -33,6 +33,7 @@ extern "C" } #include #include +#include #include /* @@ -81,6 +82,34 @@ protected: }; */ +enum GncOptionUIType +{ + INTERNAL, + BOOLEAN, + STRING, + TEXT, + CURRENCY, + COMMODITY, + MULTICHOICE, + DATE, + ACCOUNT_LIST, + ACCOUNT_SEL, + LIST, + NUMBER_RANGE, + COLOR, + FONT, + BUDGET, + PIXMAP, + RADIOBUTTON, + DATE_FORMAT, + OWNER, + CUSTOMER, + VENDOR, + EMPLOYEE, + INVOICE, + TAX_TABLE +}; + struct OptionClassifier { std::string m_section; @@ -90,18 +119,59 @@ struct OptionClassifier std::string m_doc_string; }; +/** + * Holds a pointer to the UI item which will control the option and an enum + * representing the type of the option for dispatch purposes; all of that + * happens in gnucash/gnome-utils/dialog-options and + * gnucash/gnome/business-option-gnome. + * + * This class takes no ownership responsibility, so calling code is responsible + * for ensuring that the UI_Item is alive. For convenience the public + * clear_ui_item function can be used as a weak_ptr's destruction callback to + * ensure that if the ui_item is destroyed elsewhere the ptr will be nulled and + * the type reset to OptionUIType::INTERNAL. + */ +class OptionUIItem +{ +public: + GncOptionUIType get_ui_type() { return m_ui_type; } + const void* get_ui_item() {return m_ui_item; } + void set_ui_item(void* ui_item) + { + if (m_ui_type == GncOptionUIType::INTERNAL) + { + std::string error{"Can't set ui item with void ui type."}; + throw std::logic_error(std::move(error)); + } + m_ui_item = ui_item; + } +protected: + OptionUIItem(GncOptionUIType ui_type) : + m_ui_item{nullptr}, m_ui_type{ui_type} {} + OptionUIItem(const OptionUIItem&) = default; + OptionUIItem(OptionUIItem&&) = default; + ~OptionUIItem() = default; + OptionUIItem& operator=(const OptionUIItem&) = default; + OptionUIItem& operator=(OptionUIItem&&) = default; +private: + void* m_ui_item; + GncOptionUIType m_ui_type; +}; + template SCM scm_from_value(ValueType); template class GncOptionValue : - public OptionClassifier + public OptionClassifier, public OptionUIItem { public: GncOptionValue(const char* section, const char* name, const char* key, const char* doc_string, - ValueType value) : + ValueType value, + GncOptionUIType ui_type = GncOptionUIType::INTERNAL) : OptionClassifier{section, name, key, doc_string}, + OptionUIItem(ui_type), m_value{value}, m_default_value{value} {} ValueType get_value() const { return m_value; } ValueType get_default_value() const { return m_default_value; } @@ -121,14 +191,17 @@ private: template class GncOptionValidatedValue : - public OptionClassifier + public OptionClassifier, public OptionUIItem { public: GncOptionValidatedValue(const char* section, const char* name, const char* key, const char* doc_string, ValueType value, - std::functionvalidator) : + std::functionvalidator, + GncOptionUIType ui_type = GncOptionUIType::INTERNAL + ) : OptionClassifier{section, name, key, doc_string}, + OptionUIItem(ui_type), m_value{value}, m_default_value{value}, m_validator{validator} { if (!this->validate(value)) @@ -184,10 +257,10 @@ public: template GncOption(const char* section, const char* name, const char* key, const char* doc_string, - ValueType value) : + ValueType value, + GncOptionUIType ui_type = GncOptionUIType::INTERNAL) : m_option{GncOptionValue { - section, name, key, doc_string, value - }} {} + section, name, key, doc_string, value, ui_type}} {} template ValueType get_value() const { @@ -225,6 +298,18 @@ public: { return boost::apply_visitor(GetDocstringVisitor(), m_option); } + void set_ui_item(void* ui_elem) + { + return boost::apply_visitor(SetUIItemVisitor(ui_elem), m_option); + } + const GncOptionUIType get_ui_type() + { + return boost::apply_visitor(GetUITypeVisitor(), m_option); + } + const void* get_ui_item() + { + return boost::apply_visitor(GetUIItemVisitor(), m_option); + } private: template struct GetValueVisitor : public boost::static_visitor @@ -313,6 +398,33 @@ private: return option.m_doc_string; } }; + struct SetUIItemVisitor : public boost::static_visitor<> + { + SetUIItemVisitor(void* ui_item) : m_ui_item{ui_item} {} + template + void operator()(OptionType& option) const { + option.set_ui_item(m_ui_item); + } + private: + void* m_ui_item; + }; + struct GetUITypeVisitor : + public boost::static_visitor + { + template + const GncOptionUIType operator()(OptionType& option) const { + return option.get_ui_type(); + } + }; + struct GetUIItemVisitor : + public boost::static_visitor + { + template + const void* operator()(OptionType& option) const { + return option.get_ui_item(); + } + }; + GncOptionVariant m_option; }; diff --git a/libgnucash/app-utils/test/gtest-gnc-option.cpp b/libgnucash/app-utils/test/gtest-gnc-option.cpp index bd1712094e..8dffa8afa7 100644 --- a/libgnucash/app-utils/test/gtest-gnc-option.cpp +++ b/libgnucash/app-utils/test/gtest-gnc-option.cpp @@ -192,3 +192,36 @@ TEST(GNCOption, test_currency_setter) gnc_commodity_table_destroy(table); qof_book_destroy(book); } + +class GncUIItem +{ +public: + void set_value(const std::string& value) { m_value = value; } + const std::string& get_value() { return m_value; } +private: + std::string m_value; +}; + +class GncOptionUITest : public ::testing::Test +{ +protected: + GncOptionUITest() : + m_option{"foo", "bar", "baz", "Phony Option", std::string{"waldo"}, + GncOptionUIType::STRING} {} + + GncOption m_option; +}; + +using GncOptionUI = GncOptionUITest; + +TEST_F(GncOptionUI, test_option_ui_type) +{ + EXPECT_EQ(GncOptionUIType::STRING, m_option.get_ui_type()); +} + +TEST_F(GncOptionUI, test_set_option_ui_element) +{ + GncUIItem ui_item; + m_option.set_ui_item(&ui_item); + EXPECT_EQ(&ui_item, static_cast(m_option.get_ui_item())); +}