26 #include <gnc-datetime.hpp> 38 static const QofLogModule log_module{
"gnc.options"};
40 const std::string GncOptionMultichoiceValue::c_empty_string{
""};
41 const std::string GncOptionMultichoiceValue::c_list_string{
"multiple values"};
43 using GncItem = std::pair<QofIdTypeConst, GncGUID>;
52 return std::make_pair(std::move(type), std::move(*const_cast<GncGUID*>(guid)));
56 qof_instance_from_gnc_item(
const GncItem& item)
58 auto [type, guid] = item;
59 auto book{gnc_get_current_book()};
65 operator!=(
const GncItem& left,
const GncItem& right)
67 auto [ltype, lguid]{left};
68 auto [rtype, rguid]{right};
69 return strcmp(rtype, ltype) && !
guid_equal(&rguid, &lguid);
72 GncOptionQofInstanceValue::GncOptionQofInstanceValue(
73 const char* section,
const char* name,
74 const char* key,
const char* doc_string,
77 m_ui_type(ui_type), m_value{},
79 m_value = make_gnc_item(value);
80 m_default_value = make_gnc_item(value);
86 m_ui_type(from.get_ui_type()), m_value{from.get_item()},
87 m_default_value{from.get_default_item()}
91 GncOptionQofInstanceValue::set_value(
const QofInstance* new_value)
93 m_value = make_gnc_item(new_value);
97 GncOptionQofInstanceValue::set_default_value(
const QofInstance *new_value)
99 m_value = m_default_value = make_gnc_item(new_value);
104 GncOptionQofInstanceValue::get_value()
const 106 return qof_instance_from_gnc_item(m_value);
110 GncOptionQofInstanceValue::get_default_value()
const 112 return qof_instance_from_gnc_item(m_default_value);
116 GncOptionQofInstanceValue::reset_default_value()
118 m_value = m_default_value;
122 GncOptionQofInstanceValue::is_changed() const noexcept
124 return m_value != m_default_value;
128 GncOptionQofInstanceValue::deserialize(
const std::string& str) noexcept
133 auto guid{
static_cast<GncGUID>(gnc::GUID::from_string(str))};
134 inst = qof_instance_from_guid(&guid, m_ui_type);
137 m_value = make_gnc_item(inst);
143 PWARN(
"Failed to convert %s to a GUID", str.c_str());
149 GncOptionQofInstanceValue::serialize() const noexcept
151 auto inst{get_value()};
153 if (GNC_IS_COMMODITY(inst))
155 auto commodity{GNC_COMMODITY(inst)};
159 if (name_space && *name_space !=
'\0')
171 retval = guid.to_string();
176 static gnc_commodity*
177 gnc_commodity_from_namespace_and_mnemonic(std::string_view name_space,
178 std::string_view mnemonic)
180 auto book{gnc_get_current_book()};
182 return gnc_commodity_table_lookup(
table, name_space.data(),
187 GncOptionCommodityValue::get_value()
const 189 return gnc_commodity_from_namespace_and_mnemonic(m_namespace, m_mnemonic);
193 GncOptionCommodityValue::get_default_value()
const 195 return gnc_commodity_from_namespace_and_mnemonic(m_default_namespace,
200 GncOptionCommodityValue::set_value(gnc_commodity* value)
202 if (!validate(value))
203 throw std::invalid_argument(
"Value not a currency when required or not a commodity. Value not set.");
209 GncOptionCommodityValue::set_default_value(gnc_commodity* value)
211 if (!validate(value))
212 throw std::invalid_argument(
"Value not a currency when required or not a commodity. Value not set.");
218 GncOptionCommodityValue::reset_default_value()
220 m_mnemonic = m_default_mnemonic;
221 m_namespace = m_default_namespace;
225 GncOptionCommodityValue::is_changed() const noexcept
227 return m_namespace != m_default_namespace || m_mnemonic != m_default_mnemonic;
231 GncOptionCommodityValue::validate(gnc_commodity* comm)
const noexcept
233 if (!GNC_IS_COMMODITY(comm))
241 GncOptionCommodityValue::serialize() const noexcept
246 return m_namespace +
":" + m_mnemonic;
250 GncOptionCommodityValue::deserialize(
const std::string& str) noexcept
252 auto sep{str.find(
":")};
253 gnc_commodity* comm{};
254 std::string mnemonic, name_space;
255 if (sep != std::string::npos)
257 name_space = str.substr(0, sep);
258 mnemonic = str.substr(sep + 1, -1);
262 name_space =
"CURRENCY";
265 comm = gnc_commodity_from_namespace_and_mnemonic(name_space, mnemonic);
268 m_namespace = std::move(name_space);
269 m_mnemonic = std::move(mnemonic);
274 GncOptionAccountListValue::validate(
const GncOptionAccountList& values)
const 278 if ((get_ui_type() == GncOptionUIType::ACCOUNT_SEL || !m_multiselect) &&
281 std::cerr <<
"GncOptionAccountListValue::validate: Multiple values for a non-multiselect option." << std::endl;
284 if (m_allowed.empty())
286 auto book{gnc_get_current_book()};
287 for(
auto& guid : values)
289 if (std::find(m_allowed.begin(), m_allowed.end(),
292 std::cerr <<
"GncOptionAccountListValue::validate: Account " <<
gnc::GUID(guid).to_string() <<
" is not of an allowed type" << std::endl;
299 GncOptionAccountListValue::get_value()
const 301 return !m_value.empty() ? m_value : get_default_value();
305 GncOptionAccountListValue::get_default_value()
const 307 if (!m_default_value.empty())
308 return m_default_value;
313 GncOptionAccountList retval{};
314 if (m_allowed.empty())
317 auto root{gnc_get_current_root_account()};
322 auto book{gnc_get_current_book()};
323 for (
auto node = account_list; node; node = g_list_next (node))
325 if (std::find(m_allowed.begin(), m_allowed.end(),
332 g_list_free(account_list);
343 GncOptionAccountListValue::is_changed() const noexcept
345 return m_value != m_default_value;
360 if (m_allowed.empty())
362 GList* retval{
nullptr};
363 for (
auto type : m_allowed)
364 retval = g_list_prepend(retval, GINT_TO_POINTER(type));
365 return g_list_reverse(retval);
369 GncOptionAccountSelValue::validate(
const Account* value)
const 371 if (m_allowed.empty() || !value)
373 if (std::find(m_allowed.begin(), m_allowed.end(),
380 GncOptionAccountSelValue::get_value()
const 382 auto book{gnc_get_current_book()};
388 GncOptionAccountSelValue::get_default_value()
const 393 auto book{gnc_get_current_book()};
400 if (m_allowed.empty())
403 const Account* retval{
nullptr};
404 auto root{gnc_get_current_root_account()};
409 for (
auto node = account_list; node; node = g_list_next (node))
410 if (std::find(m_allowed.begin(), m_allowed.end(),
413 retval = GNC_ACCOUNT(node->data);
416 g_list_free(account_list);
431 if (m_allowed.empty())
433 GList* retval{
nullptr};
434 for (
auto type : m_allowed)
435 retval = g_list_prepend(retval, GINT_TO_POINTER(type));
436 return g_list_reverse(retval);
441 if (m_period_set.empty())
443 if (std::find(m_period_set.begin(), m_period_set.end(),
444 value) != m_period_set.end())
450 GncOptionDateValue::get_value() const noexcept
452 if (m_period == RelativeDatePeriod::ABSOLUTE)
458 GncOptionDateValue::get_default_value() const noexcept
460 if (m_default_period == RelativeDatePeriod::ABSOLUTE)
461 return m_default_date;
469 GncOptionDateValue::get_period_index() const noexcept
471 assert (m_period != RelativeDatePeriod::ABSOLUTE);
472 assert(!m_period_set.empty());
473 auto item{std::find(m_period_set.begin(), m_period_set.end(), m_period)};
474 assert(item != m_period_set.end());
475 return item - m_period_set.begin();
479 GncOptionDateValue::get_default_period_index() const noexcept
481 assert(m_period != RelativeDatePeriod::ABSOLUTE);
482 assert(!m_period_set.empty());
483 auto item{std::find(m_period_set.begin(), m_period_set.end(),
485 assert (item != m_period_set.end());
486 return item - m_period_set.begin();
490 GncOptionDateValue::set_value(
size_t index) noexcept
492 assert(!m_period_set.empty());
493 assert(index < m_period_set.size());
495 m_period = m_period_set[index];
499 GncOptionDateValue::permissible_value_index(
const char* key)
const noexcept
501 auto index = std::find_if(m_period_set.begin(), m_period_set.end(),
502 [key](
auto period) ->
bool {
506 return index != m_period_set.end() ? index - m_period_set.begin() : 0;
509 static const char* date_type_str[] {
"absolute",
"relative"};
512 GncOptionDateValue::out_stream(std::ostream& oss)
const noexcept
514 if (m_period == RelativeDatePeriod::ABSOLUTE)
515 oss << date_type_str[0] <<
" . " << m_date;
517 oss << date_type_str[1] <<
" . " <<
523 GncOptionDateValue::in_stream(std::istream& iss)
526 iss.getline(type_str,
sizeof(type_str),
'.');
528 throw std::invalid_argument(
"Date Type separator missing");
530 if (strcmp(type_str,
"absolute ") == 0)
535 if (iss.get() !=
')')
538 else if (strcmp(type_str,
"relative ") == 0)
540 std::string period_str;
542 if (period_str.back() ==
')')
543 period_str.pop_back();
545 if (period == RelativeDatePeriod::ABSOLUTE)
547 std::string err{
"Unknown period string in date option: '"};
550 throw std::invalid_argument(err);
557 std::string err{
"Unknown date type string in date option: '"};
560 throw std::invalid_argument{err};
571 case GncOptionUIType::BUDGET:
574 case GncOptionUIType::JOB:
577 case GncOptionUIType::CUSTOMER:
578 qof_type =
"gncCustomer";
580 case GncOptionUIType::VENDOR:
581 qof_type =
"gncVendor";
583 case GncOptionUIType::EMPLOYEE:
584 qof_type =
"gncEmployee";
586 case GncOptionUIType::INVOICE:
587 qof_type =
"gncInvoice";
589 case GncOptionUIType::TAX_TABLE:
590 qof_type =
"gncTaxTable";
592 case GncOptionUIType::ACCOUNT_LIST:
593 case GncOptionUIType::ACCOUNT_SEL:
595 qof_type =
"Account";
598 auto book{gnc_get_current_book()};
608 auto guid{
static_cast<GncGUID>(gnc::GUID::from_string(str))};
609 retval = qof_instance_from_guid(&guid, type);
613 PWARN(
"Failed to convert %s to a GUID", str.c_str());
623 retval = guid.to_string();
627 template <
typename ValueType>
void 633 template <
typename ValueType>
void 636 m_value = m_default_value = new_value;
639 template <
typename ValueType>
void 642 m_value = m_default_value;
650 template <
typename ValueType> std::string
653 static const std::string no_value{
"No Value"};
654 if constexpr(std::is_same_v<ValueType, const QofInstance*>)
655 return m_value ? qof_instance_to_string(m_value) : no_value;
656 if constexpr(std::is_same_v<ValueType, const GncOwner*>)
662 std::ostringstream ostr{};
663 ostr << type <<
" " << guid;
666 if constexpr(std::is_same_v<ValueType, GncOptionReportPlacementVec>)
668 std::ostringstream ostr{};
670 std::for_each(m_value.begin(), m_value.end(),
672 auto [id, wide, high] = rp;
673 ostr <<
"(" <<
id <<
" " << wide <<
" " << high <<
" #f) ";
678 else if constexpr(is_same_decayed_v<ValueType, std::string>)
680 else if constexpr(is_same_decayed_v<ValueType, bool>)
681 return m_value ?
"True" :
"False";
682 else if constexpr(std::is_arithmetic_v<ValueType>)
683 return std::to_string(m_value);
685 return "Serialization not implemented";
688 template <
typename ValueType>
bool 691 if constexpr(std::is_same_v<ValueType, const QofInstance*>)
692 set_value(qof_instance_from_string(str, get_ui_type()));
693 if constexpr(std::is_same_v<ValueType, const GncOwner*>)
695 std::istringstream istr{str};
696 std::string type, guid;
697 istr >> type >> guid;
698 auto inst{qof_instance_from_string(guid, get_ui_type())};
701 if constexpr(std::is_same_v<ValueType, GncOptionReportPlacementVec>)
703 std::istringstream istr{str};
704 GncOptionReportPlacementVec rpv;
707 uint32_t id, wide, high;
708 istr >>
id >> wide >> high;
709 rpv.emplace_back(
id, wide, high);
713 else if constexpr(is_same_decayed_v<ValueType, std::string>)
715 else if constexpr(is_same_decayed_v<ValueType, bool>)
716 set_value(str ==
"True");
717 else if constexpr(is_same_decayed_v<ValueType, int>)
718 set_value(stoi(str));
719 else if constexpr(is_same_decayed_v<ValueType, int64_t>)
720 set_value(stoll(str));
721 else if constexpr(is_same_decayed_v<ValueType, double>)
722 set_value(stod(str));
729 GncOptionAccountListValue::serialize() const noexcept
731 static const std::string no_value{
"No Value"};
736 for (
auto val : m_value)
747 GncOptionAccountListValue::deserialize(
const std::string& str) noexcept
762 m_value.push_back(guid);
769 GncOptionAccountSelValue::serialize() const noexcept
771 static const std::string no_value{
"No Value"};
776 GncOptionAccountSelValue::deserialize(
const std::string& str) noexcept
778 set_value(reinterpret_cast<Account*>(qof_instance_from_string(str, get_ui_type())));
783 GncOptionMultichoiceValue::serialize() const noexcept
785 static const std::string no_value{
"No Value"};
790 for (
auto index : m_value)
795 retval += std::get<0>(m_choices[index]);
801 GncOptionMultichoiceValue::deserialize(
const std::string& str) noexcept
803 static const auto size_t_max = std::numeric_limits<std::size_t>::max();
808 while (pos < str.size())
810 auto endpos{str.find(
' ', pos)};
811 if (endpos == std::string::npos)
814 auto index{permissible_value_index(str.substr(pos, endpos).c_str())};
815 if (index == size_t_max)
817 m_value.push_back(index);
823 template <
typename ValueType> std::string
826 if constexpr (std::is_arithmetic_v<ValueType>)
827 return std::to_string(m_value);
831 template <
typename ValueType>
bool 834 if constexpr(is_same_decayed_v<ValueType, int>)
835 set_value(stoi(str));
836 else if constexpr(is_same_decayed_v<ValueType, double>)
837 set_value(stod(str));
842 GncOptionDateValue::serialize() const noexcept
844 std::string retval{
"("};
845 if (m_period == RelativeDatePeriod::ABSOLUTE)
847 retval += date_type_str[0];
849 retval += std::to_string(m_date);
853 retval += date_type_str[1];
862 GncOptionDateValue::deserialize(
const std::string& str) noexcept
865 static constexpr
size_t date_type_len{9};
867 static constexpr
size_t date_value_pos{12};
868 auto type_str{str.substr(0, date_type_len)};
869 auto period_str{str.substr(date_value_pos)};
870 if (type_str ==
"absolute")
873 set_value(static_cast<size_t>(std::stoll(period_str)));
876 else if (type_str ==
"relative ")
879 if (period == RelativeDatePeriod::ABSOLUTE)
881 PWARN(
"Unknown period string in date option: '%s'",
891 PWARN(
"Unknown date type string in date option: '%s'",
902 if (!opt.deserialize(instr))
903 throw std::invalid_argument(
"Invalid commodity string in stream.");
972 template
std::
string GncOptionValue<GncOptionReportPlacementVec>::serialize() const noexcept;
980 template
bool GncOptionValue<const
char*>::deserialize(const
std::
string&) noexcept;
984 template
bool GncOptionValue<GncOptionReportPlacementVec>::deserialize(const
std::
string&) noexcept;
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Returns the commodity table associated with a book.
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
Checks to see if the specified commodity is an ISO 4217 recognized currency or a legacy currency...
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
RelativeDatePeriod gnc_relative_date_from_storage_string(const char *str)
Convert a relative date storage string back to a RelativeDatePeriod value.
GList * gnc_account_get_descendants_sorted(const Account *account)
This function returns a GList containing all the descendants of the specified account, sorted at each level.
const char * gnc_relative_date_display_string(RelativeDatePeriod per)
Provide the string representation of a relative date for displaying value to a user.
The generic option-value class.
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
GList * account_type_list() const noexcept
Create a GList of account types to pass to gnc_account_sel_set_acct_filters.
utility functions for the GnuCash UI
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
GncGUID guid_new_return(void)
Generate a new id.
gboolean string_to_guid(const gchar *string, GncGUID *guid)
Given a string, replace the given guid with the parsed one unless the given value is null...
GList * account_type_list() const noexcept
Create a GList of account types to pass to gnc_account_sel_set_acct_filters.
QofCollection * qof_instance_get_collection(gconstpointer ptr)
Return the collection this instance belongs to.
const char * gnc_commodity_get_namespace(const gnc_commodity *cm)
Retrieve the namespace for the specified commodity.
time64 gnc_relative_date_to_time64(RelativeDatePeriod period)
Convert a RelativeDatePeriod value to a concrete time64 by applying the value to the current time...
QofInstance * qofOwnerGetOwner(const GncOwner *owner)
return the owner itself as an entity.
This class is the parent of all option implmentations.
#define PWARN(format, args...)
Log a warning.
const gchar * QofIdType
QofIdType declaration.
gboolean guid_equal(const GncGUID *guid_1, const GncGUID *guid_2)
Given two GUIDs, return TRUE if they are non-NULL and equal.
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
RelativeDatePeriod
Reporting periods relative to the current date.
General utilities for dealing with accounting periods.
QofIdTypeConst qofOwnerGetType(const GncOwner *owner)
return the type for the collection.
void qofOwnerSetEntity(GncOwner *owner, QofInstance *ent)
set the owner from the entity.
Implementation templates and specializtions for GncOption values.
class GncOptionCommodityValue Commodities are stored with their namespace and mnemonic instead of the...
Used for numeric ranges and plot sizes.
const GncGUID * qof_entity_get_guid(gconstpointer ent)
QofIdType qof_collection_get_type(const QofCollection *col)
return the type that the collection stores
gchar * guid_to_string(const GncGUID *guid)
The guid_to_string() routine returns a null-terminated string encoding of the id. ...
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
const char * gnc_relative_date_storage_string(RelativeDatePeriod per)
Provide the string representation of a relative date for persisting the value.
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
The type used to store guids in C.
GncOptionUIType
Used by GncOptionClassifier to indicate to dialog-options what control should be displayed for the op...
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...