mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
[c++options] Implement GncOptionGncOwnerValue class.
GncOwners aren't QofInstances and have limited lifetimes so an option must hold its own, wrapped in std::unique_ptr for memory management.
This commit is contained in:
parent
8db8105850
commit
a44b3664e2
@ -740,6 +740,10 @@ gnc_option_test_book_destroy(QofBook* book)
|
||||
wrap_unique_ptr(GncOptionDBPtr, GncOptionDB);
|
||||
|
||||
%ignore swig_get_option(GncOption&);
|
||||
%ignore GncOwnerDeleter;
|
||||
%ignore
|
||||
GncOptionGncOwnerValue::GncOptionGncOwnerValue(GncOptionGncOwnerValue &&);
|
||||
|
||||
%inline %{
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
@ -1151,7 +1155,6 @@ inline SCM return_scm_value(ValueType value)
|
||||
%template(gnc_make_bool_option) gnc_make_option<bool>;
|
||||
%template(gnc_make_int64_option) gnc_make_option<int64_t>;
|
||||
%template(gnc_make_query_option) gnc_make_option<const QofQuery*>;
|
||||
%template(gnc_make_owner_option) gnc_make_option<const GncOwner*>;
|
||||
|
||||
%rename (get_value) GncOption::get_scm_value;
|
||||
%rename (get_default_value) GncOption::get_scm_default_value;
|
||||
@ -1247,13 +1250,12 @@ inline SCM return_scm_value(ValueType value)
|
||||
return scm_simple_format(SCM_BOOL_F, date_fmt, value);
|
||||
}
|
||||
|
||||
if constexpr (is_same_decayed_v<decltype(option),
|
||||
GncOptionValue<const GncOwner*>>)
|
||||
if constexpr (is_GncOwnerValue_v<decltype(option)>)
|
||||
{
|
||||
auto value{option.get_value()};
|
||||
auto guid{scm_from_utf8_string(qof_instance_to_string(qofOwnerGetOwner(value)).c_str())};
|
||||
auto type{scm_from_long(gncOwnerGetType(value))};
|
||||
return scm_simple_format(SCM_BOOL_F, ticked_format_str,
|
||||
return scm_simple_format(SCM_BOOL_F, list_format_str,
|
||||
scm_list_1(scm_cons(type, guid)));
|
||||
}
|
||||
if constexpr (is_QofQueryValue_v<decltype(option)>)
|
||||
@ -1420,6 +1422,24 @@ inline SCM return_scm_value(ValueType value)
|
||||
}
|
||||
return;
|
||||
}
|
||||
if constexpr (is_GncOwnerValue_v<decltype(option)>)
|
||||
{
|
||||
if (scm_is_pair(new_value))
|
||||
{
|
||||
GncOwner owner{};
|
||||
owner.type = static_cast<GncOwnerType>(scm_to_int(scm_car(new_value)));
|
||||
auto strval{scm_to_utf8_string(scm_cdr(new_value))};
|
||||
owner.owner.undefined = qof_instance_from_string(strval, option.get_ui_type());
|
||||
option.set_value(&owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto val{scm_to_value<const GncOwner*>(new_value)};
|
||||
option.set_value(val);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if constexpr (is_QofQueryValue_v<decltype(option)>)
|
||||
{
|
||||
if (scm_is_pair(new_value))
|
||||
@ -1516,6 +1536,37 @@ inline SCM return_scm_value(ValueType value)
|
||||
}
|
||||
return;
|
||||
}
|
||||
if constexpr (is_GncOwnerValue_v<decltype(option)>)
|
||||
{
|
||||
if (scm_is_pair(new_value))
|
||||
{
|
||||
GncOwner owner{};
|
||||
owner.type = static_cast<GncOwnerType>(scm_to_int(scm_car(new_value)));
|
||||
auto strval{scm_to_utf8_string(scm_cdr(new_value))};
|
||||
owner.owner.undefined = qof_instance_from_string(strval, option.get_ui_type());
|
||||
option.set_default_value(&owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto val{scm_to_value<const GncOwner*>(new_value)};
|
||||
option.set_default_value(val);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if constexpr (is_QofQueryValue_v<decltype(option)>)
|
||||
{
|
||||
if (scm_is_pair(new_value))
|
||||
{
|
||||
auto val{gnc_scm2query(new_value)};
|
||||
option.set_default_value(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto val{scm_to_value<const QofQuery*>(new_value)};
|
||||
option.set_default_value(val);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if constexpr (is_same_decayed_v<decltype(option),
|
||||
GncOptionAccountSelValue>)
|
||||
{
|
||||
@ -1674,6 +1725,26 @@ gnc_register_multichoice_callback_option(GncOptionDBPtr& db,
|
||||
}
|
||||
}
|
||||
|
||||
static GncOption*
|
||||
gnc_make_gncowner_option(const char* section,
|
||||
const char* name, const char* key,
|
||||
const char* doc_string,
|
||||
const GncOwner* value,
|
||||
GncOptionUIType ui_type)
|
||||
{
|
||||
try {
|
||||
return new GncOption(GncOptionGncOwnerValue{section, name, key,
|
||||
doc_string,
|
||||
value, ui_type});
|
||||
}
|
||||
catch (const std::exception& err)
|
||||
{
|
||||
std::cerr << "Make GncOwner option threw unexpected exception"
|
||||
<< err.what() << ", option not created." << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static GncOption*
|
||||
gnc_make_account_list_option(const char* section,
|
||||
const char* name, const char* key,
|
||||
|
@ -297,7 +297,7 @@
|
||||
((eqv? owner-type GNC-OWNER-EMPLOYEE) (gncEmployeeLookupFlip guid book))
|
||||
((eqv? owner-type GNC-OWNER-JOB) (gncJobLookupFlip guid book)))))
|
||||
|
||||
(gnc-make-owner-option section name key docstring defval ui-type)))
|
||||
(gnc-make-gncowner-option section name key docstring defval ui-type)))
|
||||
(define-public (gnc:make-invoice-option section name key docstring getter validator)
|
||||
(issue-deprecation-warning "gnc:make-invoice-option is deprecated. Make and register the option in one command with gnc-register-ionvoice-option.")
|
||||
(let ((defval (if getter (getter) #f)))
|
||||
|
@ -588,7 +588,7 @@ veritatis et quasi architecto beatae vitae dicta sunt, explicabo.")
|
||||
(test-equal "owner unchanged" test-unchanged-section-output-template
|
||||
(gnc:generate-restore-forms odb "options"))
|
||||
(let* ((option (gnc:lookup-option odb "foo" "bar"))
|
||||
(test-template test-literal-output-template)
|
||||
(test-template test-list-output-template)
|
||||
(book (gnc-get-current-book))
|
||||
(owner (gncOwnerNew)))
|
||||
(gncOwnerInitCustomer owner (gncCustomerCreate book))
|
||||
|
@ -37,6 +37,112 @@ static const QofLogModule log_module{"gnc.options"};
|
||||
const std::string GncOptionMultichoiceValue::c_empty_string{""};
|
||||
const std::string GncOptionMultichoiceValue::c_list_string{"multiple values"};
|
||||
|
||||
static inline GncOwnerType
|
||||
ui_type_to_owner_type(GncOptionUIType ui_type)
|
||||
{
|
||||
if (ui_type == GncOptionUIType::CUSTOMER)
|
||||
return GNC_OWNER_CUSTOMER;
|
||||
if (ui_type == GncOptionUIType::VENDOR)
|
||||
return GNC_OWNER_VENDOR;
|
||||
if (ui_type == GncOptionUIType::EMPLOYEE)
|
||||
return GNC_OWNER_EMPLOYEE;
|
||||
return GNC_OWNER_NONE;
|
||||
}
|
||||
|
||||
static GncOwner*
|
||||
make_owner_ptr(const GncOwner* owner)
|
||||
{
|
||||
if (!owner)
|
||||
return nullptr;
|
||||
auto rv{gncOwnerNew()};
|
||||
gncOwnerCopy(owner, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
GncOptionGncOwnerValue::GncOptionGncOwnerValue(
|
||||
const char* section, const char* name,
|
||||
const char* key, const char* doc_string,
|
||||
const GncOwner* value, GncOptionUIType ui_type) :
|
||||
OptionClassifier{section, name, key, doc_string},
|
||||
m_ui_type(ui_type), m_value{make_owner_ptr(value)},
|
||||
m_default_value{make_owner_ptr(value)} {}
|
||||
|
||||
GncOptionGncOwnerValue::GncOptionGncOwnerValue(const GncOptionGncOwnerValue& from) :
|
||||
OptionClassifier{from.m_section, from.m_name, from.m_sort_tag,
|
||||
from.m_doc_string},
|
||||
m_ui_type(from.get_ui_type()), m_value{make_owner_ptr(from.get_value())},
|
||||
m_default_value{make_owner_ptr(from.get_default_value())} {}
|
||||
|
||||
void
|
||||
GncOptionGncOwnerValue::set_value(const GncOwner* new_value)
|
||||
{
|
||||
m_value.reset(make_owner_ptr(new_value));
|
||||
}
|
||||
|
||||
void
|
||||
GncOptionGncOwnerValue::set_default_value(const GncOwner *new_value)
|
||||
{
|
||||
m_value.reset(make_owner_ptr(new_value));
|
||||
m_default_value.reset(make_owner_ptr(new_value));
|
||||
}
|
||||
|
||||
const GncOwner*
|
||||
GncOptionGncOwnerValue::get_value() const
|
||||
{
|
||||
return m_value.get();
|
||||
}
|
||||
|
||||
const GncOwner*
|
||||
GncOptionGncOwnerValue::get_default_value() const
|
||||
{
|
||||
return m_default_value.get();
|
||||
}
|
||||
|
||||
void
|
||||
GncOptionGncOwnerValue::reset_default_value()
|
||||
{
|
||||
gncOwnerCopy(m_default_value.get(), m_value.get());
|
||||
}
|
||||
|
||||
bool
|
||||
GncOptionGncOwnerValue::is_changed() const noexcept
|
||||
{
|
||||
return gncOwnerEqual(m_value.get(), m_default_value.get());
|
||||
}
|
||||
|
||||
bool
|
||||
GncOptionGncOwnerValue::deserialize(const std::string& str) noexcept
|
||||
{
|
||||
try {
|
||||
auto guid{static_cast<GncGUID>(gnc::GUID::from_string(str))};
|
||||
auto inst = qof_instance_from_guid(&guid, m_ui_type);
|
||||
if (inst)
|
||||
{
|
||||
GncOwner owner{};
|
||||
owner.type = ui_type_to_owner_type(m_ui_type);
|
||||
owner.owner.undefined = inst;
|
||||
set_default_value(&owner);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (const gnc::guid_syntax_exception& err)
|
||||
{
|
||||
PWARN("Failed to convert %s to a GUID", str.c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string
|
||||
GncOptionGncOwnerValue::serialize() const noexcept
|
||||
{
|
||||
|
||||
auto owner{m_value.get()};
|
||||
gnc::GUID guid{*qof_instance_get_guid(static_cast<QofInstance*>(owner->owner.undefined))};
|
||||
std::string retval{guid.to_string()};
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
using GncItem = std::pair<QofIdTypeConst, GncGUID>;
|
||||
|
||||
static GncItem
|
||||
@ -60,6 +166,7 @@ get_current_root_account(void)
|
||||
{
|
||||
return gnc_book_get_root_account(get_current_book());
|
||||
}
|
||||
|
||||
static const QofInstance*
|
||||
qof_instance_from_gnc_item(const GncItem& item)
|
||||
{
|
||||
|
@ -113,6 +113,54 @@ private:
|
||||
ValueType m_default_value;
|
||||
};
|
||||
|
||||
|
||||
/** class GncOptionGncOwnerValue
|
||||
*
|
||||
* Unlike QofInstance based classes GncOwners are created on the fly, aren't
|
||||
* placed in QofCollection, and therefore their lifetimes have to be managed.
|
||||
* We use GncOwnerPtr for the purpose.
|
||||
*/
|
||||
struct GncOwnerDeleter
|
||||
{
|
||||
void operator()(GncOwner* o) {
|
||||
g_free(o);
|
||||
}
|
||||
};
|
||||
|
||||
using GncOwnerPtr = std::unique_ptr<GncOwner, GncOwnerDeleter>;
|
||||
|
||||
class GncOptionGncOwnerValue: public OptionClassifier {
|
||||
public:
|
||||
GncOptionGncOwnerValue(
|
||||
const char* section, const char* name,
|
||||
const char* key, const char* doc_string,
|
||||
const GncOwner* value,
|
||||
GncOptionUIType ui_type = GncOptionUIType::INTERNAL);
|
||||
GncOptionGncOwnerValue(const GncOptionGncOwnerValue& from);
|
||||
GncOptionGncOwnerValue(GncOptionGncOwnerValue&&) = default;
|
||||
~GncOptionGncOwnerValue() = default;
|
||||
const GncOwner* get_value() const;
|
||||
const GncOwner* get_default_value() const;
|
||||
void set_value(const GncOwner* new_value);
|
||||
void set_default_value(const GncOwner* new_value);
|
||||
void reset_default_value();
|
||||
bool is_changed() const noexcept;
|
||||
GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
|
||||
void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
|
||||
bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
|
||||
std::string serialize() const noexcept;
|
||||
bool deserialize(const std::string& str) noexcept;
|
||||
private:
|
||||
GncOptionUIType m_ui_type;
|
||||
GncOwnerPtr m_value;
|
||||
GncOwnerPtr m_default_value;
|
||||
};
|
||||
|
||||
/** class GncOptionQofinstanceValue
|
||||
*
|
||||
* QofInstances know what type they are but getting them to tell you is a pain
|
||||
* so we put them in a pair with a type identifier.
|
||||
*/
|
||||
using GncItem = std::pair<QofIdTypeConst, GncGUID>;
|
||||
|
||||
class GncOptionQofInstanceValue: public OptionClassifier {
|
||||
@ -201,6 +249,16 @@ QofInstance* qof_instance_from_string(const std::string& str,
|
||||
QofInstance* qof_instance_from_guid(GncGUID*, GncOptionUIType type);
|
||||
std::string qof_instance_to_string(const QofInstance* inst);
|
||||
|
||||
template <typename T>
|
||||
struct is_GncOwnerValue
|
||||
{
|
||||
static constexpr bool value =
|
||||
std::is_same_v<std::decay_t<T>, GncOptionGncOwnerValue>;
|
||||
};
|
||||
|
||||
template <typename T> inline constexpr bool
|
||||
is_GncOwnerValue_v = is_GncOwnerValue<T>::value;
|
||||
|
||||
template <typename T>
|
||||
struct is_QofInstanceValue
|
||||
{
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "gnc-option-impl.hpp"
|
||||
#include "gnc-option-uitype.hpp"
|
||||
#include "gnc-option-ui.hpp"
|
||||
#include "gncOwner.h"
|
||||
|
||||
static const char* log_module{"gnc.app-utils.gnc-option"};
|
||||
|
||||
@ -466,8 +467,6 @@ template GncOption::GncOption(const char*, const char*, const char*,
|
||||
const char*, std::string, GncOptionUIType);
|
||||
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*, const GncOwner*, GncOptionUIType);
|
||||
|
||||
template bool GncOption::get_value<bool>() const;
|
||||
template int GncOption::get_value<int>() const;
|
||||
@ -477,6 +476,7 @@ template uint16_t GncOption::get_value<uint16_t>() const;
|
||||
template const char* GncOption::get_value<const char*>() const;
|
||||
template std::string GncOption::get_value<std::string>() const;
|
||||
template const QofInstance* GncOption::get_value<const QofInstance*>() const;
|
||||
template const GncOwner* GncOption::get_value<const GncOwner*>() const;
|
||||
template gnc_commodity* GncOption::get_value<gnc_commodity*>() const;
|
||||
template const Account* GncOption::get_value<const Account*>() const;
|
||||
template RelativeDatePeriod GncOption::get_value<RelativeDatePeriod>() const;
|
||||
@ -506,6 +506,7 @@ template void GncOption::set_value(char*);
|
||||
template void GncOption::set_value(const char*);
|
||||
template void GncOption::set_value(std::string);
|
||||
template void GncOption::set_value(const QofInstance*);
|
||||
template void GncOption::set_value(const GncOwner*);
|
||||
template void GncOption::set_value(gnc_commodity*);
|
||||
template void GncOption::set_value(const Account*);
|
||||
template void GncOption::set_value(RelativeDatePeriod);
|
||||
@ -556,5 +557,3 @@ template GncOption* gnc_make_option<bool>(const char*, const char*, const char*,
|
||||
template GncOption* gnc_make_option<int64_t>(const char*, const char*,
|
||||
const char*, const char*, int64_t,
|
||||
GncOptionUIType);
|
||||
|
||||
|
||||
|
@ -56,6 +56,7 @@ using QofQuery = _QofQuery;
|
||||
struct QofInstance_s;
|
||||
using QofInstance = QofInstance_s;
|
||||
template <typename ValueType> class GncOptionValue;
|
||||
class GncOptionGncOwnerValue;
|
||||
class GncOptionQofInstanceValue;
|
||||
class GncOptionAccountListValue;
|
||||
class GncOptionAccountSelValue;
|
||||
@ -101,8 +102,8 @@ using GncOptionVariant = std::variant<GncOptionValue<std::string>,
|
||||
GncOptionValue<bool>,
|
||||
GncOptionValue<int64_t>,
|
||||
GncOptionQofInstanceValue,
|
||||
GncOptionGncOwnerValue,
|
||||
GncOptionValue<const QofQuery*>,
|
||||
GncOptionValue<const GncOwner*>,
|
||||
GncOptionValue<GncOptionReportPlacementVec>,
|
||||
GncOptionAccountListValue,
|
||||
GncOptionAccountSelValue,
|
||||
|
@ -809,8 +809,8 @@ gnc_register_owner_option(GncOptionDB* db, const char* section,
|
||||
default:
|
||||
uitype = GncOptionUIType::INTERNAL;
|
||||
};
|
||||
GncOption option{section, name, key, doc_string, value,
|
||||
uitype};
|
||||
GncOption option{GncOptionGncOwnerValue{section, name, key, doc_string,
|
||||
value, uitype}};
|
||||
db->register_option(section, std::move(option));
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user