25#include "gnc-datetime.hpp"
33#include "gnc-session.h"
36static const QofLogModule log_module{
"gnc.options"};
38const std::string GncOptionMultichoiceValue::c_empty_string{
""};
39const std::string GncOptionMultichoiceValue::c_list_string{
"multiple values"};
41static inline GncOwnerType
44 if (ui_type == GncOptionUIType::CUSTOMER)
45 return GNC_OWNER_CUSTOMER;
46 if (ui_type == GncOptionUIType::VENDOR)
47 return GNC_OWNER_VENDOR;
48 if (ui_type == GncOptionUIType::EMPLOYEE)
49 return GNC_OWNER_EMPLOYEE;
50 if (ui_type == GncOptionUIType::JOB)
52 return GNC_OWNER_NONE;
61 gncOwnerCopy(owner, rv);
65GncOptionGncOwnerValue::GncOptionGncOwnerValue(
66 const char* section,
const char* name,
67 const char* key,
const char* doc_string,
70 m_ui_type(ui_type), m_value{make_owner_ptr(value)},
71 m_default_value{make_owner_ptr(value)} {}
76 m_ui_type(from.get_ui_type()), m_value{make_owner_ptr(from.get_value())},
77 m_default_value{make_owner_ptr(from.get_default_value())} {}
80GncOptionGncOwnerValue::set_value(
const GncOwner* new_value)
82 m_value.reset(make_owner_ptr(new_value));
87GncOptionGncOwnerValue::set_default_value(
const GncOwner *new_value)
89 m_value.reset(make_owner_ptr(new_value));
90 m_default_value.reset(make_owner_ptr(new_value));
94GncOptionGncOwnerValue::get_value()
const
100GncOptionGncOwnerValue::get_default_value()
const
102 return m_default_value.get();
106GncOptionGncOwnerValue::reset_default_value()
108 gncOwnerCopy(m_default_value.get(), m_value.get());
112GncOptionGncOwnerValue::is_changed() const noexcept
118GncOptionGncOwnerValue::deserialize(
const std::string& str)
noexcept
121 auto guid{
static_cast<GncGUID>(gnc::GUID::from_string(str))};
122 auto inst = qof_instance_from_guid(&guid, m_ui_type);
126 owner.type = ui_type_to_owner_type(m_ui_type);
127 owner.owner.undefined = inst;
128 set_default_value(&owner);
134 PWARN(
"Failed to convert %s to a GUID", str.c_str());
140GncOptionGncOwnerValue::serialize() const noexcept
143 auto owner{m_value.get()};
145 std::string retval{guid.to_string()};
157 return std::make_pair(std::move(type), std::move(*
const_cast<GncGUID*
>(guid)));
161get_current_book(
void)
167get_current_root_account(
void)
169 return gnc_book_get_root_account(get_current_book());
173qof_instance_from_gnc_item(
const GncItem& item)
175 auto [type, guid] = item;
176 auto book{get_current_book()};
181GncOptionQofInstanceValue::GncOptionQofInstanceValue(
182 const char* section,
const char* name,
183 const char* key,
const char* doc_string,
186 m_ui_type(ui_type), m_value{},
188 m_value = make_gnc_item(value);
189 m_default_value = make_gnc_item(value);
195 m_ui_type(from.get_ui_type()), m_value{from.get_item()},
196 m_default_value{from.get_default_item()}
200GncOptionQofInstanceValue::set_value(
const QofInstance* new_value)
202 m_value = make_gnc_item(new_value);
207GncOptionQofInstanceValue::set_default_value(
const QofInstance *new_value)
209 m_value = m_default_value = make_gnc_item(new_value);
214GncOptionQofInstanceValue::get_value()
const
216 return qof_instance_from_gnc_item(m_value);
220GncOptionQofInstanceValue::get_default_value()
const
222 return qof_instance_from_gnc_item(m_default_value);
226GncOptionQofInstanceValue::reset_default_value()
228 m_value = m_default_value;
232GncOptionQofInstanceValue::is_changed() const noexcept
234 return m_value != m_default_value;
238GncOptionQofInstanceValue::deserialize(
const std::string& str)
noexcept
243 auto guid{
static_cast<GncGUID>(gnc::GUID::from_string(str))};
244 inst = qof_instance_from_guid(&guid, m_ui_type);
247 m_value = make_gnc_item(inst);
253 PWARN(
"Failed to convert %s to a GUID", str.c_str());
259GncOptionQofInstanceValue::serialize() const noexcept
261 auto inst{get_value()};
263 if (GNC_IS_COMMODITY(inst))
265 auto commodity{GNC_COMMODITY(inst)};
269 if (name_space && *name_space !=
'\0')
281 retval = guid.to_string();
287gnc_commodity_from_namespace_and_mnemonic(std::string_view name_space,
288 std::string_view mnemonic)
290 auto book{get_current_book()};
292 return gnc_commodity_table_lookup(
table, name_space.data(),
297GncOptionCommodityValue::get_value()
const
299 return gnc_commodity_from_namespace_and_mnemonic(m_namespace, m_mnemonic);
303GncOptionCommodityValue::get_default_value()
const
305 return gnc_commodity_from_namespace_and_mnemonic(m_default_namespace,
310GncOptionCommodityValue::set_value(gnc_commodity* value)
312 if (!validate(value))
313 throw std::invalid_argument(
"Value not a currency when required or not a commodity. Value not set.");
320GncOptionCommodityValue::set_default_value(gnc_commodity* value)
322 if (!validate(value))
323 throw std::invalid_argument(
"Value not a currency when required or not a commodity. Value not set.");
329GncOptionCommodityValue::reset_default_value()
331 m_mnemonic = m_default_mnemonic;
332 m_namespace = m_default_namespace;
336GncOptionCommodityValue::is_changed() const noexcept
338 return m_namespace != m_default_namespace || m_mnemonic != m_default_mnemonic;
342GncOptionCommodityValue::validate(gnc_commodity* comm)
const noexcept
344 if (!GNC_IS_COMMODITY(comm))
352GncOptionCommodityValue::serialize() const noexcept
357 return m_namespace +
":" + m_mnemonic;
361GncOptionCommodityValue::deserialize(
const std::string& str)
noexcept
363 auto sep{str.find(
":")};
364 gnc_commodity* comm{};
365 std::string mnemonic, name_space;
366 if (sep != std::string::npos)
368 name_space = str.substr(0, sep);
369 mnemonic = str.substr(sep + 1, -1);
373 name_space =
"CURRENCY";
376 comm = gnc_commodity_from_namespace_and_mnemonic(name_space, mnemonic);
379 m_namespace = std::move(name_space);
380 m_mnemonic = std::move(mnemonic);
385GncOptionAccountListValue::validate(
const GncOptionAccountList& values)
const
389 if ((get_ui_type() == GncOptionUIType::ACCOUNT_SEL || !m_multiselect) &&
392 PWARN(
"GncOptionAccountListValue::validate: Multiple values for a non-multiselect option.");
395 if (m_allowed.empty())
397 auto book{get_current_book()};
398 for(
auto& guid : values)
400 if (std::find(m_allowed.begin(), m_allowed.end(),
403 PWARN(
"GncOptionAccountListValue::validate: Account %s is not of an allowed type",
gnc::GUID(guid).to_string().c_str());
410GncOptionAccountListValue::get_value()
const
412 return !m_value.empty() ? m_value : get_default_value();
416GncOptionAccountListValue::get_default_value()
const
418 if (!m_default_value.empty())
419 return m_default_value;
424 GncOptionAccountList retval{};
425 if (m_allowed.empty())
428 auto root{get_current_root_account()};
433 for (
auto node = account_list; node; node = g_list_next (node))
435 if (std::find(m_allowed.begin(), m_allowed.end(),
442 g_list_free(account_list);
447GncOptionAccountListValue::is_changed() const noexcept
449 return m_value != m_default_value;
464 if (m_allowed.empty())
466 GList* retval{
nullptr};
467 for (
auto type : m_allowed)
468 retval = g_list_prepend(retval, GINT_TO_POINTER(type));
469 return g_list_reverse(retval);
473GncOptionAccountSelValue::validate(
const Account* value)
const
475 if (m_allowed.empty() || !value)
477 if (std::find(m_allowed.begin(), m_allowed.end(),
484GncOptionAccountSelValue::get_value()
const
486 auto book{get_current_book()};
492GncOptionAccountSelValue::get_default_value()
const
497 auto book{get_current_book()};
504 if (m_allowed.empty())
507 const Account* retval{
nullptr};
508 auto root{get_current_root_account()};
513 for (
auto node = account_list; node; node = g_list_next (node))
514 if (std::find(m_allowed.begin(), m_allowed.end(),
517 retval = GNC_ACCOUNT(node->data);
520 g_list_free(account_list);
535 if (m_allowed.empty())
537 GList* retval{
nullptr};
538 for (
auto type : m_allowed)
539 retval = g_list_prepend(retval, GINT_TO_POINTER(type));
540 return g_list_reverse(retval);
545 if (m_period_set.empty())
547 if (std::find(m_period_set.begin(), m_period_set.end(),
548 value) != m_period_set.end())
554GncOptionDateValue::get_value() const noexcept
556 if (m_period == RelativeDatePeriod::ABSOLUTE)
562GncOptionDateValue::get_default_value() const noexcept
564 if (m_default_period == RelativeDatePeriod::ABSOLUTE)
565 return m_default_date;
573GncOptionDateValue::get_period_index() const noexcept
575 assert (m_period != RelativeDatePeriod::ABSOLUTE);
576 assert(!m_period_set.empty());
577 auto item{std::find(m_period_set.begin(), m_period_set.end(), m_period)};
578 assert(item != m_period_set.end());
579 return item - m_period_set.begin();
583GncOptionDateValue::get_default_period_index() const noexcept
585 assert(m_period != RelativeDatePeriod::ABSOLUTE);
586 assert(!m_period_set.empty());
587 auto item{std::find(m_period_set.begin(), m_period_set.end(),
589 assert (item != m_period_set.end());
590 return item - m_period_set.begin();
594GncOptionDateValue::set_value(uint16_t index)
noexcept
596 assert(!m_period_set.empty());
597 assert(index < m_period_set.size());
599 m_period = m_period_set[index];
604GncOptionDateValue::permissible_value_index(
const char* key)
const noexcept
606 auto index = std::find_if(m_period_set.begin(), m_period_set.end(),
607 [key](
auto period) ->
bool {
608 return strcmp(gnc_relative_date_display_string(period),
611 return index != m_period_set.end() ? index - m_period_set.begin() : 0;
614static const char* date_type_str[] {
"absolute",
"relative"};
617GncOptionDateValue::out_stream(std::ostream& oss)
const noexcept
619 if (m_period == RelativeDatePeriod::ABSOLUTE)
620 oss << date_type_str[0] <<
" . " << m_date;
622 oss << date_type_str[1] <<
" . " <<
628GncOptionDateValue::in_stream(std::istream& iss)
631 iss.getline(type_str,
sizeof(type_str),
'.');
633 throw std::invalid_argument(
"Date Type separator missing");
635 if (strcmp(type_str,
"absolute ") == 0)
640 if (iss.get() !=
')')
643 else if (strcmp(type_str,
"relative ") == 0)
645 std::string period_str;
647 if (period_str.back() ==
')')
648 period_str.pop_back();
650 if (period == RelativeDatePeriod::ABSOLUTE)
652 std::string err{
"Unknown period string in date option: '"};
655 throw std::invalid_argument(err);
662 std::string err{
"Unknown date type string in date option: '"};
665 throw std::invalid_argument{err};
676 case GncOptionUIType::BUDGET:
679 case GncOptionUIType::JOB:
682 case GncOptionUIType::CUSTOMER:
683 qof_type =
"gncCustomer";
685 case GncOptionUIType::VENDOR:
686 qof_type =
"gncVendor";
688 case GncOptionUIType::EMPLOYEE:
689 qof_type =
"gncEmployee";
691 case GncOptionUIType::INVOICE:
692 qof_type =
"gncInvoice";
694 case GncOptionUIType::TAX_TABLE:
695 qof_type =
"gncTaxTable";
697 case GncOptionUIType::ACCOUNT_LIST:
698 case GncOptionUIType::ACCOUNT_SEL:
700 qof_type =
"Account";
703 auto book{get_current_book()};
713 auto guid{
static_cast<GncGUID>(gnc::GUID::from_string(str))};
714 retval = qof_instance_from_guid(&guid, type);
718 PWARN(
"Failed to convert %s to a GUID", str.c_str());
728 retval = guid.to_string();
732template <
typename ValueType>
void
739template <
typename ValueType>
void
742 m_value = m_default_value = new_value;
745template <
typename ValueType>
void
748 m_value = m_default_value;
756template <
typename ValueType> std::string
759 static const std::string no_value{
"No Value"};
760 if constexpr(std::is_same_v<ValueType, const QofInstance*>)
761 return m_value ? qof_instance_to_string(m_value) : no_value;
762 if constexpr(std::is_same_v<ValueType, const GncOwner*>)
768 std::ostringstream ostr{};
769 ostr << type <<
" " << guid;
772 if constexpr(std::is_same_v<ValueType, GncOptionReportPlacementVec>)
774 std::ostringstream ostr{};
776 std::for_each(m_value.begin(), m_value.end(),
778 auto [id, wide, high] = rp;
779 ostr <<
"(" << id <<
" " << wide <<
" " << high <<
" #f) ";
784 else if constexpr(is_same_decayed_v<ValueType, std::string>)
786 else if constexpr(is_same_decayed_v<ValueType, bool>)
787 return m_value ?
"True" :
"False";
788 else if constexpr(std::is_arithmetic_v<ValueType>)
789 return std::to_string(m_value);
791 return "Serialization not implemented";
794template <
typename ValueType>
bool
797 if constexpr(std::is_same_v<ValueType, const QofInstance*>)
798 set_value(qof_instance_from_string(str, get_ui_type()));
799 if constexpr(std::is_same_v<ValueType, const GncOwner*>)
801 std::istringstream istr{str};
802 std::string type, guid;
803 istr >> type >> guid;
804 auto inst{qof_instance_from_string(guid, get_ui_type())};
807 if constexpr(std::is_same_v<ValueType, GncOptionReportPlacementVec>)
809 std::istringstream istr{str};
810 GncOptionReportPlacementVec rpv;
813 uint32_t id, wide, high;
814 istr >>
id >> wide >> high;
815 rpv.emplace_back(
id, wide, high);
819 else if constexpr(is_same_decayed_v<ValueType, std::string>)
821 else if constexpr(is_same_decayed_v<ValueType, bool>)
822 set_value(str ==
"True");
823 else if constexpr(is_same_decayed_v<ValueType, int>)
824 set_value(stoi(str));
825 else if constexpr(is_same_decayed_v<ValueType, int64_t>)
826 set_value(stoll(str));
827 else if constexpr(is_same_decayed_v<ValueType, double>)
828 set_value(stod(str));
835GncOptionAccountListValue::serialize() const noexcept
837 static const std::string no_value{
"No Value"};
843 for (
auto val : m_value)
855GncOptionAccountListValue::deserialize(
const std::string& str)
noexcept
870 m_value.push_back(guid);
877GncOptionAccountSelValue::serialize() const noexcept
879 static const std::string no_value{
"No Value"};
889GncOptionAccountSelValue::deserialize(
const std::string& str)
noexcept
891 set_value(
reinterpret_cast<Account*
>(qof_instance_from_string(str, get_ui_type())));
896GncOptionMultichoiceValue::serialize() const noexcept
898 static const std::string no_value{
""};
901 bool list_context = m_ui_type == GncOptionUIType::LIST;
907 for (
auto index : m_value)
912 retval += std::get<0>(m_choices[index]);
920GncOptionMultichoiceValue::deserialize(
const std::string& str)
noexcept
922 static const auto uint16_t_max = std::numeric_limits<uint16_t>::max();
927 while (pos < str.size())
929 auto endpos{str.find(
' ', pos)};
930 if (endpos == std::string::npos)
933 auto index{permissible_value_index(str.substr(pos, endpos).c_str())};
934 if (index == uint16_t_max)
936 m_value.push_back(index);
942template <
typename ValueType> std::string
945 if constexpr (std::is_arithmetic_v<ValueType>)
947 std::ostringstream ostr;
948 if constexpr(is_same_decayed_v<ValueType, double>)
949 ostr << std::showpoint << std::fixed;
956template <
typename ValueType>
bool
959 if constexpr(is_same_decayed_v<ValueType, int>)
960 set_value(stoi(str));
961 else if constexpr(is_same_decayed_v<ValueType, double>)
962 set_value(stod(str));
967GncOptionDateValue::serialize() const noexcept
969 std::string retval{
"("};
970 if (m_period == RelativeDatePeriod::ABSOLUTE)
972 retval += date_type_str[0];
974 retval += std::to_string(m_date);
978 retval += date_type_str[1];
987GncOptionDateValue::deserialize(
const std::string& str)
noexcept
990 static constexpr size_t date_type_len{9};
992 static constexpr size_t date_value_pos{12};
993 auto type_str{str.substr(0, date_type_len)};
994 auto period_str{str.substr(date_value_pos)};
995 if (type_str ==
"absolute")
998 set_value(
static_cast<uint16_t
>(std::stoll(period_str)));
1001 else if (type_str ==
"relative ")
1004 if (period == RelativeDatePeriod::ABSOLUTE)
1006 PWARN(
"Unknown period string in date option: '%s'",
1007 period_str.c_str());
1016 PWARN(
"Unknown date type string in date option: '%s'",
1027 if (!opt.deserialize(instr))
1028 throw std::invalid_argument(
"Invalid commodity string in stream.");
1078template std::
string GncOptionValue<
int>::serialize() const noexcept;
1079template std::
string GncOptionValue<int64_t>::serialize() const noexcept;
1080template std::
string GncOptionValue<
double>::serialize() const noexcept;
1081template std::
string GncOptionValue<
char*>::serialize() const noexcept;
1082template std::
string GncOptionValue<const
char*>::serialize() const noexcept;
1083template std::
string GncOptionValue<std::
string>::serialize() const noexcept;
1086template std::
string GncOptionValue<GncOptionReportPlacementVec>::serialize() const noexcept;
1087template std::
string GncOptionValue<GncOptionDateFormat>::serialize() const noexcept;
1090template
bool GncOptionValue<
bool>::deserialize(const std::
string&) noexcept;
1091template
bool GncOptionValue<
int>::deserialize(const std::
string&) noexcept;
1092template
bool GncOptionValue<int64_t>::deserialize(const std::
string&) noexcept;
1093template
bool GncOptionValue<
double>::deserialize(const std::
string&) noexcept;
1094template
bool GncOptionValue<
char*>::deserialize(const std::
string&) noexcept;
1095template
bool GncOptionValue<const
char*>::deserialize(const std::
string&) noexcept;
1096template
bool GncOptionValue<std::
string>::deserialize(const std::
string&) noexcept;
1099template
bool GncOptionValue<GncOptionReportPlacementVec>::deserialize(const std::
string&) noexcept;
1100template
bool GncOptionValue<GncOptionDateFormat>::deserialize(const std::
string&) noexcept;
class GncOptionCommodityValue Commodities are stored with their namespace and mnemonic instead of the...
Used for numeric ranges and plot sizes.
The generic option-value class.
General utilities for dealing with accounting periods.
Implementation templates and specializtions for GncOption values.
Business Interface: Object OWNERs.
GList * gnc_account_get_descendants_sorted(const Account *account)
This function returns a GList containing all the descendants of the specified account,...
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id,...
QofBook * qof_session_get_book(const QofSession *session)
Returns the QofBook of this session.
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
const char * gnc_commodity_get_namespace(const gnc_commodity *cm)
Retrieve the namespace for the specified commodity.
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Returns the commodity table associated with a book.
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
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.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
GList * account_type_list() const noexcept
Create a GList of account types to pass to gnc_account_sel_set_acct_filters.
GList * account_type_list() const noexcept
Create a GList of account types to pass to gnc_account_sel_set_acct_filters.
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
const gchar * QofIdType
QofIdType declaration.
QofIdType qof_collection_get_type(const QofCollection *col)
return the type that the collection stores
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
gboolean guid_equal(const GncGUID *guid_1, const GncGUID *guid_2)
Given two GUIDs, return TRUE if they are non-NULL and equal.
GncGUID guid_new_return(void)
Generate a new id.
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
QofCollection * qof_instance_get_collection(gconstpointer ptr)
Return the collection this instance belongs to.
const GncGUID * qof_entity_get_guid(gconstpointer ent)
#define PWARN(format, args...)
Log a warning.
time64 gnc_relative_date_to_time64(RelativeDatePeriod period, time64 now_t)
Convert a RelativeDatePeriod value to a concrete time64 by applying the value to the current time.
RelativeDatePeriod
Reporting periods relative to the current date.
GncOptionUIType
Used by GncOptionClassifier to indicate to dialog-options what control should be displayed for the op...
const char * gnc_relative_date_storage_string(RelativeDatePeriod per)
Provide the string representation of a relative date for persisting the value.
std::pair< QofIdTypeConst, GncGUID > GncItem
class GncOptionQofinstanceValue
RelativeDatePeriod gnc_relative_date_from_storage_string(const char *str)
Convert a relative date storage string back to a RelativeDatePeriod value.
QofIdTypeConst qofOwnerGetType(const GncOwner *owner)
return the type for the collection.
gboolean gncOwnerEqual(const GncOwner *a, const GncOwner *b)
Assess equality by checking.
GncOwner * gncOwnerNew(void)
These two functions are mainly for the convenience of scheme code.
QofInstance * qofOwnerGetOwner(const GncOwner *owner)
return the owner itself as an entity.
void qofOwnerSetEntity(GncOwner *owner, QofInstance *ent)
set the owner from the entity.
The type used to store guids in C.
This class is the parent of all option implementations.