gnucash stable: [c++options] Correctly implement handling Fancy Date Format.

John Ralls jralls at code.gnucash.org
Tue Sep 19 19:06:01 EDT 2023


Updated	 via  https://github.com/Gnucash/gnucash/commit/a49fd0bc (commit)
	from  https://github.com/Gnucash/gnucash/commit/8150645b (commit)



commit a49fd0bc098e6bcffb7824b86f838bac37b277db
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Sep 19 16:04:28 2023 -0700

    [c++options] Correctly implement handling Fancy Date Format.
    
    It's not a simple string.

diff --git a/bindings/guile/gnc-optiondb.i b/bindings/guile/gnc-optiondb.i
index 4e3874bc51..e8a559fd3a 100644
--- a/bindings/guile/gnc-optiondb.i
+++ b/bindings/guile/gnc-optiondb.i
@@ -319,6 +319,12 @@ scm_from_value<GncOptionReportPlacementVec>(GncOptionReportPlacementVec value)
     return scm_reverse(s_list);
 }
 
+template <> inline SCM
+scm_from_value<GncOptionDateFormat>(GncOptionDateFormat value)
+{
+    return SCM_BOOL_F;
+}
+
 static std::string
 scm_color_list_to_string(SCM list)
 {
@@ -564,7 +570,6 @@ gnc_option_test_book_destroy(QofBook* book)
 %ignore operator>>(std::istream&, GncOption&);
 %ignore GncOption::_get_option();
 
-
 %rename(gnc_register_date_option_set)
     gnc_register_date_option(GncOptionDBPtr&, const char*, const char*,
                              const char*, const char*, RelativeDatePeriodVec&,
@@ -804,7 +809,8 @@ wrap_unique_ptr(GncOptionDBPtr, GncOptionDB);
 %ignore gnc_register_taxtable_option(GncOptionDB*, const char*, const char*, const char*, const char*, GncTaxTable*);
 %ignore gnc_register_counter_option(GncOptionDB*, const char*, const char*, const char*, const char*, double);
 %ignore gnc_register_counter_format_option(GncOptionDB*, const char*, const char*, const char*, const char*, std::string);
-%ignore gnc_register_dateformat_option(GncOptionDB*, const char*, const char*, const char*, const char*, std::string);
+%ignore gnc_register_dateformat_option(GncOptionDB*, const char*, const char*, const char*, const char*, GncOptionDateFormat&&);
+%ignore gnc_register_dateformat_option(GncOptionDBPtr&, const char*, const char*, const char*, const char*, GncOptionDateFormat&&);
 %ignore gnc_register_date_option(GncOptionDB*, const char*, const char*, const char*, const char*, RelativeDatePeriod, RelativeDateUI);
 %ignore gnc_register_date_option(GncOptionDB*, const char*, const char*, const char*, const char*, time64, RelativeDateUI);
 %ignore gnc_register_date_option(GncOptionDB*, const char*, const char*, const char*, const char*, RelativeDatePeriodVec, bool);
diff --git a/gnucash/gnome-utils/gnc-option-gtk-ui.cpp b/gnucash/gnome-utils/gnc-option-gtk-ui.cpp
index e9f96f99c2..8babd0ce13 100644
--- a/gnucash/gnome-utils/gnc-option-gtk-ui.cpp
+++ b/gnucash/gnome-utils/gnc-option-gtk-ui.cpp
@@ -1682,13 +1682,21 @@ public:
     void set_ui_item_from_option(GncOption& option) noexcept override
     {
         auto widget{GNC_DATE_FORMAT(get_widget())};
-        gnc_date_format_set_custom(widget,
-                                   option.get_value<std::string>().c_str());
+        auto [format, months, years, custom] = option.get_value<GncOptionDateFormat>();
+        gnc_date_format_set_format(widget, format);
+        gnc_date_format_set_months(widget, months);
+        gnc_date_format_set_years(widget, years);
+        gnc_date_format_set_custom(widget, custom.c_str());
     }
     void set_option_from_ui_item(GncOption& option) noexcept override
     {
         auto widget{GNC_DATE_FORMAT(get_widget())};
-        option.set_value(std::string{gnc_date_format_get_custom(widget)});
+        GncOptionDateFormat format{
+            gnc_date_format_get_format(widget),
+            gnc_date_format_get_months(widget),
+            gnc_date_format_get_years(widget),
+            gnc_date_format_get_custom(widget)};
+        option.set_value(format);
     }
 };
 
diff --git a/libgnucash/engine/gnc-option-impl.cpp b/libgnucash/engine/gnc-option-impl.cpp
index b60b18a2ae..df6a57e462 100644
--- a/libgnucash/engine/gnc-option-impl.cpp
+++ b/libgnucash/engine/gnc-option-impl.cpp
@@ -1038,6 +1038,7 @@ template void GncOptionValue<uint16_t>::set_value(uint16_t);
 template void GncOptionValue<GncOptionAccountList>::set_value(GncOptionAccountList);
 template void GncOptionValue<GncMultichoiceOptionIndexVec>::set_value(GncMultichoiceOptionIndexVec);
 template void GncOptionValue<GncOptionReportPlacementVec>::set_value(GncOptionReportPlacementVec);
+template void GncOptionValue<GncOptionDateFormat>::set_value(GncOptionDateFormat);
 template void GncOptionValue<bool>::set_default_value(bool);
 template void GncOptionValue<int>::set_default_value(int);
 template void GncOptionValue<int64_t>::set_default_value(int64_t);
@@ -1052,6 +1053,7 @@ template void GncOptionValue<uint16_t>::set_default_value(uint16_t);
 template void GncOptionValue<GncOptionAccountList>::set_default_value(GncOptionAccountList);
 template void GncOptionValue<GncMultichoiceOptionIndexVec>::set_default_value(GncMultichoiceOptionIndexVec);
 template void GncOptionValue<GncOptionReportPlacementVec>::set_default_value(GncOptionReportPlacementVec);
+template void GncOptionValue<GncOptionDateFormat>::set_default_value(GncOptionDateFormat);
 template void GncOptionValue<bool>::reset_default_value();
 template void GncOptionValue<int>::reset_default_value();
 template void GncOptionValue<int64_t>::reset_default_value();
@@ -1066,6 +1068,7 @@ template void GncOptionValue<uint16_t>::reset_default_value();
 template void GncOptionValue<GncOptionAccountList>::reset_default_value();
 template void GncOptionValue<GncMultichoiceOptionIndexVec>::reset_default_value();
 template void GncOptionValue<GncOptionReportPlacementVec>::reset_default_value();
+template void GncOptionValue<GncOptionDateFormat>::reset_default_value();
 template std::string GncOptionValue<bool>::serialize() const noexcept;
 template std::string GncOptionValue<int>::serialize() const noexcept;
 template std::string GncOptionValue<int64_t>::serialize() const noexcept;
@@ -1076,6 +1079,7 @@ template std::string GncOptionValue<std::string>::serialize() const noexcept;
 template std::string GncOptionValue<const QofQuery*>::serialize() const noexcept;
 template std::string GncOptionValue<const GncOwner*>::serialize() const noexcept;
 template std::string GncOptionValue<GncOptionReportPlacementVec>::serialize() const noexcept;
+template std::string GncOptionValue<GncOptionDateFormat>::serialize() const noexcept;
 template std::string GncOptionRangeValue<int>::serialize() const noexcept;
 template std::string GncOptionRangeValue<double>::serialize() const noexcept;
 template bool GncOptionValue<bool>::deserialize(const std::string&) noexcept;
@@ -1088,5 +1092,6 @@ template bool GncOptionValue<std::string>::deserialize(const std::string&) noexc
 template bool GncOptionValue<const QofQuery*>::deserialize(const std::string&) noexcept;
 template bool GncOptionValue<const GncOwner*>::deserialize(const std::string&) noexcept;
 template bool GncOptionValue<GncOptionReportPlacementVec>::deserialize(const std::string&) noexcept;
+template bool GncOptionValue<GncOptionDateFormat>::deserialize(const std::string&) noexcept;
 template bool GncOptionRangeValue<int>::deserialize(const std::string&) noexcept;
 template bool GncOptionRangeValue<double>::deserialize(const std::string&) noexcept;
diff --git a/libgnucash/engine/gnc-option-impl.hpp b/libgnucash/engine/gnc-option-impl.hpp
index 4ebaa36708..0a279f5bdb 100644
--- a/libgnucash/engine/gnc-option-impl.hpp
+++ b/libgnucash/engine/gnc-option-impl.hpp
@@ -341,7 +341,8 @@ template<class OptType,
 std::istream& operator>>(std::istream& iss, OptType& opt)
 {
     if constexpr (std::is_same_v<std::decay_t<decltype(opt.get_value())>, const _gncOwner*> ||
-                  std::is_same_v<std::decay_t<decltype(opt.get_value())>, const _QofQuery*>)
+                  std::is_same_v<std::decay_t<decltype(opt.get_value())>, const _QofQuery*> ||
+                  std::is_same_v<std::decay_t<decltype(opt.get_value())>, GncOptionDateFormat>)
         return iss;
     else
     {
diff --git a/libgnucash/engine/gnc-option.cpp b/libgnucash/engine/gnc-option.cpp
index 8b1005230a..0078e69238 100644
--- a/libgnucash/engine/gnc-option.cpp
+++ b/libgnucash/engine/gnc-option.cpp
@@ -115,6 +115,7 @@ GncOption::set_value(ValueType value)
         [value](auto& option) {
             if constexpr
                 (is_same_decayed_v<decltype(option.get_value()), ValueType> ||
+                 is_same_decayed_v<decltype(option), GncOptionDateFormat> ||
                  (is_same_decayed_v<decltype(option),
                   GncOptionDateValue> &&
                   (is_same_decayed_v<ValueType, RelativeDatePeriod> ||
@@ -146,6 +147,7 @@ GncOption::set_default_value(ValueType value)
         [value](auto& option) {
             if constexpr
                 (is_same_decayed_v<decltype(option.get_value()), ValueType>||
+                 is_same_decayed_v<decltype(option), GncOptionDateFormat> ||
                  (is_same_decayed_v<decltype(option), GncOptionDateValue> &&
                   (is_same_decayed_v<ValueType, RelativeDatePeriod> ||
                    std::is_same_v<ValueType, time64> ||
@@ -486,6 +488,10 @@ template GncOption::GncOption(const char*, const char*, const char*,
 template GncOption::GncOption(const char*, const char*, const char*,
                               const char*, const QofQuery*, GncOptionUIType);
 
+template GncOption::GncOption(const char *, const char*, const char*,
+                              const char *, GncOptionDateFormat,
+                              GncOptionUIType);
+
 template bool GncOption::get_value<bool>() const;
 template int GncOption::get_value<int>() const;
 template int64_t GncOption::get_value<int64_t>() const;
@@ -501,6 +507,7 @@ template RelativeDatePeriod GncOption::get_value<RelativeDatePeriod>() const;
 template GncOptionAccountList GncOption::get_value<GncOptionAccountList>() const;
 template GncMultichoiceOptionIndexVec GncOption::get_value<GncMultichoiceOptionIndexVec>() const;
 template GncOptionReportPlacementVec GncOption::get_value<GncOptionReportPlacementVec>() const;
+template GncOptionDateFormat GncOption::get_value<GncOptionDateFormat>() const;
 
 template bool GncOption::get_default_value<bool>() const;
 template int GncOption::get_default_value<int>() const;
@@ -515,6 +522,7 @@ template RelativeDatePeriod GncOption::get_default_value<RelativeDatePeriod>() c
 template GncOptionAccountList GncOption::get_default_value<GncOptionAccountList>() const;
 template GncMultichoiceOptionIndexVec GncOption::get_default_value<GncMultichoiceOptionIndexVec>() const;
 template GncOptionReportPlacementVec GncOption::get_default_value<GncOptionReportPlacementVec>() const;
+template GncOptionDateFormat GncOption::get_default_value<GncOptionDateFormat>() const;
 
 template void GncOption::set_value(bool);
 template void GncOption::set_value(int);
@@ -532,6 +540,7 @@ template void GncOption::set_value(uint16_t);
 template void GncOption::set_value(GncOptionAccountList);
 template void GncOption::set_value(GncMultichoiceOptionIndexVec);
 template void GncOption::set_value(GncOptionReportPlacementVec);
+template void GncOption::set_value(GncOptionDateFormat);
 
 template void GncOption::set_default_value(bool);
 template void GncOption::set_default_value(int);
@@ -547,6 +556,7 @@ template void GncOption::set_default_value(uint16_t);
 template void GncOption::set_default_value(GncOptionAccountList);
 template void GncOption::set_default_value(GncMultichoiceOptionIndexVec);
 template void GncOption::set_default_value(GncOptionReportPlacementVec);
+template void GncOption::set_default_value(GncOptionDateFormat);
 
 template void GncOption::get_limits(double&, double&, double&) const noexcept;
 template void GncOption::get_limits(int&, int&, int&) const noexcept;
@@ -563,6 +573,7 @@ template bool GncOption::validate(const QofQuery*) const;
 template bool GncOption::validate(RelativeDatePeriod) const;
 template bool GncOption::validate(GncMultichoiceOptionIndexVec) const;
 template bool GncOption::validate(GncOptionReportPlacementVec) const;
+template bool GncOption::validate(GncOptionDateFormat) const;
 
 template GncOption* gnc_make_option<const std::string&>(const char*,
                                                         const char*,
diff --git a/libgnucash/engine/gnc-option.hpp b/libgnucash/engine/gnc-option.hpp
index 267c0aaee5..a15641a458 100644
--- a/libgnucash/engine/gnc-option.hpp
+++ b/libgnucash/engine/gnc-option.hpp
@@ -66,6 +66,7 @@ class GncOptionMultichoiceValue;
 template <typename ValueType> class GncOptionRangeValue;
 class GncOptionCommodityValue;
 class GncOptionDateValue;
+using GncOptionDateFormat = std::tuple<QofDateFormat, GNCDateMonthFormat, bool, std::string>;
 using GncOptionReportPlacement = std::tuple<uint32_t, uint32_t, uint32_t>;
 using GncOptionReportPlacementVec = std::vector<GncOptionReportPlacement>;
 template <typename T>
@@ -113,7 +114,8 @@ using GncOptionVariant = std::variant<GncOptionValue<std::string>,
                                       GncOptionRangeValue<int>,
                                       GncOptionRangeValue<double>,
                                       GncOptionCommodityValue,
-                                      GncOptionDateValue>;
+                                      GncOptionDateValue,
+                                      GncOptionValue<GncOptionDateFormat>>;
 
 using GncOptionVariantPtr = std::unique_ptr<GncOptionVariant>;
 
diff --git a/libgnucash/engine/gnc-optiondb.cpp b/libgnucash/engine/gnc-optiondb.cpp
index e30199b210..f423164db7 100644
--- a/libgnucash/engine/gnc-optiondb.cpp
+++ b/libgnucash/engine/gnc-optiondb.cpp
@@ -28,6 +28,7 @@
 #include <sstream>
 #include "gnc-option-uitype.hpp"
 #include "kvp-value.hpp"
+#include "kvp-frame.hpp"
 #include "qofbookslots.h"
 #include "guid.hpp"
 #include "gnc-optiondb.h"
@@ -436,6 +437,30 @@ kvp_value_from_qof_instance_option(const GncOption& option)
     return new KvpValue(guid);
 }
 
+/* GncOptionDateFormat Constants and support functions. These are frozen for backwards compatibility. */
+
+static const char* date_format_frame_key = "Fancy Date Format";
+static const char* date_format_custom_key ="custom";
+static const char* date_format_months_key = "month";
+static const char* date_format_years_key = "years";
+static const char *date_format_format_key = "fmt";
+
+static inline KvpValue *
+kvp_frame_from_date_format_option(const GncOption& option)
+{
+    auto [format, months, years, custom] = option.get_value<GncOptionDateFormat>();
+
+    if (format == QOF_DATE_FORMAT_UNSET)
+        return nullptr;
+
+    auto frame{new KvpFrame};
+    frame->set({date_format_format_key}, new KvpValue(g_strdup(gnc_date_dateformat_to_string(format))));
+    frame->set({date_format_months_key}, new KvpValue(g_strdup(gnc_date_monthformat_to_string(months))));
+    frame->set({date_format_years_key}, new KvpValue(static_cast<int64_t>(years)));
+    frame->set({date_format_custom_key}, new KvpValue(g_strdup(custom.c_str())));
+    return new KvpValue(frame);
+};
+
 void
 GncOptionDB::save_to_kvp(QofBook* book, bool clear_options) const noexcept
 {
@@ -476,6 +501,8 @@ GncOptionDB::save_to_kvp(QofBook* book, bool clear_options) const noexcept
                                 kvp = new KvpValue(option.template get_value<double>());
                             }
                         }
+                        else if (type == GncOptionUIType::DATE_FORMAT)
+                            kvp = kvp_frame_from_date_format_option(option);
                         else
                         {
                             auto str{option.template get_value<std::string>()};
@@ -506,6 +533,33 @@ fill_option_from_guid_kvp(GncOption& option, KvpValue* kvp)
         (const QofInstance*)qof_instance_from_guid(guid, option.get_ui_type()));
 }
 
+static inline void
+fill_option_from_date_format_kvp(GncOption& option, KvpValue* kvp)
+{
+    GncOptionDateFormat default_fmt{QOF_DATE_FORMAT_UNSET, GNCDATE_MONTH_NUMBER, true, ""};
+    auto frame{kvp->get<KvpFrame*>()};
+    if (!frame)
+    {
+        option.set_value(default_fmt);
+        return;
+    }
+    auto format_str{frame->get_slot({date_format_format_key})->get<const char*>()};
+    QofDateFormat format;
+    if (!format_str || gnc_date_string_to_dateformat(format_str, &format))
+    {
+        option.set_value(default_fmt);
+        return;
+    }
+    GNCDateMonthFormat months = GNCDATE_MONTH_NUMBER;
+    auto months_str{frame->get_slot({date_format_months_key})->get<const char*>()};
+    if (months_str)
+        gnc_date_string_to_monthformat(months_str, &months);
+    auto years_num{frame->get_slot({date_format_years_key})->get<int64_t>()};
+    bool years = static_cast<bool>(years_num);
+    auto custom_str{frame->get_slot({date_format_custom_key})->get<const char*>()};
+    option.set_value<GncOptionDateFormat>({format, months, years, custom_str ? custom_str : ""});
+}
+
 void
 GncOptionDB::load_from_kvp(QofBook* book) noexcept
 {
@@ -556,6 +610,10 @@ GncOptionDB::load_from_kvp(QofBook* book) noexcept
                         case KvpValue::Type::GUID:
                             fill_option_from_guid_kvp(option, kvp);
                           break;
+                        case KvpValue::Type::FRAME:
+                            if (g_strcmp0(option.get_name().c_str(), date_format_frame_key) == 0)
+                                fill_option_from_date_format_kvp(option, kvp);
+                            break;
                         default:
                             return;
                             break;
@@ -909,9 +967,9 @@ gnc_register_counter_format_option(GncOptionDB* db,
 void
 gnc_register_dateformat_option(GncOptionDB* db, const char* section,
                                const char* name, const char* key,
-                               const char* doc_string, std::string value)
+                               const char* doc_string, GncOptionDateFormat&& value)
 {
-    GncOption option{section, name, key, doc_string, value,
+    GncOption option{section, name, key, doc_string, std::move(value),
             GncOptionUIType::DATE_FORMAT};
     db->register_option(section, std::move(option));
 }
@@ -1284,10 +1342,11 @@ gnc_option_db_book_options(GncOptionDB* odb)
                                  N_("Default Vendor TaxTable"), "f2",
                                  N_("The default tax table to apply to vendors."),
                                  nullptr);
+
     gnc_register_dateformat_option(odb, business_section,
                                    N_("Fancy Date Format"), "g",
                                    N_("The default date format used for fancy printed dates."),
-                                   empty_string);
+                                   {QOF_DATE_FORMAT_UNSET, GNCDATE_MONTH_NUMBER, true, ""});
 
 //Tax Tab
 
diff --git a/libgnucash/engine/gnc-optiondb.hpp b/libgnucash/engine/gnc-optiondb.hpp
index 7a9cd8ca61..9bdefed313 100644
--- a/libgnucash/engine/gnc-optiondb.hpp
+++ b/libgnucash/engine/gnc-optiondb.hpp
@@ -806,7 +806,7 @@ inline void gnc_register_counter_format_option(GncOptionDBPtr& db,
 void gnc_register_dateformat_option(GncOptionDB* db,
                                     const char* section, const char* name,
                                     const char* key, const char* doc_string,
-                                    std::string value);
+                                    GncOptionDateFormat&& value);
 
 /**
  * As above but takes a const GncOptionDBPtr& (const std::unique_ptr<GncOptionDB>&) for calling from C++.
@@ -815,10 +815,10 @@ inline void gnc_register_dateformat_option(GncOptionDBPtr& db,
                                            const char* section,
                                            const char* name, const char* key,
                                            const char* doc_string,
-                                           std::string value)
+                                           GncOptionDateFormat&& value)
 {
     gnc_register_dateformat_option(db.get(), section, name, key,
-                                   doc_string, value);
+                                   doc_string, std::move(value));
 }
 
 enum RelativeDateUI : uint8_t



Summary of changes:
 bindings/guile/gnc-optiondb.i             | 10 ++++-
 gnucash/gnome-utils/gnc-option-gtk-ui.cpp | 14 +++++--
 libgnucash/engine/gnc-option-impl.cpp     |  5 +++
 libgnucash/engine/gnc-option-impl.hpp     |  3 +-
 libgnucash/engine/gnc-option.cpp          | 11 ++++++
 libgnucash/engine/gnc-option.hpp          |  4 +-
 libgnucash/engine/gnc-optiondb.cpp        | 65 +++++++++++++++++++++++++++++--
 libgnucash/engine/gnc-optiondb.hpp        |  6 +--
 8 files changed, 105 insertions(+), 13 deletions(-)



More information about the gnucash-changes mailing list