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