mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Report options need to be saved when they're different from the defaults, book options need to be saved when their value changes regardless of whether it's the default value. That's dirty. Implement it.
578 lines
22 KiB
C++
578 lines
22 KiB
C++
/********************************************************************\
|
|
* gnc-option.cpp -- Application options system *
|
|
* Copyright (C) 2020 John Ralls <jralls@ceridwen.us> *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU General Public License as *
|
|
* published by the Free Software Foundation; either version 2 of *
|
|
* the License, or (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License*
|
|
* along with this program; if not, contact: *
|
|
* *
|
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
|
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
|
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
|
* *
|
|
\********************************************************************/
|
|
|
|
#include "gnc-option.hpp"
|
|
#include "gnc-option-impl.hpp"
|
|
#include "gnc-option-uitype.hpp"
|
|
#include "gnc-option-ui.hpp"
|
|
#include "gncOwner.h"
|
|
#include "kvp-value.hpp"
|
|
|
|
static const char* log_module{"gnc.app-utils.gnc-option"};
|
|
|
|
#include "qoflog.h"
|
|
|
|
template <typename ValueType,
|
|
typename std::enable_if_t<!is_OptionClassifier_v<ValueType>,
|
|
int>>
|
|
GncOption::GncOption(const char* section, const char* name,
|
|
const char* key, const char* doc_string,
|
|
ValueType value, GncOptionUIType ui_type) :
|
|
m_option{std::make_unique<GncOptionVariant>(
|
|
std::in_place_type<GncOptionValue<ValueType>>,
|
|
section, name, key, doc_string, value, ui_type)}
|
|
{
|
|
}
|
|
|
|
template <typename ValueType> ValueType
|
|
GncOption::get_value() const
|
|
{
|
|
return std::visit(
|
|
[](const auto& option)->ValueType {
|
|
if constexpr (is_same_decayed_v<decltype(option.get_value()),
|
|
ValueType>)
|
|
return option.get_value();
|
|
if constexpr (is_same_decayed_v<decltype(option),
|
|
GncOptionDateValue>)
|
|
{
|
|
if constexpr (is_same_decayed_v<ValueType,
|
|
RelativeDatePeriod>)
|
|
return option.get_period();
|
|
if constexpr (std::is_same_v<ValueType, time64>)
|
|
return option.get_value();
|
|
if constexpr (std::is_same_v<ValueType, uint16_t>)
|
|
return option.get_period_index();
|
|
return ValueType{};
|
|
}
|
|
if constexpr (is_same_decayed_v<decltype(option),
|
|
GncOptionMultichoiceValue>)
|
|
{
|
|
if constexpr (std::is_same_v<ValueType, uint16_t>)
|
|
return option.get_index();
|
|
if constexpr (is_same_decayed_v<ValueType,
|
|
GncMultichoiceOptionIndexVec>)
|
|
return option.get_multiple();
|
|
}
|
|
return ValueType {};
|
|
}, *m_option);
|
|
}
|
|
|
|
template <typename ValueType> ValueType
|
|
GncOption::get_default_value() const
|
|
{
|
|
return std::visit(
|
|
[](const auto& option)->ValueType {
|
|
if constexpr (is_same_decayed_v<decltype(option.get_value()),
|
|
ValueType>)
|
|
return option.get_default_value();
|
|
if constexpr (is_same_decayed_v<decltype(option),
|
|
GncOptionDateValue>)
|
|
{
|
|
if constexpr (is_same_decayed_v<ValueType,
|
|
RelativeDatePeriod>)
|
|
return option.get_default_period();
|
|
if constexpr (std::is_same_v<ValueType, time64>)
|
|
return option.get_value();
|
|
if constexpr (std::is_same_v<ValueType, uint16_t>)
|
|
return option.get_default_period_index();
|
|
return ValueType{};
|
|
}
|
|
if constexpr
|
|
(is_same_decayed_v<decltype(option),
|
|
GncOptionMultichoiceValue> &&
|
|
is_same_decayed_v<ValueType,
|
|
GncMultichoiceOptionIndexVec>)
|
|
return option.get_default_multiple();
|
|
return ValueType {};
|
|
}, *m_option);
|
|
|
|
}
|
|
|
|
template <typename ValueType> void
|
|
GncOption::set_value(ValueType value)
|
|
{
|
|
std::visit(
|
|
[value](auto& option) {
|
|
if constexpr
|
|
(is_same_decayed_v<decltype(option.get_value()), ValueType> ||
|
|
(is_same_decayed_v<decltype(option),
|
|
GncOptionDateValue> &&
|
|
(is_same_decayed_v<ValueType, RelativeDatePeriod> ||
|
|
std::is_same_v<ValueType, time64> ||
|
|
std::is_same_v<ValueType, uint16_t>)))
|
|
option.set_value(value);
|
|
else if constexpr (is_same_decayed_v<decltype(option),
|
|
GncOptionMultichoiceValue>)
|
|
{
|
|
if constexpr (is_same_decayed_v<ValueType,
|
|
GncMultichoiceOptionIndexVec>)
|
|
option.set_multiple(value);
|
|
else if constexpr
|
|
(std::is_same_v<ValueType, uint16_t> ||
|
|
is_same_decayed_v<ValueType, std::string> ||
|
|
std::is_same_v<std::remove_cv<ValueType>, char*>)
|
|
option.set_value(value);
|
|
}
|
|
else
|
|
PWARN("No set_value handler: get_value returns %s, value_type is %s",
|
|
typeid(option.get_value()).name(), typeid(value).name());
|
|
}, *m_option);
|
|
}
|
|
|
|
template <typename ValueType> void
|
|
GncOption::set_default_value(ValueType value)
|
|
{
|
|
std::visit(
|
|
[value](auto& option) {
|
|
if constexpr
|
|
(is_same_decayed_v<decltype(option.get_value()), ValueType>||
|
|
(is_same_decayed_v<decltype(option), GncOptionDateValue> &&
|
|
(is_same_decayed_v<ValueType, RelativeDatePeriod> ||
|
|
std::is_same_v<ValueType, time64> ||
|
|
std::is_same_v<ValueType, uint16_t>)))
|
|
option.set_default_value(value);
|
|
if constexpr (is_same_decayed_v<decltype(option),
|
|
GncOptionMultichoiceValue>)
|
|
{
|
|
if constexpr (is_same_decayed_v<ValueType,
|
|
GncMultichoiceOptionIndexVec>)
|
|
option.set_default_multiple(value);
|
|
else if constexpr
|
|
(std::is_same_v<ValueType, uint16_t> ||
|
|
is_same_decayed_v<ValueType, std::string> ||
|
|
std::is_same_v<std::remove_cv<ValueType>, char*>)
|
|
option.set_default_value(value);
|
|
}
|
|
}, *m_option);
|
|
}
|
|
void
|
|
GncOption::reset_default_value()
|
|
{
|
|
std::visit([](auto& option) { option.reset_default_value(); }, *m_option);
|
|
}
|
|
|
|
template <typename ValueType> void
|
|
GncOption::get_limits(ValueType& max, ValueType& min, ValueType& step) const noexcept
|
|
{
|
|
std::visit([&max, &min, &step](const auto& option) {
|
|
if constexpr
|
|
(is_same_decayed_v<decltype(option),
|
|
GncOptionRangeValue<ValueType>>)
|
|
option.get_limits(max, min, step);
|
|
}, *m_option);
|
|
}
|
|
|
|
const std::string&
|
|
GncOption::get_section() const
|
|
{
|
|
return std::visit([](const auto& option)->const std::string& {
|
|
return option.m_section;
|
|
}, *m_option);
|
|
}
|
|
|
|
const std::string&
|
|
GncOption::get_name() const
|
|
{
|
|
return std::visit([](const auto& option)->const std::string& {
|
|
return option.m_name;
|
|
}, *m_option);
|
|
}
|
|
|
|
const std::string&
|
|
GncOption::get_key() const
|
|
{
|
|
return std::visit([](const auto& option)->const std::string& {
|
|
return option.m_sort_tag;
|
|
}, *m_option);
|
|
}
|
|
|
|
const std::string&
|
|
GncOption::get_docstring() const
|
|
{
|
|
return std::visit([](const auto& option)->const std::string& {
|
|
return option.m_doc_string;
|
|
}, *m_option);
|
|
}
|
|
|
|
void
|
|
GncOption::set_ui_item(GncOptionUIItemPtr&& ui_item)
|
|
{
|
|
|
|
auto opt_ui_type = std::visit([](const auto& option)->GncOptionUIType {
|
|
return option.get_ui_type();
|
|
}, *m_option);
|
|
|
|
//ui_item may be nullptr to free the old m_ui_item.
|
|
if (ui_item && ui_item->get_ui_type() != opt_ui_type)
|
|
{
|
|
PERR("Setting option %s:%s UI element failed, mismatched UI types.",
|
|
get_section().c_str(), get_name().c_str());
|
|
return;
|
|
}
|
|
|
|
m_ui_item = std::move(ui_item);
|
|
}
|
|
|
|
void
|
|
GncOption::set_ui_item_selectable(bool selectable) const noexcept
|
|
{
|
|
if (m_ui_item)
|
|
m_ui_item->set_selectable(selectable);
|
|
}
|
|
|
|
const GncOptionUIType
|
|
GncOption::get_ui_type() const
|
|
{
|
|
return std::visit([](const auto& option)->GncOptionUIType {
|
|
return option.get_ui_type();
|
|
}, *m_option);
|
|
}
|
|
|
|
GncOptionUIItem* const
|
|
GncOption::get_ui_item() const
|
|
{
|
|
return m_ui_item.get();
|
|
}
|
|
|
|
void
|
|
GncOption::set_ui_item_from_option()
|
|
{
|
|
if (!m_ui_item)
|
|
return;
|
|
m_ui_item->set_ui_item_from_option(*this);
|
|
}
|
|
|
|
void
|
|
GncOption::set_option_from_ui_item()
|
|
{
|
|
if (!m_ui_item)
|
|
return;
|
|
m_ui_item->set_option_from_ui_item(*this);
|
|
}
|
|
|
|
void
|
|
GncOption::make_internal()
|
|
{
|
|
if (m_ui_item)
|
|
{
|
|
PERR("Option %s:%s has a UI Element, can't be INTERNAL.",
|
|
get_section().c_str(), get_name().c_str());
|
|
return;
|
|
}
|
|
std::visit([](auto& option) {
|
|
option.make_internal();
|
|
}, *m_option);
|
|
}
|
|
|
|
bool
|
|
GncOption::is_internal()
|
|
{
|
|
return std::visit([](auto& option)->bool {
|
|
return option.is_internal();
|
|
}, *m_option);
|
|
}
|
|
|
|
void
|
|
GncOption::mark_saved() noexcept
|
|
{
|
|
std::visit([](auto& option)->void {
|
|
option.mark_saved();
|
|
}, *m_option);
|
|
}
|
|
|
|
bool
|
|
GncOption::is_dirty() const noexcept
|
|
{
|
|
return std::visit([](const auto& option)->bool {
|
|
return option.is_dirty();
|
|
}, *m_option);
|
|
}
|
|
|
|
bool
|
|
GncOption::is_changed() const noexcept
|
|
{
|
|
return std::visit([](const auto& option)->bool {
|
|
return option.is_changed();
|
|
}, *m_option);
|
|
}
|
|
|
|
bool
|
|
GncOption::is_multiselect() const noexcept
|
|
{
|
|
return std::visit(
|
|
[](const auto& option)->bool {
|
|
if constexpr (is_same_decayed_v<decltype(option),
|
|
GncOptionAccountListValue>)
|
|
return option.is_multiselect();
|
|
else
|
|
return false;
|
|
}, *m_option);
|
|
}
|
|
|
|
template<typename ValueType> bool
|
|
GncOption::validate(ValueType value) const
|
|
{
|
|
return std::visit(
|
|
[value] (const auto& option) -> bool {
|
|
if constexpr ((is_same_decayed_v<decltype(option),
|
|
GncOptionMultichoiceValue> &&
|
|
is_same_decayed_v<ValueType, std::string>) ||
|
|
(is_same_decayed_v<decltype(option),
|
|
GncOptionMultichoiceValue> &&
|
|
is_same_decayed_v<ValueType,
|
|
GncMultichoiceOptionIndexVec>) ||
|
|
(is_same_decayed_v<decltype(option),
|
|
GncOptionCommodityValue> &&
|
|
is_same_decayed_v<ValueType, gnc_commodity*>))
|
|
return option.validate(value);
|
|
else
|
|
return false;
|
|
}, *m_option);
|
|
}
|
|
|
|
std::uint16_t
|
|
GncOption::num_permissible_values() const
|
|
{
|
|
return std::visit(
|
|
[] (const auto& option) -> uint16_t {
|
|
if constexpr (is_same_decayed_v<decltype(option),
|
|
GncOptionMultichoiceValue> ||
|
|
is_same_decayed_v<decltype(option),
|
|
GncOptionDateValue>)
|
|
return option.num_permissible_values();
|
|
else
|
|
return uint16_t_max;
|
|
}, *m_option);
|
|
}
|
|
|
|
std::uint16_t
|
|
GncOption::permissible_value_index(const char* value) const
|
|
{
|
|
return std::visit(
|
|
[&value] (const auto& option) -> uint16_t {
|
|
if constexpr (is_same_decayed_v<decltype(option),
|
|
GncOptionMultichoiceValue> ||
|
|
is_same_decayed_v<decltype(option),
|
|
GncOptionDateValue>)
|
|
return option.permissible_value_index(value);
|
|
else
|
|
return uint16_t_max;
|
|
}, *m_option);
|
|
}
|
|
|
|
const char*
|
|
GncOption::permissible_value(std::uint16_t index) const
|
|
{
|
|
return std::visit([index] (const auto& option) -> const char* {
|
|
if constexpr (std::is_same_v<std::decay_t<decltype(option)>,
|
|
GncOptionMultichoiceValue> ||
|
|
std::is_same_v<std::decay_t<decltype(option)>,
|
|
GncOptionDateValue>)
|
|
return option.permissible_value(index);
|
|
else
|
|
return "";
|
|
}, *m_option);
|
|
}
|
|
|
|
const char*
|
|
GncOption::permissible_value_name(std::uint16_t index) const
|
|
{
|
|
return std::visit([index] (const auto& option) -> const char* {
|
|
if constexpr (std::is_same_v<std::decay_t<decltype(option)>,
|
|
GncOptionMultichoiceValue> ||
|
|
std::is_same_v<std::decay_t<decltype(option)>,
|
|
GncOptionDateValue>)
|
|
return option.permissible_value_name(index);
|
|
else
|
|
return "";
|
|
}, *m_option);
|
|
}
|
|
|
|
GList*
|
|
GncOption::account_type_list() const noexcept
|
|
{
|
|
return std::visit([] (const auto& option) -> GList* {
|
|
if constexpr (std::is_same_v<std::decay_t<decltype(option)>,
|
|
GncOptionAccountListValue>)
|
|
return option.account_type_list();
|
|
else
|
|
return nullptr;
|
|
}, *m_option);
|
|
}
|
|
|
|
bool
|
|
GncOption::is_alternate() const noexcept
|
|
{
|
|
return std::visit([](auto& option) -> bool {
|
|
if constexpr(is_RangeValue_v<decltype(option)>)
|
|
return option.is_alternate();
|
|
return false;
|
|
}, *m_option);
|
|
}
|
|
|
|
void
|
|
GncOption::set_alternate(bool alt) noexcept
|
|
{
|
|
std::visit([alt](auto& option) {
|
|
if constexpr(is_RangeValue_v<decltype(option)>)
|
|
option.set_alternate(alt);
|
|
}, *m_option);
|
|
}
|
|
|
|
std::string
|
|
GncOption::serialize() const
|
|
{
|
|
if (m_option->valueless_by_exception())
|
|
return "Valueless Option";
|
|
return std::visit([&](auto& option) -> std::string {
|
|
return option.serialize();
|
|
}, *m_option);
|
|
}
|
|
|
|
bool
|
|
GncOption::deserialize(const std::string& str)
|
|
{
|
|
return std::visit([&str](auto& option) -> bool {
|
|
return option.deserialize(str);
|
|
}, *m_option);
|
|
}
|
|
|
|
std::istream&
|
|
GncOption::in_stream(std::istream& iss)
|
|
{
|
|
return std::visit([&iss](auto& option) -> std::istream& {
|
|
iss >> option;
|
|
return iss;
|
|
}, *m_option);
|
|
}
|
|
|
|
/* We must instantiate all of the templates we need here because we don't expose
|
|
* the template implementation in the public header.
|
|
*/
|
|
|
|
|
|
template GncOption::GncOption(const char*, const char*, const char*,
|
|
const char*, bool, GncOptionUIType);
|
|
//template GncOption::GncOption(const char*, const char*, const char*,
|
|
// const char*, int, GncOptionUIType);
|
|
template GncOption::GncOption(const char*, const char*, const char*,
|
|
const char*, int64_t, GncOptionUIType);
|
|
//template GncOption::GncOption(const char*, const char*, const char*,
|
|
// const char*, const char*, GncOptionUIType);
|
|
//template GncOption::GncOption(const char*, const char*, const char*,
|
|
// const char*, double, GncOptionUIType);
|
|
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 bool GncOption::get_value<bool>() const;
|
|
template int GncOption::get_value<int>() const;
|
|
template int64_t GncOption::get_value<int64_t>() const;
|
|
template double GncOption::get_value<double>() const;
|
|
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;
|
|
template GncOptionAccountList GncOption::get_value<GncOptionAccountList>() const;
|
|
template GncMultichoiceOptionIndexVec GncOption::get_value<GncMultichoiceOptionIndexVec>() const;
|
|
template GncOptionReportPlacementVec GncOption::get_value<GncOptionReportPlacementVec>() const;
|
|
|
|
template bool GncOption::get_default_value<bool>() const;
|
|
template int GncOption::get_default_value<int>() const;
|
|
template int64_t GncOption::get_default_value<int64_t>() const;
|
|
template double GncOption::get_default_value<double>() const;
|
|
template const char* GncOption::get_default_value<const char*>() const;
|
|
template std::string GncOption::get_default_value<std::string>() const;
|
|
template const QofInstance* GncOption::get_default_value<const QofInstance*>() const;
|
|
template gnc_commodity* GncOption::get_default_value<gnc_commodity*>() const;
|
|
template const Account* GncOption::get_default_value<const Account*>() const;
|
|
template RelativeDatePeriod GncOption::get_default_value<RelativeDatePeriod>() const;
|
|
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 void GncOption::set_value(bool);
|
|
template void GncOption::set_value(int);
|
|
template void GncOption::set_value(int64_t);
|
|
template void GncOption::set_value(double);
|
|
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);
|
|
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_default_value(bool);
|
|
template void GncOption::set_default_value(int);
|
|
template void GncOption::set_default_value(int64_t);
|
|
template void GncOption::set_default_value(double);
|
|
template void GncOption::set_default_value(char*);
|
|
template void GncOption::set_default_value(const char*);
|
|
template void GncOption::set_default_value(std::string);
|
|
template void GncOption::set_default_value(const QofInstance*);
|
|
template void GncOption::set_default_value(const Account*);
|
|
template void GncOption::set_default_value(RelativeDatePeriod);
|
|
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::get_limits(double&, double&, double&) const noexcept;
|
|
template void GncOption::get_limits(int&, int&, int&) const noexcept;
|
|
template bool GncOption::validate(bool) const;
|
|
template bool GncOption::validate(int) const;
|
|
template bool GncOption::validate(int64_t) const;
|
|
template bool GncOption::validate(double) const;
|
|
template bool GncOption::validate(const char*) const;
|
|
template bool GncOption::validate(std::string) const;
|
|
template bool GncOption::validate(const QofInstance*) const;
|
|
template bool GncOption::validate(gnc_commodity*) const;
|
|
template bool GncOption::validate(const Account*) const;
|
|
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 GncOption* gnc_make_option<const std::string&>(const char*,
|
|
const char*,
|
|
const char*,
|
|
const char*,
|
|
const std::string&,
|
|
GncOptionUIType);
|
|
template GncOption* gnc_make_option<bool>(const char*, const char*, const char*,
|
|
const char*, bool, GncOptionUIType);
|
|
template GncOption* gnc_make_option<int64_t>(const char*, const char*,
|
|
const char*, const char*, int64_t,
|
|
GncOptionUIType);
|