diff --git a/libgnucash/engine/gnc-option-impl.cpp b/libgnucash/engine/gnc-option-impl.cpp index 905088884b..edb1b10d44 100644 --- a/libgnucash/engine/gnc-option-impl.cpp +++ b/libgnucash/engine/gnc-option-impl.cpp @@ -77,6 +77,7 @@ void GncOptionGncOwnerValue::set_value(const GncOwner* new_value) { m_value.reset(make_owner_ptr(new_value)); + m_dirty = true; } void @@ -196,6 +197,7 @@ void GncOptionQofInstanceValue::set_value(const QofInstance* new_value) { m_value = make_gnc_item(new_value); + m_dirty = true; } void @@ -308,6 +310,7 @@ GncOptionCommodityValue::set_value(gnc_commodity* value) throw std::invalid_argument("Value not a currency when required or not a commodity. Value not set."); m_mnemonic = gnc_commodity_get_mnemonic(value); m_namespace = gnc_commodity_get_namespace(value); + m_dirty = true; } void @@ -591,6 +594,7 @@ GncOptionDateValue::set_value(uint16_t index) noexcept assert(index < m_period_set.size()); m_date = INT64_MAX; m_period = m_period_set[index]; + m_dirty = true; } uint16_t @@ -726,6 +730,7 @@ template void GncOptionValue::set_value(ValueType new_value) { m_value = new_value; + m_dirty = true; } template void diff --git a/libgnucash/engine/gnc-option-impl.hpp b/libgnucash/engine/gnc-option-impl.hpp index 10d4eeab18..4ebaa36708 100644 --- a/libgnucash/engine/gnc-option-impl.hpp +++ b/libgnucash/engine/gnc-option-impl.hpp @@ -101,6 +101,8 @@ public: void set_value(ValueType new_value); void set_default_value(ValueType new_value); void reset_default_value(); + void mark_saved() noexcept { m_dirty = false; } + bool is_dirty() const noexcept { return m_dirty; } 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; } @@ -111,6 +113,7 @@ private: GncOptionUIType m_ui_type; ValueType m_value; ValueType m_default_value; + bool m_dirty{false}; }; @@ -144,6 +147,8 @@ public: void set_value(const GncOwner* new_value); void set_default_value(const GncOwner* new_value); void reset_default_value(); + void mark_saved() noexcept { m_dirty = false; } + bool is_dirty() const noexcept { return m_dirty; } bool is_changed() const noexcept; GncOptionUIType get_ui_type() const noexcept { return m_ui_type; } void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; } @@ -154,6 +159,7 @@ private: GncOptionUIType m_ui_type; GncOwnerPtr m_value; GncOwnerPtr m_default_value; + bool m_dirty{false}; }; /** class GncOptionQofinstanceValue @@ -181,6 +187,8 @@ public: void set_value(const QofInstance* new_value); void set_default_value(const QofInstance* new_value); void reset_default_value(); + void mark_saved() noexcept { m_dirty = false; } + bool is_dirty() const noexcept { return m_dirty; } bool is_changed() const noexcept; GncOptionUIType get_ui_type() const noexcept { return m_ui_type; } void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; } @@ -191,6 +199,7 @@ private: GncOptionUIType m_ui_type; GncItem m_value; GncItem m_default_value; + bool m_dirty{false}; }; /** class GncOptionCommodityValue @@ -229,6 +238,8 @@ public: void set_value(gnc_commodity* value); void set_default_value(gnc_commodity* value); void reset_default_value(); + void mark_saved() noexcept { m_dirty = false; } + bool is_dirty() const noexcept { return m_dirty; } bool is_changed() const noexcept; GncOptionUIType get_ui_type() const noexcept { return m_ui_type; } void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; } @@ -242,6 +253,7 @@ private: std::string m_mnemonic; std::string m_default_namespace; std::string m_default_mnemonic; + bool m_dirty{false}; }; QofInstance* qof_instance_from_string(const std::string& str, @@ -408,7 +420,10 @@ public: void set_value(ValueType value) { if (this->validate(value)) + { m_value = value; + m_dirty = true; + } else throw std::invalid_argument("Validation failed, value not set."); } @@ -426,6 +441,8 @@ public: step = m_step; } void reset_default_value() { m_value = m_default_value; } + void mark_saved() noexcept { m_dirty = false; } + bool is_dirty() const noexcept { return m_dirty; } 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; } @@ -441,7 +458,8 @@ private: ValueType m_min; ValueType m_max; ValueType m_step; - bool m_alternate = false; + bool m_alternate{false}; + bool m_dirty{false}; }; template(m_choices.at(index)).c_str(); } void reset_default_value() { m_value = m_default_value; } + void mark_saved() noexcept { m_dirty = false; } + bool is_dirty() const noexcept { return m_dirty; } 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; } @@ -712,6 +734,7 @@ private: GncMultichoiceOptionIndexVec m_value; GncMultichoiceOptionIndexVec m_default_value; GncMultichoiceOptionChoices m_choices; + bool m_dirty{false}; static const std::string c_empty_string; static const std::string c_list_string; }; @@ -832,8 +855,11 @@ public: bool validate (const GncOptionAccountList& values) const; void set_value (GncOptionAccountList values) { if (validate(values)) + { //throw! m_value = values; + m_dirty = true; + } } void set_default_value (GncOptionAccountList values) { if (validate(values)) @@ -842,6 +868,8 @@ public: } GList* account_type_list() const noexcept; void reset_default_value() { m_value = m_default_value; } + void mark_saved() noexcept { m_dirty = false; } + bool is_dirty() const noexcept { return m_dirty; } bool is_changed() const noexcept; GncOptionUIType get_ui_type() const noexcept { return m_ui_type; } void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; } @@ -855,6 +883,7 @@ private: GncOptionAccountList m_default_value; GncOptionAccountTypeList m_allowed; bool m_multiselect; + bool m_dirty{false}; }; template<> inline std::ostream& @@ -943,6 +972,7 @@ public: { auto guid{qof_entity_get_guid(value)}; m_value = *guid; + m_dirty = true; } //else throw } @@ -956,6 +986,8 @@ public: } GList* account_type_list() const noexcept; void reset_default_value() { m_value = m_default_value; } + void mark_saved() noexcept { m_dirty = false; } + bool is_dirty() const noexcept { return m_dirty; } bool is_changed() const noexcept { return !guid_equal(&m_value, &m_default_value); } GncOptionUIType get_ui_type() const noexcept { return m_ui_type; } void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; } @@ -967,6 +999,7 @@ private: GncGUID m_value; GncGUID m_default_value; GncOptionAccountTypeList m_allowed; + bool m_dirty{false}; }; template<> inline std::ostream& @@ -1063,6 +1096,7 @@ public: { m_period = value; m_date = INT64_MAX; + m_dirty = true; } } void set_value(time64 time) { @@ -1070,6 +1104,7 @@ public: { m_period = RelativeDatePeriod::ABSOLUTE; m_date = time; + m_dirty = true; } } void set_value(uint16_t index) noexcept; @@ -1104,6 +1139,8 @@ public: m_period = m_default_period; m_date = m_default_date; } + void mark_saved() noexcept { m_dirty = false; } + bool is_dirty() const noexcept { return m_dirty; } bool is_changed() const noexcept { return m_period != m_default_period && m_date != m_default_date; } GncOptionUIType get_ui_type() const noexcept { return m_ui_type; } @@ -1119,6 +1156,7 @@ private: RelativeDatePeriod m_period; RelativeDatePeriod m_default_period; RelativeDatePeriodVec m_period_set; + bool m_dirty{false}; }; template<> inline std::ostream& diff --git a/libgnucash/engine/gnc-option.cpp b/libgnucash/engine/gnc-option.cpp index 49fa74e73a..b95cc2e7bf 100644 --- a/libgnucash/engine/gnc-option.cpp +++ b/libgnucash/engine/gnc-option.cpp @@ -26,6 +26,7 @@ #include "gnc-option-uitype.hpp" #include "gnc-option-ui.hpp" #include "gncOwner.h" +#include "kvp-value.hpp" static const char* log_module{"gnc.app-utils.gnc-option"}; @@ -291,6 +292,22 @@ GncOption::is_internal() }, *m_option); } +void +GncOption::mark_saved() noexcept +{ + std::visit([](auto& option)->void { + option.mark_saved(); + }, *m_option); +} + +bool +GncOption::is_dirty() const noexcept +{ + return std::visit([](const auto& option)->bool { + return option.is_dirty(); + }, *m_option); +} + bool GncOption::is_changed() const noexcept { diff --git a/libgnucash/engine/gnc-option.hpp b/libgnucash/engine/gnc-option.hpp index b2f9ffb8a7..267c0aaee5 100644 --- a/libgnucash/engine/gnc-option.hpp +++ b/libgnucash/engine/gnc-option.hpp @@ -164,6 +164,11 @@ public: void set_option_from_ui_item(); void make_internal(); bool is_internal(); +/** Mark the option as needing to be saved. */ + void mark_saved() noexcept; +/** @returns true if the option has been marked as needing to be saved. */ + bool is_dirty() const noexcept; +/** @returns true if the option value differs from its default value. */ bool is_changed() const noexcept; /** @returns false unless m_option contains a GncOptionMultiselectValue or * GncOptionAccountListValue for which multiple selections have been enabled. diff --git a/libgnucash/engine/gnc-optiondb.cpp b/libgnucash/engine/gnc-optiondb.cpp index 11ad68ac47..e30199b210 100644 --- a/libgnucash/engine/gnc-optiondb.cpp +++ b/libgnucash/engine/gnc-optiondb.cpp @@ -445,8 +445,8 @@ GncOptionDB::save_to_kvp(QofBook* book, bool clear_options) const noexcept [book](GncOptionSectionPtr& section) { section->foreach_option( - [book, §ion](auto& option) { - if (option.is_changed()) + [book, §ion](GncOption& option) { + if (option.is_dirty()) { /* We need the string name out here so that it stays in * scope long enough to pass its c_str to @@ -482,6 +482,7 @@ GncOptionDB::save_to_kvp(QofBook* book, bool clear_options) const noexcept kvp = new KvpValue{g_strdup(str.c_str())}; } qof_book_set_option(book, kvp, &list_head); + option.mark_saved(); } }); });