25 #include "gnc-datetime.hpp" 33 #include "gnc-session.h" 36 static const QofLogModule log_module{
"gnc.options"};
38 const std::string GncOptionMultichoiceValue::c_empty_string{
""};
39 const std::string GncOptionMultichoiceValue::c_list_string{
"multiple values"};
41 static 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;
56 make_owner_ptr(
const GncOwner* owner)
61 gncOwnerCopy(owner, rv);
65 GncOptionGncOwnerValue::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())} {}
80 GncOptionGncOwnerValue::set_value(
const GncOwner* new_value)
82 m_value.reset(make_owner_ptr(new_value));
87 GncOptionGncOwnerValue::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));
94 GncOptionGncOwnerValue::get_value()
const 100 GncOptionGncOwnerValue::get_default_value()
const 102 return m_default_value.get();
106 GncOptionGncOwnerValue::reset_default_value()
108 gncOwnerCopy(m_default_value.get(), m_value.get());
112 GncOptionGncOwnerValue::is_changed() const noexcept
118 GncOptionGncOwnerValue::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());
140 GncOptionGncOwnerValue::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)));
160 static inline QofBook*
161 get_current_book(
void)
167 get_current_root_account(
void)
169 return gnc_book_get_root_account(get_current_book());
173 qof_instance_from_gnc_item(
const GncItem& item)
175 auto [type, guid] = item;
176 auto book{get_current_book()};
181 GncOptionQofInstanceValue::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()}
200 GncOptionQofInstanceValue::set_value(
const QofInstance* new_value)
202 m_value = make_gnc_item(new_value);
207 GncOptionQofInstanceValue::set_default_value(
const QofInstance *new_value)
209 m_value = m_default_value = make_gnc_item(new_value);
214 GncOptionQofInstanceValue::get_value()
const 216 return qof_instance_from_gnc_item(m_value);
220 GncOptionQofInstanceValue::get_default_value()
const 222 return qof_instance_from_gnc_item(m_default_value);
226 GncOptionQofInstanceValue::reset_default_value()
228 m_value = m_default_value;
232 GncOptionQofInstanceValue::is_changed() const noexcept
234 return m_value != m_default_value;
238 GncOptionQofInstanceValue::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());
259 GncOptionQofInstanceValue::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();
286 static gnc_commodity*
287 gnc_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(),
297 GncOptionCommodityValue::get_value()
const 299 return gnc_commodity_from_namespace_and_mnemonic(m_namespace, m_mnemonic);
303 GncOptionCommodityValue::get_default_value()
const 305 return gnc_commodity_from_namespace_and_mnemonic(m_default_namespace,
310 GncOptionCommodityValue::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.");
320 GncOptionCommodityValue::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.");
329 GncOptionCommodityValue::reset_default_value()
331 m_mnemonic = m_default_mnemonic;
332 m_namespace = m_default_namespace;
336 GncOptionCommodityValue::is_changed() const noexcept
338 return m_namespace != m_default_namespace || m_mnemonic != m_default_mnemonic;
342 GncOptionCommodityValue::validate(gnc_commodity* comm)
const noexcept
344 if (!GNC_IS_COMMODITY(comm))
352 GncOptionCommodityValue::serialize() const noexcept
357 return m_namespace +
":" + m_mnemonic;
361 GncOptionCommodityValue::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);
385 GncOptionAccountListValue::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());
410 GncOptionAccountListValue::get_value()
const 412 return !m_value.empty() ? m_value : get_default_value();
416 GncOptionAccountListValue::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);
447 GncOptionAccountListValue::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);
473 GncOptionAccountSelValue::validate(
const Account* value)
const 475 if (m_allowed.empty() || !value)
477 if (std::find(m_allowed.begin(), m_allowed.end(),
484 GncOptionAccountSelValue::get_value()
const 486 auto book{get_current_book()};
492 GncOptionAccountSelValue::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())
554 GncOptionDateValue::get_value() const noexcept
556 if (m_period == RelativeDatePeriod::ABSOLUTE)
562 GncOptionDateValue::get_default_value() const noexcept
564 if (m_default_period == RelativeDatePeriod::ABSOLUTE)
565 return m_default_date;
573 GncOptionDateValue::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();
583 GncOptionDateValue::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();
594 GncOptionDateValue::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];
604 GncOptionDateValue::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 {
611 return index != m_period_set.end() ? index - m_period_set.begin() : 0;
614 static const char* date_type_str[] {
"absolute",
"relative"};
617 GncOptionDateValue::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] <<
" . " <<
628 GncOptionDateValue::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();
732 template <
typename ValueType>
void 739 template <
typename ValueType>
void 742 m_value = m_default_value = new_value;
745 template <
typename ValueType>
void 748 m_value = m_default_value;
756 template <
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";
794 template <
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));
835 GncOptionAccountListValue::serialize() const noexcept
837 static const std::string no_value{
"No Value"};
843 for (
auto val : m_value)
855 GncOptionAccountListValue::deserialize(
const std::string& str) noexcept
870 m_value.push_back(guid);
877 GncOptionAccountSelValue::serialize() const noexcept
879 static const std::string no_value{
"No Value"};
889 GncOptionAccountSelValue::deserialize(
const std::string& str) noexcept
891 set_value(reinterpret_cast<Account*>(qof_instance_from_string(str, get_ui_type())));
896 GncOptionMultichoiceValue::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]);
920 GncOptionMultichoiceValue::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);
942 template <
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;
956 template <
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));
967 GncOptionDateValue::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];
987 GncOptionDateValue::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.");
1086 template
std::
string GncOptionValue<GncOptionReportPlacementVec>::serialize() const noexcept;
1087 template
std::
string GncOptionValue<GncOptionDateFormat>::serialize() const noexcept;
1092 template
bool GncOptionValue<int64_t>::deserialize(const
std::
string&) noexcept;
1095 template
bool GncOptionValue<const
char*>::deserialize(const
std::
string&) noexcept;
1099 template
bool GncOptionValue<GncOptionReportPlacementVec>::deserialize(const
std::
string&) noexcept;
1100 template
bool GncOptionValue<GncOptionDateFormat>::deserialize(const
std::
string&) noexcept;
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Returns the commodity table associated with a book.
std::pair< QofIdTypeConst, GncGUID > GncItem
class GncOptionQofinstanceValue
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...
Business Interface: Object OWNERs.
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.
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.
gboolean gncOwnerEqual(const GncOwner *a, const GncOwner *b)
Assess equality by checking.
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.
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...
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 implementations.
#define PWARN(format, args...)
Log a warning.
const gchar * QofIdType
QofIdType declaration.
QofBook * qof_session_get_book(const QofSession *session)
Returns the QofBook of this session.
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
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
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
The type used to store guids in C.
GncOwner * gncOwnerNew(void)
These two functions are mainly for the convenience of scheme code.
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...