LCOV - code coverage report
Current view: top level - libgnucash/engine - gnc-optiondb.cpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 53.0 % 608 322
Test Date: 2026-11-02 18:19:43 Functions: 56.0 % 100 56
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /********************************************************************\
       2              :  * gnc-optiondb.cpp -- Collection of GncOption objects              *
       3              :  * Copyright (C) 2019 John Ralls <jralls@ceridwen.us>               *
       4              :  *                                                                  *
       5              :  * This program is free software; you can redistribute it and/or    *
       6              :  * modify it under the terms of the GNU General Public License as   *
       7              :  * published by the Free Software Foundation; either version 2 of   *
       8              :  * the License, or (at your option) any later version.              *
       9              :  *                                                                  *
      10              :  * This program is distributed in the hope that it will be useful,  *
      11              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
      12              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
      13              :  * GNU General Public License for more details.                     *
      14              :  *                                                                  *
      15              :  * You should have received a copy of the GNU General Public License*
      16              :  * along with this program; if not, contact:                        *
      17              :  *                                                                  *
      18              :  * Free Software Foundation           Voice:  +1-617-542-5942       *
      19              :  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
      20              :  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
      21              :  *                                                                  *
      22              : \********************************************************************/
      23              : 
      24              : #include <cstdint>
      25              : #include <functional>
      26              : #include <string>
      27              : #include <limits>
      28              : #include <sstream>
      29              : #include "gnc-option-uitype.hpp"
      30              : #include "kvp-value.hpp"
      31              : #include "kvp-frame.hpp"
      32              : #include "qofbookslots.h"
      33              : #include "guid.hpp"
      34              : #include "gnc-optiondb.h"
      35              : #include "gnc-optiondb.hpp"
      36              : #include "gnc-optiondb-impl.hpp"
      37              : #include "gnc-option-ui.hpp"
      38              : 
      39              : #include "gnc-session.h"
      40              : constexpr const char* log_module{G_LOG_DOMAIN};
      41              : 
      42              : constexpr auto stream_max = std::numeric_limits<std::streamsize>::max();
      43              : using AliasedOption = std::pair<const char*, const char*>;
      44              : using OptionAlias = std::pair<const char*, AliasedOption>;
      45              : using OptionAliases = std::vector<OptionAlias>;
      46              : class Aliases
      47              : {
      48              :     static const OptionAliases c_option_aliases;
      49              : public:
      50         1290 :     static const AliasedOption* find_alias (const char* old_name)
      51              :     {
      52         1290 :         if (!old_name) return nullptr;
      53              :         const auto alias =
      54         1290 :             std::find_if(c_option_aliases.begin(), c_option_aliases.end(),
      55        51500 :                          [old_name](auto alias){
      56        51500 :                              return std::strcmp(old_name, alias.first) == 0;
      57              :                          });
      58         2580 :         if (alias == c_option_aliases.end())
      59         1280 :             return nullptr;
      60              : 
      61           10 :         return &alias->second;
      62              :     }
      63              : };
      64              : 
      65              : const OptionAliases Aliases::c_option_aliases
      66              : {
      67              :     {"Accounts to include", {nullptr, "Accounts"}},
      68              :     {"Exclude transactions between selected accounts?",
      69              :         {nullptr, "Exclude transactions between selected accounts"}},
      70              :     {"Filter Accounts", {nullptr, "Filter By…"}},
      71              :     {"Flatten list to depth limit?",
      72              :         {nullptr, "Flatten list to depth limit"}},
      73              :     {"From", {nullptr, "Start Date"}},
      74              :     {"Report Accounts", {nullptr, "Accounts"}},
      75              :     {"Report Currency", {nullptr, "Report's currency"}},
      76              :     {"Show Account Code?", {nullptr, "Show Account Code"}},
      77              :     {"Show Full Account Name?", {nullptr, "Show Full Account Name"}},
      78              :     {"Show Multi-currency Totals?",
      79              :         {nullptr, "Show Multi-currency Totals"}},
      80              :     {"Show zero balance items?", {nullptr, "Show zero balance items"}},
      81              :     {"Sign Reverses?", {nullptr, "Sign Reverses"}},
      82              :     {"To", {nullptr, "End Date"}},
      83              :     {"Charge Type", {nullptr, "Action"}}, // easy-invoice.scm, renamed June 2018
      84              :     // the following 4 options in income-gst-statement.scm renamed Dec 2018
      85              :     {"Individual income columns", {nullptr, "Individual sales columns"}},
      86              :     {"Individual expense columns",
      87              :         {nullptr, "Individual purchases columns"}},
      88              :     {"Remittance amount", {nullptr, "Gross Balance"}},
      89              :     {"Net Income", {nullptr, "Net Balance"}},
      90              :     // transaction.scm:
      91              :     {"Use Full Account Name?", {nullptr, "Use Full Account Name"}},
      92              :     {"Use Full Other Account Name?",
      93              :         {nullptr, "Use Full Other Account Name"}},
      94              :     {"Void Transactions?", {"Filter", "Void Transactions"}},
      95              :     {"Void Transactions", {"Filter", "Void Transactions"}},
      96              :     {"Account Substring", {"Filter", "Account Name Filter"}},
      97              :     {"Enable links", {nullptr, "Enable Links"}},
      98              :     // trep-engine: moved currency options to own tab
      99              :     {"Common Currency", {"Currency", "Common Currency"}},
     100              :     {"Show original currency amount",
     101              :         {"Currency", "Show original currency amount"}},
     102              :     {"Report's currency", {"Currency", "Report's currency"}},
     103              :     {"Reconcile Status", {nullptr, "Reconciled Status"}},
     104              :     // new-owner-report.scm, renamed Oct 2020 to differentiate with
     105              :     // Document Links:
     106              :     {"Links", {nullptr, "Transaction Links"}},
     107              :     // invoice.scm, renamed November 2018
     108              :     {"Individual Taxes", {nullptr, "Use Detailed Tax Summary"}},
     109              :     {"Show Accounts until level", {nullptr, "Levels of Subaccounts"}},
     110              :     {"Invoice number", {nullptr, "Invoice Number"}},
     111              :     {"Report title", {nullptr, "Report Title"}},
     112              :     {"Extra notes", {nullptr, "Extra Notes"}},
     113              :     // income-gst-statement.scm
     114              :     {"default format", {nullptr, "Default Format"}},
     115              :     {"Report format", {nullptr, "Report Format"}},
     116              :     // ... replaced to …, Dec 2022
     117              :     {"Filter By...", {nullptr, "Filter By…"}},
     118              :     {"Specify date to filter by...", {nullptr, "Specify date to filter by…"}},
     119              :     // trep-engine:
     120              :     {"Running Balance", {nullptr, "Account Balance"}},
     121              :     {"Totals", {nullptr, "Grand Total"}},
     122              : };
     123              : 
     124              : static bool
     125       122427 : operator==(const std::string& str, const char* cstr)
     126              : {
     127       122427 :     return strcmp(str.c_str(), cstr) == 0;
     128              : }
     129              : 
     130              : void
     131           83 : GncOptionSection::foreach_option(std::function<void(GncOption&)> func)
     132              : {
     133           83 :     std::for_each(m_options.begin(), m_options.end(), func);
     134           83 : }
     135              : 
     136              : void
     137            0 : GncOptionSection::foreach_option(std::function<void(const GncOption&)> func) const
     138              : {
     139            0 :     std::for_each(m_options.begin(), m_options.end(), func);
     140            0 : }
     141              : 
     142              : void
     143         6146 : GncOptionSection::add_option(GncOption&& option)
     144              : {
     145        12292 :     m_options.push_back(std::move(option));
     146         6146 :     if (!std::is_sorted(m_options.begin(), m_options.end()))
     147         1560 :         std::sort(m_options.begin(), m_options.end());
     148         6146 : }
     149              : 
     150              : void
     151            4 : GncOptionSection::remove_option(const char* name)
     152              : {
     153            8 :     m_options.erase(std::remove_if(m_options.begin(), m_options.end(),
     154           10 :                                    [name](const auto& option) -> bool
     155              :                                    {
     156           10 :                                        return option.get_name() == name;
     157            4 :                                    }), m_options.end());
     158            4 : }
     159              : 
     160              : const GncOption*
     161        21342 : GncOptionSection::find_option(const char* name) const
     162              : {
     163        21342 :     auto option = std::find_if(m_options.begin(), m_options.end(),
     164       122417 :                                [name](auto& option) -> bool {
     165       122417 :                                    return option.get_name() == name;
     166              :                                });
     167        42684 :     if (option != m_options.end())
     168        20697 :         return &*option;
     169              : 
     170          645 :     auto alias = Aliases::find_alias(name);
     171          645 :     if (!alias || alias->first) // No alias or the alias
     172          637 :         return nullptr;         // is in a different section.
     173            8 :     return find_option(alias->second);
     174              : }
     175              : 
     176          265 : GncOptionDB::GncOptionDB() : m_default_section{} {}
     177              : 
     178            0 : GncOptionDB::GncOptionDB(QofBook* book) : GncOptionDB() {}
     179              : 
     180              : void
     181         6146 : GncOptionDB::register_option(const char* sectname, GncOption&& option)
     182              : {
     183         6146 :     auto section = find_section(sectname);
     184              : 
     185         6146 :     if (section)
     186              :     {
     187        10470 :         section->add_option(std::move(option));
     188         5235 :         return;
     189              :     }
     190              : 
     191          911 :     m_sections.push_back(std::make_shared<GncOptionSection>(sectname));
     192         1822 :     m_sections.back()->add_option(std::move(option));
     193          911 :     if (!std::is_sorted(m_sections.begin(), m_sections.end()))
     194          435 :         std::sort(m_sections.begin(), m_sections.end());
     195              : }
     196              : 
     197              : void
     198           20 : GncOptionDB::register_option(const char* sectname, GncOption* option)
     199              : {
     200           20 :     register_option(sectname, std::move(*option));
     201           20 :     delete option;
     202           20 : }
     203              : 
     204              : void
     205            4 : GncOptionDB::unregister_option(const char* sectname, const char* name)
     206              : {
     207            4 :     auto section = find_section(sectname);
     208            4 :     if (section)
     209            4 :         section->remove_option(name);
     210            4 : }
     211              : 
     212              : void
     213          165 : GncOptionDB::set_default_section(const char* sectname)
     214              : {
     215          165 :     m_default_section = find_section(sectname);
     216          165 : }
     217              : 
     218              : const GncOptionSection* const
     219            0 : GncOptionDB::get_default_section() const noexcept
     220              : {
     221            0 :         return m_default_section;
     222              : }
     223              : 
     224              : const GncOptionSection*
     225        27657 : GncOptionDB::find_section(const std::string& section) const
     226              : {
     227        27657 :     auto db_section = std::find_if(m_sections.begin(), m_sections.end(),
     228        73762 :                                    [&section](auto& sect) -> bool
     229              :                                    {
     230        73762 :                                        return section == sect->get_name();
     231              :                                    });
     232        82052 :     return db_section == m_sections.end() ? nullptr : db_section->get();
     233              : }
     234              : 
     235              : const GncOption*
     236        21342 : GncOptionDB::find_option(const std::string& section, const char* name) const
     237              : {
     238        21342 :     auto db_section = const_cast<GncOptionDB*>(this)->find_section(section);
     239        21342 :     const GncOption* option = nullptr;
     240        21342 :     if (db_section)
     241        21334 :         option = db_section->find_option(name);
     242        21342 :     if (option)
     243        20697 :         return option;
     244          645 :     auto alias = Aliases::find_alias(name);
     245              :      /* Only try again if alias.first isn't
     246              :      * nullptr. GncOptionSection::find_option already checked if the alias
     247              :      * should have been in the same section.
     248              :      */
     249          645 :     if (alias && alias->first && section != alias->first)
     250            3 :         return find_option(alias->first, alias->second);
     251          644 :     return nullptr;
     252              : }
     253              : 
     254              : std::string
     255            7 : GncOptionDB::lookup_string_option(const char* section, const char* name)
     256              : {
     257            7 :     static const std::string empty_string{};
     258              : 
     259            7 :     auto db_opt = find_option(section, name);
     260            7 :     if (!db_opt)
     261            1 :         return empty_string;
     262            6 :     return db_opt->get_value<std::string>();
     263              : }
     264              : 
     265              : void
     266           40 : GncOptionDB::make_internal(const char* section, const char* name)
     267              : {
     268              : 
     269           40 :     auto db_opt = find_option(section, name);
     270           40 :     if (db_opt)
     271           40 :         db_opt->make_internal();
     272           40 : }
     273              : 
     274              : std::ostream&
     275            2 : GncOptionDB::save_option_key_value(std::ostream& oss,
     276              :                                    const std::string& section,
     277              :                                    const std::string& name) const noexcept
     278              : {
     279              : 
     280            2 :     auto db_opt = find_option(section, name.c_str());
     281            2 :     if (!db_opt || !db_opt->is_changed())
     282            1 :         return oss;
     283            1 :     oss << section.substr(0, classifier_size_max) << ":" <<
     284            1 :         name.substr(0, classifier_size_max) << "=" << *db_opt << ";";
     285            1 :     return oss;
     286              : }
     287              : 
     288              : std::istream&
     289            1 : GncOptionDB::load_option_key_value(std::istream& iss)
     290              : {
     291              : 
     292              :     char section[classifier_size_max], name[classifier_size_max];
     293            1 :     iss.getline(section, classifier_size_max, ':');
     294            1 :     iss.getline(name, classifier_size_max, '=');
     295            1 :     if (!iss)
     296            0 :         throw std::invalid_argument("Section or name delimiter not found or values too long");
     297            1 :     auto option = find_option(section, name);
     298            1 :     if (!option)
     299            0 :         iss.ignore(stream_max, ';');
     300              :     else
     301              :     {
     302            1 :         std::string value;
     303            1 :         std::getline(iss, value, ';');
     304            1 :         std::istringstream item_iss{value};
     305            1 :         item_iss >> *option;
     306            1 :     }
     307            1 :     return iss;
     308              : }
     309              : 
     310              : std::ostream&
     311            0 : GncOptionDB::save_to_key_value(std::ostream& oss) const noexcept
     312              : {
     313              : 
     314            0 :     foreach_section(
     315            0 :         [&oss](const GncOptionSectionPtr& section)
     316              :         {
     317            0 :             oss << "[Options]\n";
     318            0 :             section->foreach_option(
     319            0 :                 [&oss, &section](auto& option)
     320              :                 {
     321            0 :                     if (option.is_changed())
     322            0 :                         oss << section->get_name().substr(0, classifier_size_max) <<
     323            0 :                             ':' << option.get_name().substr(0, classifier_size_max) <<
     324            0 :                             '=' << option << '\n';
     325            0 :                 });
     326            0 :         });
     327            0 :     return oss;
     328              : }
     329              : 
     330              : std::istream&
     331            0 : GncOptionDB::load_from_key_value(std::istream& iss)
     332              : {
     333            0 :     if (iss.peek() == '[')
     334              :     {
     335              :         char buf[classifier_size_max];
     336            0 :         iss.getline(buf, classifier_size_max);
     337            0 :         if (strcmp(buf, "[Options]") != 0) // safe
     338            0 :             throw std::runtime_error("Wrong secion header for options.");
     339              :     }
     340              :     // Otherwise assume we were sent here correctly:
     341            0 :     while (iss.peek() != '[') //Indicates the start of the next file section
     342              :     {
     343            0 :         load_option_key_value(iss);
     344              :     }
     345            0 :     return iss;
     346              : }
     347              : 
     348              : size_t
     349            0 : GncOptionDB::register_callback(GncOptionDBChangeCallback cb, void* data)
     350              : {
     351              :     constexpr std::hash<GncOptionDBChangeCallback> cb_hash;
     352            0 :     auto id{cb_hash(cb)};
     353            0 :     if (std::find_if(m_callbacks.begin(), m_callbacks.end(),
     354            0 :                      [id](auto&cb)->bool{ return cb.m_id == id; }) == m_callbacks.end())
     355            0 :         m_callbacks.emplace_back(id, cb, data);
     356            0 :     return id;
     357              : }
     358              : 
     359              : void
     360            0 : GncOptionDB::unregister_callback(size_t id)
     361              : {
     362            0 :     m_callbacks.erase(std::remove_if(m_callbacks.begin(), m_callbacks.end(),
     363            0 :                                      [id](auto& cb)->bool { return cb.m_id == id; }),
     364            0 :                       m_callbacks.end());
     365            0 : }
     366              : 
     367              : void
     368            0 : GncOptionDB::run_callbacks()
     369              : {
     370            0 :     std::for_each(m_callbacks.begin(), m_callbacks.end(),
     371            0 :                   [](auto& cb)->void { cb.m_func(cb.m_data); });
     372            0 : }
     373              : 
     374              : static inline void
     375            0 : counter_option_path(const GncOption& option, GSList* list, std::string& name)
     376              : {
     377            0 :     constexpr const char* counters{"counters"};
     378            0 :     constexpr const char* formats{"counter_formats"};
     379            0 :     auto key = option.get_key();
     380            0 :     name = key.substr(0, key.size() - 1);
     381            0 :     list->next->data = (void*)name.c_str();
     382            0 :     if (option.get_name().rfind("format")
     383            0 :         != std::string::npos)
     384            0 :         list->data = (void*)formats;
     385              :     else
     386            0 :         list->data = (void*)counters;
     387            0 : }
     388              : 
     389              : static inline void
     390            1 : option_path(const GncOption& option, GSList* list)
     391              : {
     392            1 :     list->next->data = (void*)option.get_name().c_str();
     393            1 :     list->data = (void*)option.get_section().c_str();
     394            1 : }
     395              : 
     396              : /* The usage "option.template get_value<bool>()" looks weird, but it's required
     397              :  * by the C++ standard: "When the name of a member template specialization
     398              :  * appears after . or -> in a postfix-expression, or after nested-name-specifier
     399              :  * in a qualified-id, and the postfix-expression or qualified-id explicitly
     400              :  * depends on a template-parameter (14.6.2), the member template name must be
     401              :  * prefixed by the keyword template. Otherwise the name is assumed to name a
     402              :  * non-template."
     403              :  */
     404              : static inline KvpValue*
     405            0 : kvp_value_from_bool_option(const GncOption& option)
     406              : {
     407            0 :     auto val{option.template get_value<bool>()};
     408              :     // ~KvpValue will g_free the value.
     409            0 :     return new KvpValue(val ? g_strdup("t") : g_strdup("f"));
     410              : }
     411              : 
     412              : static bool
     413            1 : is_qofinstance_ui_type(GncOptionUIType type)
     414              : {
     415            1 :     switch (type)
     416              :     {
     417            0 :         case GncOptionUIType::ACCOUNT_SEL:
     418              :         case GncOptionUIType::BUDGET:
     419              :         case GncOptionUIType::OWNER:
     420              :         case GncOptionUIType::CUSTOMER:
     421              :         case GncOptionUIType::VENDOR:
     422              :         case GncOptionUIType::EMPLOYEE:
     423              :         case GncOptionUIType::INVOICE:
     424              :         case GncOptionUIType::TAX_TABLE:
     425              :         case GncOptionUIType::QUERY:
     426            0 :             return true;
     427            1 :         default:
     428            1 :             return false;
     429              :     }
     430              : }
     431              : 
     432              : static inline KvpValue*
     433            0 : kvp_value_from_qof_instance_option(const GncOption& option)
     434              : {
     435            0 :     const QofInstance* inst{QOF_INSTANCE(option.template get_value<const QofInstance*>())};
     436            0 :     auto guid = guid_copy(qof_instance_get_guid(inst));
     437            0 :     return new KvpValue(guid);
     438              : }
     439              : 
     440              : /* GncOptionDateFormat Constants and support functions. These are frozen for backwards compatibility. */
     441              : 
     442              : static const char* date_format_frame_key = "Fancy Date Format";
     443              : static const char* date_format_custom_key ="custom";
     444              : static const char* date_format_months_key = "month";
     445              : static const char* date_format_years_key = "years";
     446              : static const char *date_format_format_key = "fmt";
     447              : 
     448              : static inline KvpValue *
     449            0 : kvp_frame_from_date_format_option(const GncOption& option)
     450              : {
     451            0 :     auto [format, months, years, custom] = option.get_value<GncOptionDateFormat>();
     452              : 
     453            0 :     if (format == QOF_DATE_FORMAT_UNSET)
     454            0 :         return nullptr;
     455              : 
     456            0 :     auto frame{new KvpFrame};
     457            0 :     frame->set({date_format_format_key}, new KvpValue(g_strdup(gnc_date_dateformat_to_string(format))));
     458            0 :     frame->set({date_format_months_key}, new KvpValue(g_strdup(gnc_date_monthformat_to_string(months))));
     459            0 :     frame->set({date_format_years_key}, new KvpValue(static_cast<int64_t>(years)));
     460            0 :     frame->set({date_format_custom_key}, new KvpValue(g_strdup(custom.c_str())));
     461            0 :     return new KvpValue(frame);
     462            0 : };
     463              : 
     464              : void
     465            2 : GncOptionDB::save_to_kvp(QofBook* book, bool clear_options) const noexcept
     466              : {
     467            2 :     if (clear_options)
     468            1 :         qof_book_options_delete(book, nullptr);
     469            2 :     const_cast<GncOptionDB*>(this)->foreach_section(
     470            4 :         [book](GncOptionSectionPtr& section)
     471              :         {
     472           16 :             section->foreach_option(
     473           16 :                 [book, &section](GncOption& option) {
     474           12 :                     if (option.is_dirty())
     475              :                     {
     476              :                         /* We need the string name out here so that it stays in
     477              :                          * scope long enough to pass its c_str to
     478              :                          * gnc_book_set_option. */
     479            1 :                         std::string name;
     480              :                         /* qof_book_set_option wants a GSList path. Let's avoid
     481              :                          * allocating and make one here. */
     482            1 :                         GSList list_tail{}, list_head{nullptr, &list_tail};
     483            1 :                         if (strcmp(section->get_name().c_str(), "Counters") == 0)
     484            0 :                             counter_option_path(option, &list_head, name);
     485              :                         else
     486            1 :                             option_path(option, &list_head);
     487            1 :                         auto type{option.get_ui_type()};
     488            1 :                         KvpValue* kvp{};
     489            1 :                         if (type == GncOptionUIType::BOOLEAN)
     490            0 :                             kvp = kvp_value_from_bool_option(option);
     491            1 :                         else if (is_qofinstance_ui_type(type))
     492            0 :                             kvp = kvp_value_from_qof_instance_option(option);
     493            1 :                         else if (type == GncOptionUIType::NUMBER_RANGE)
     494              :                         {
     495            0 :                             if (option.is_alternate())
     496              :                             {
     497            0 :                                 kvp = new KvpValue(static_cast<int64_t>(option.template get_value<int>()));
     498              :                             }
     499              :                             else
     500              :                             {
     501            0 :                                 kvp = new KvpValue(option.template get_value<double>());
     502              :                             }
     503              :                         }
     504            1 :                         else if (type == GncOptionUIType::DATE_FORMAT)
     505            0 :                             kvp = kvp_frame_from_date_format_option(option);
     506              :                         else
     507              :                         {
     508            1 :                             auto str{option.template get_value<std::string>()};
     509            2 :                             kvp = new KvpValue{g_strdup(str.c_str())};
     510            1 :                         }
     511            1 :                         qof_book_set_option(book, kvp, &list_head);
     512            1 :                         option.mark_saved();
     513            1 :                     }
     514           12 :                 });
     515            8 :         });
     516            2 : }
     517              : 
     518              : static inline void
     519            0 : fill_option_from_string_kvp(GncOption& option, KvpValue* kvp)
     520              : {
     521            0 :     auto str{kvp->get<const char*>()};
     522            0 :     if (option.get_ui_type() == GncOptionUIType::BOOLEAN)
     523            0 :         option.set_value(*str == 't' ? true : false);
     524              :     else
     525            0 :         option.set_value(std::string{str});
     526            0 : }
     527              : 
     528              : static inline void
     529            0 : fill_option_from_guid_kvp(GncOption& option, KvpValue* kvp)
     530              : {
     531            0 :     auto guid{kvp->get<GncGUID*>()};
     532            0 :     option.set_value(
     533            0 :         (const QofInstance*)qof_instance_from_guid(guid, option.get_ui_type()));
     534            0 : }
     535              : 
     536              : static inline void
     537            0 : fill_option_from_date_format_kvp(GncOption& option, KvpValue* kvp)
     538              : {
     539            0 :     GncOptionDateFormat default_fmt{QOF_DATE_FORMAT_UNSET, GNCDATE_MONTH_NUMBER, true, ""};
     540            0 :     auto frame{kvp->get<KvpFrame*>()};
     541            0 :     if (!frame)
     542              :     {
     543            0 :         option.set_value(default_fmt);
     544            0 :         return;
     545              :     }
     546            0 :     auto format_str{frame->get_slot({date_format_format_key})->get<const char*>()};
     547              :     QofDateFormat format;
     548            0 :     if (!format_str || gnc_date_string_to_dateformat(format_str, &format))
     549              :     {
     550            0 :         option.set_value(default_fmt);
     551            0 :         return;
     552              :     }
     553            0 :     GNCDateMonthFormat months = GNCDATE_MONTH_NUMBER;
     554            0 :     auto months_str{frame->get_slot({date_format_months_key})->get<const char*>()};
     555            0 :     if (months_str)
     556            0 :         gnc_date_string_to_monthformat(months_str, &months);
     557            0 :     auto years_num{frame->get_slot({date_format_years_key})->get<int64_t>()};
     558            0 :     bool years = static_cast<bool>(years_num);
     559            0 :     auto custom_str{frame->get_slot({date_format_custom_key})->get<const char*>()};
     560            0 :     option.set_value<GncOptionDateFormat>({format, months, years, custom_str ? custom_str : ""});
     561            0 : }
     562              : 
     563              : void
     564            0 : GncOptionDB::load_from_kvp(QofBook* book) noexcept
     565              : {
     566            0 :     foreach_section(
     567            0 :         [book](GncOptionSectionPtr& section)
     568              :         {
     569            0 :             section->foreach_option(
     570            0 :                 [book, &section](GncOption& option)
     571              :                 {
     572              :                     // Make path list as above.
     573            0 :                     std::string name;
     574              :                     /* qof_book_set_option wants a GSList path. Let's avoid
     575              :                      * allocating and make one here. */
     576            0 :                     GSList list_tail{}, list_head{nullptr, &list_tail};
     577            0 :                     if (strcmp(section->get_name().c_str(), "Counters") == 0)
     578            0 :                         counter_option_path(option, &list_head, name);
     579              :                     else
     580            0 :                         option_path(option, &list_head);
     581            0 :                     auto kvp = qof_book_get_option(book, &list_head);
     582            0 :                     if (!kvp)
     583            0 :                         return;
     584              : 
     585            0 :                     auto set_double = [&option, kvp, &list_head]() {
     586              :                         /*counters might have been set as doubles
     587              :                          * because of
     588              :                          * https://bugs.gnucash.org/show_bug.cgi?id=798930. They
     589              :                          * should be int.
     590              :                          */
     591            0 :                             constexpr const char *counters{"counters"};
     592            0 :                             auto value{kvp->get<double>()};
     593            0 :                             if (strcmp(static_cast<char*>(list_head.data), counters) == 0)
     594            0 :                                 option.set_value(static_cast<int>(value));
     595              :                             else
     596            0 :                                 option.set_value(value);
     597            0 :                     };
     598              : 
     599            0 :                     switch (kvp->get_type())
     600              :                     {
     601            0 :                         case KvpValue::Type::DOUBLE:
     602            0 :                             set_double();
     603            0 :                             break;
     604            0 :                         case KvpValue::Type::INT64:
     605            0 :                             option.set_value(static_cast<int>(kvp->get<int64_t>()));
     606            0 :                             break;
     607            0 :                         case KvpValue::Type::STRING:
     608            0 :                             fill_option_from_string_kvp(option, kvp);
     609            0 :                             break;
     610            0 :                         case KvpValue::Type::GUID:
     611            0 :                             fill_option_from_guid_kvp(option, kvp);
     612            0 :                           break;
     613            0 :                         case KvpValue::Type::FRAME:
     614            0 :                             if (g_strcmp0(option.get_name().c_str(), date_format_frame_key) == 0)
     615            0 :                                 fill_option_from_date_format_kvp(option, kvp);
     616            0 :                             break;
     617            0 :                         default:
     618            0 :                             return;
     619              :                             break;
     620              :                     }
     621            0 :                 });
     622            0 :         });
     623            0 : }
     624              : 
     625              : void
     626          343 : gnc_register_string_option(GncOptionDB* db, const char* section,
     627              :                            const char* name, const char* key,
     628              :                            const char* doc_string, std::string value)
     629              : {
     630              :     GncOption option{section, name, key, doc_string, value,
     631          343 :             GncOptionUIType::STRING};
     632          686 :     db->register_option(section, std::move(option));
     633          343 : }
     634              : 
     635              : void
     636          118 : gnc_register_text_option(GncOptionDB* db, const char* section, const char* name,
     637              :                          const char* key, const char* doc_string,
     638              :                          std::string value)
     639              : {
     640              :     GncOption option{section, name, key, doc_string, value,
     641          118 :             GncOptionUIType::TEXT};
     642          236 :     db->register_option(section, std::move(option));
     643              : 
     644          118 : }
     645              : 
     646              : void
     647          180 : gnc_register_font_option(GncOptionDB* db, const char* section,
     648              :                          const char* name, const char* key,
     649              :                          const char* doc_string, std::string value)
     650              : {
     651              :     GncOption option{section, name, key, doc_string, value,
     652          180 :             GncOptionUIType::FONT};
     653          360 :     db->register_option(section, std::move(option));
     654          180 : }
     655              : 
     656              : void
     657            3 : gnc_register_budget_option(GncOptionDB* db, const char* section,
     658              :                            const char* name, const char* key,
     659              :                            const char* doc_string, GncBudget *value)
     660              : {
     661            3 :     GncOption option{GncOptionQofInstanceValue{section, name, key, doc_string,
     662              :                                                (const QofInstance*)value,
     663            3 :                                                GncOptionUIType::BUDGET}};
     664            6 :     db->register_option(section, std::move(option));
     665            3 : }
     666              : 
     667              : void
     668           46 : gnc_register_color_option(GncOptionDB* db, const char* section,
     669              :                          const char* name, const char* key,
     670              :                          const char* doc_string, std::string value)
     671              : {
     672              :     GncOption option{section, name, key, doc_string, value,
     673           46 :             GncOptionUIType::COLOR};
     674           92 :     db->register_option(section, std::move(option));
     675           46 : }
     676              : 
     677              : void
     678            0 : gnc_register_commodity_option(GncOptionDB* db, const char* section,
     679              :                               const char* name, const char* key,
     680              :                               const char* doc_string, gnc_commodity *value)
     681              : {
     682            0 :     GncOption option{GncOptionCommodityValue{section, name, key, doc_string,
     683              :                                                value,
     684            0 :                                                GncOptionUIType::COMMODITY}};
     685            0 :     db->register_option(section, std::move(option));
     686            0 : }
     687              : 
     688              : void
     689            2 : gnc_register_commodity_option(GncOptionDB* db, const char* section,
     690              :                               const char* name, const char* key,
     691              :                               const char* doc_string, const char* value)
     692              : {
     693            2 :     gnc_commodity* commodity{};
     694            2 :     const auto book{qof_session_get_book(gnc_get_current_session())};
     695            2 :     const auto commodity_table{gnc_commodity_table_get_table(book)};
     696            2 :     const auto namespaces{gnc_commodity_table_get_namespaces(commodity_table)};
     697            2 :     for (auto node = namespaces; node && commodity == nullptr;
     698            0 :          node = g_list_next(node))
     699              :     {
     700            4 :         commodity = gnc_commodity_table_lookup(commodity_table,
     701            2 :                                                (const char*)(node->data),
     702              :                                                value);
     703            2 :         if (commodity)
     704            2 :             break;
     705              :     }
     706            2 :     GncOption option{GncOptionCommodityValue{section, name, key, doc_string,
     707              :                 commodity,
     708            2 :                 GncOptionUIType::COMMODITY}};
     709            4 :     db->register_option(section, std::move(option));
     710            2 :     g_list_free (namespaces);
     711            2 : }
     712              : 
     713              : void
     714         2640 : gnc_register_simple_boolean_option(GncOptionDB* db,
     715              :                                    const char* section, const char* name,
     716              :                                    const char* key, const char* doc_string,
     717              :                                    bool value)
     718              : {
     719              :     GncOption option{section, name, key, doc_string, value,
     720         2640 :             GncOptionUIType::BOOLEAN};
     721         5280 :     db->register_option(section, std::move(option));
     722         2640 : }
     723              : 
     724              : void
     725           51 : gnc_register_pixmap_option(GncOptionDB* db, const char* section,
     726              :                            const char* name, const char* key,
     727              :                            const char* doc_string, std::string value)
     728              : {
     729              :     GncOption option{section, name, key, doc_string, value,
     730           51 :             GncOptionUIType::PIXMAP};
     731          102 :     db->register_option(section, std::move(option));
     732           51 : }
     733              : 
     734              : void
     735          117 : gnc_register_account_list_option(GncOptionDB* db, const char* section,
     736              :                                  const char* name, const char* key,
     737              :                                  const char* doc_string,
     738              :                                  const GncOptionAccountList& value)
     739              : {
     740          117 :     GncOption option{GncOptionAccountListValue{section, name, key, doc_string,
     741          117 :                 GncOptionUIType::ACCOUNT_LIST, value}};
     742          234 :     db->register_option(section, std::move(option));
     743          117 : }
     744              : 
     745              : void
     746           63 : gnc_register_account_list_limited_option(GncOptionDB* db,
     747              :                                          const char* section, const char* name,
     748              :                                          const char* key,
     749              :                                          const char* doc_string,
     750              :                                          const GncOptionAccountList& value,
     751              :                                          GncOptionAccountTypeList&& allowed)
     752              : {
     753              :     try
     754              :     {
     755           63 :         GncOption option{GncOptionAccountListValue{section, name, key, doc_string,
     756          126 :                     GncOptionUIType::ACCOUNT_LIST, value, std::move(allowed)}};
     757          120 :         db->register_option(section, std::move(option));
     758           60 :     }
     759            3 :     catch (const std::invalid_argument& err)
     760              :     {
     761            3 :         PWARN("Account List Limited Option, value failed validation, option not registered.");
     762            3 :     }
     763           63 : }
     764              : 
     765              : using AccountPair = std::pair<GncOptionAccountList&,
     766              :                               const GncOptionAccountTypeList&>;
     767              : static void
     768          139 : find_children(Account* account, void* data)
     769              : {
     770          139 :     auto datapair =
     771              :         (AccountPair*)data;
     772          139 :     GncOptionAccountList& list = datapair->first;
     773          139 :     const GncOptionAccountTypeList& types = datapair->second;
     774          139 :     if (std::find(types.begin(), types.end(),
     775          278 :                   xaccAccountGetType(account)) != types.end())
     776           46 :         list.push_back(*qof_entity_get_guid(account));
     777          139 : }
     778              : 
     779              : GncOptionAccountList
     780           13 : gnc_account_list_from_types(QofBook *book,
     781              :                             const GncOptionAccountTypeList& types)
     782              : {
     783           13 :     GncOptionAccountList list;
     784           13 :     AccountPair funcdata{list, types};
     785           13 :     Account* base_acct = gnc_book_get_root_account(book);
     786           13 :     gnc_account_foreach_descendant(base_acct, (AccountCb)find_children,
     787              :                                    &funcdata);
     788           13 :     return list;
     789            0 : }
     790              : 
     791              : 
     792              : void
     793           11 : gnc_register_account_sel_limited_option(GncOptionDB* db,
     794              :                                         const char* section, const char* name,
     795              :                                         const char* key, const char* doc_string,
     796              :                                         const Account* value,
     797              :                                         GncOptionAccountTypeList&& allowed)
     798              : {
     799              :     try
     800              :     {
     801           11 :         GncOption option{GncOptionAccountSelValue{section, name, key, doc_string,
     802           22 :                     GncOptionUIType::ACCOUNT_SEL, value, std::move(allowed)}};
     803           22 :     db->register_option(section, std::move(option));
     804           11 :     }
     805            0 :     catch (const std::invalid_argument& err)
     806              :     {
     807            0 :         PWARN("Account Sel Limited Option, value failed validation, option not registerd.");
     808            0 :     }
     809           11 : }
     810              : 
     811              : void
     812         1171 : gnc_register_multichoice_option(GncOptionDB* db, const char* section,
     813              :                                 const char* name, const char* key,
     814              :                                 const char* doc_string, const char* default_val,
     815              :                                 GncMultichoiceOptionChoices&& choices)
     816              : {
     817         2342 :     std::string defval{default_val};
     818         1171 :     auto found{std::find_if(choices.begin(), choices.end(),
     819         2362 :                             [&defval](auto& choice)->bool {
     820         2362 :                                 return defval == std::get<0>(choice);
     821              :                             })};
     822         2342 :     if (found == choices.end())
     823           20 :         defval = (choices.empty() ? std::string{"None"} :
     824            5 :                   std::get<0>(choices.at(0)));
     825         1171 :     GncOption option{GncOptionMultichoiceValue{section, name, key, doc_string,
     826         2342 :                 defval.c_str(), std::move(choices)}};
     827         2342 :     db->register_option(section, std::move(option));
     828         1171 : }
     829              : 
     830              : void
     831            5 : gnc_register_list_option(GncOptionDB* db, const char* section,
     832              :                          const char* name, const char* key,
     833              :                          const char* doc_string, const char* value,
     834              :                          GncMultichoiceOptionChoices&& list)
     835              : {
     836            5 :     GncOption option{GncOptionMultichoiceValue{section, name, key, doc_string,
     837           10 :                 value,  std::move(list), GncOptionUIType::LIST}};
     838           10 :     db->register_option(section, std::move(option));
     839            5 : }
     840              : 
     841              : /* Only balance-forecast.scm, sample-report.scm, and net-charts.scm
     842              :  * use decimals and fractional steps and they can be worked around.
     843              :  */
     844              : template <typename ValueType> void
     845          161 : gnc_register_number_range_option(GncOptionDB* db, const char* section,
     846              :                                  const char* name, const char* key,
     847              :                                  const char* doc_string, ValueType value,
     848              :                                  ValueType min, ValueType max, ValueType step)
     849              : {
     850              :     try
     851              :     {
     852          161 :         GncOption option{GncOptionRangeValue<ValueType>{section, name, key,
     853              :                                                         doc_string, value, min,
     854              :                                                         max, step}};
     855          322 :         db->register_option(section, std::move(option));
     856          161 :     }
     857            0 :     catch(const std::invalid_argument& err)
     858              :     {
     859            0 :         PWARN("Number Range Option %s, option not registerd.",
     860              :               err.what());
     861              :     }
     862          161 : }
     863              : 
     864              : void
     865          172 : gnc_register_number_plot_size_option(GncOptionDB* db,
     866              :                                      const char* section, const char* name,
     867              :                                      const char* key, const char* doc_string,
     868              :                                      int value)
     869              : {
     870              : //65K is 10x reasonable, but it's a convenient constant.
     871          172 :     GncOption option{GncOptionRangeValue<int>{section, name, key, doc_string,
     872          172 :             value, 10, UINT16_MAX, 1, GncOptionUIType::PLOT_SIZE}};
     873          344 :     db->register_option(section, std::move(option));
     874          172 : }
     875              : 
     876              : void
     877            4 : gnc_register_query_option(GncOptionDB* db, const char* section,
     878              :                           const char* name, const QofQuery* value)
     879              : {
     880              :     GncOption option{section, name, "", "", value,
     881            4 :             GncOptionUIType::INTERNAL};
     882            8 :     db->register_option(section, std::move(option));
     883            4 : }
     884              : 
     885              : void
     886           14 : gnc_register_owner_option(GncOptionDB* db, const char* section,
     887              :                           const char* name, const char* key,
     888              :                           const char* doc_string, const GncOwner* value,
     889              :                           GncOwnerType type)
     890              : {
     891              :     GncOptionUIType uitype;
     892           14 :     switch (type)
     893              :     {
     894            5 :     case GNC_OWNER_CUSTOMER:
     895            5 :         uitype = GncOptionUIType::CUSTOMER;
     896            5 :         break;
     897            3 :     case GNC_OWNER_EMPLOYEE:
     898            3 :         uitype = GncOptionUIType::EMPLOYEE;
     899            3 :         break;
     900            3 :     case GNC_OWNER_JOB:
     901            3 :         uitype = GncOptionUIType::JOB;
     902            3 :         break;
     903            3 :     case GNC_OWNER_VENDOR:
     904            3 :         uitype = GncOptionUIType::VENDOR;
     905            3 :         break;
     906            0 :     default:
     907            0 :         uitype = GncOptionUIType::INTERNAL;
     908              :     };
     909           14 :     GncOption option{GncOptionGncOwnerValue{section, name, key, doc_string,
     910           28 :                                             value, uitype}};
     911           28 :     db->register_option(section, std::move(option));
     912           14 : }
     913              : 
     914              : void
     915           29 : gnc_register_invoice_option(GncOptionDB* db, const char* section,
     916              :                             const char* name, const char* key,
     917              :                             const char* doc_string, GncInvoice* value)
     918              : {
     919           29 :     GncOption option{GncOptionQofInstanceValue{section, name, key, doc_string,
     920              :                                                (const QofInstance*)value,
     921           29 :                                                GncOptionUIType::INVOICE}};
     922           58 :     db->register_option(section, std::move(option));
     923           29 : }
     924              : 
     925              : void
     926            0 : gnc_register_taxtable_option(GncOptionDB* db, const char* section,
     927              :                              const char* name, const char* key,
     928              :                              const char* doc_string, GncTaxTable* value)
     929              : {
     930            0 :     GncOption option{GncOptionQofInstanceValue{section, name, key, doc_string,
     931              :                                                (const QofInstance*)value,
     932            0 :                                                GncOptionUIType::TAX_TABLE}};
     933            0 :     db->register_option(section, std::move(option));
     934            0 : }
     935              : 
     936              : void
     937            0 : gnc_register_invoice_print_report_option(GncOptionDB* db, const char* section,
     938              :                                          const char* name, const char* key,
     939              :                                          const char* doc_string, std::string value)
     940              : {
     941              :     GncOption option{section, name, key, doc_string,
     942            0 :                      value, GncOptionUIType::INV_REPORT};
     943            0 :     db->register_option(section, std::move(option));
     944            0 : }
     945              : 
     946              : void
     947            0 : gnc_register_counter_option(GncOptionDB* db, const char* section,
     948              :                             const char* name, const char* key,
     949              :                             const char* doc_string, int value)
     950              : {
     951            0 :     GncOption option{GncOptionRangeValue<int>{section, name, key, doc_string,
     952            0 :                 value, 0, 999999999, 1}};
     953            0 :     option.set_alternate(true);
     954            0 :     db->register_option(section, std::move(option));
     955            0 : }
     956              : 
     957              : void
     958            0 : gnc_register_counter_format_option(GncOptionDB* db,
     959              :                                    const char* section, const char* name,
     960              :                                    const char* key, const char* doc_string,
     961              :                                    std::string value)
     962              : {
     963              :     GncOption option{section, name, key, doc_string, value,
     964            0 :             GncOptionUIType::STRING};
     965            0 :     db->register_option(section, std::move(option));
     966            0 : }
     967              : 
     968              : void
     969            0 : gnc_register_dateformat_option(GncOptionDB* db, const char* section,
     970              :                                const char* name, const char* key,
     971              :                                const char* doc_string, GncOptionDateFormat&& value)
     972              : {
     973            0 :     GncOption option{section, name, key, doc_string, std::move(value),
     974            0 :             GncOptionUIType::DATE_FORMAT};
     975            0 :     db->register_option(section, std::move(option));
     976            0 : }
     977              : 
     978              : void
     979          132 : gnc_register_currency_option(GncOptionDB* db, const char* section,
     980              :                              const char* name, const char* key,
     981              :                              const char* doc_string, gnc_commodity *value)
     982              : {
     983          132 :     GncOption option{GncOptionCommodityValue{
     984              :         section, name, key, doc_string, value, GncOptionUIType::CURRENCY
     985          132 :         }};
     986          264 :     db->register_option(section, std::move(option));
     987          132 : }
     988              : 
     989              : void
     990            0 : gnc_register_currency_option(GncOptionDB* db, const char* section,
     991              :                              const char* name, const char* key,
     992              :                              const char* doc_string, const char* value)
     993              : {
     994            0 :     const auto book{qof_session_get_book(gnc_get_current_session())};
     995            0 :     const auto commodity_table{gnc_commodity_table_get_table(book)};
     996            0 :     const auto commodity = gnc_commodity_table_lookup(commodity_table,
     997              :                                                       "CURRENCY",
     998              :                                                       value);
     999            0 :     GncOption option{GncOptionCommodityValue{
    1000              :         section, name, key, doc_string, commodity, GncOptionUIType::CURRENCY
    1001            0 :         }};
    1002            0 :     db->register_option(section, std::move(option));
    1003            0 : }
    1004              : 
    1005              : void
    1006            1 : gnc_register_date_option(GncOptionDB* db, const char* section,
    1007              :                          const char* name, const char* key,
    1008              :                          const char* doc_string, time64 time,
    1009              :                          RelativeDateUI ui)
    1010              : {
    1011            1 :     auto ui_type = ui == RelativeDateUI::BOTH ? GncOptionUIType::DATE_BOTH :
    1012            0 :         ui == RelativeDateUI::RELATIVE ? GncOptionUIType::DATE_RELATIVE :
    1013              :         GncOptionUIType::DATE_ABSOLUTE;
    1014            1 :     GncOption option{GncOptionDateValue(section, name, key, doc_string,
    1015            1 :                                         ui_type, time)};
    1016            2 :     db->register_option(section, std::move(option));
    1017            1 : }
    1018              : 
    1019              : void
    1020            5 : gnc_register_date_option(GncOptionDB* db, const char* section,
    1021              :                          const char* name, const char* key,
    1022              :                          const char* doc_string, RelativeDatePeriod period,
    1023              :                          RelativeDateUI ui)
    1024              : {
    1025            5 :     auto ui_type = ui == RelativeDateUI::BOTH ? GncOptionUIType::DATE_BOTH :
    1026            0 :         ui == RelativeDateUI::RELATIVE ? GncOptionUIType::DATE_RELATIVE :
    1027              :         GncOptionUIType::DATE_ABSOLUTE;
    1028            5 :     GncOption option{GncOptionDateValue(section, name, key, doc_string,
    1029            5 :                                         ui_type, period)};
    1030           10 :     db->register_option(section, std::move(option));
    1031            5 : }
    1032              : 
    1033              : void
    1034            1 : gnc_register_date_option(GncOptionDB* db,
    1035              :                                   const char* section, const char* name,
    1036              :                                   const char* key, const char* doc_string,
    1037              :                                   RelativeDatePeriodVec& period_set,
    1038              :                                   bool both)
    1039              : {
    1040            1 :     auto is_absolute = period_set.size() == 1 &&
    1041            0 :                        period_set.front() == RelativeDatePeriod::ABSOLUTE;
    1042            1 :     auto ui_type = both ? GncOptionUIType::DATE_BOTH :
    1043            0 :         is_absolute ? GncOptionUIType::DATE_ABSOLUTE : GncOptionUIType::DATE_RELATIVE;
    1044            1 :     GncOption option{GncOptionDateValue(section, name, key, doc_string,
    1045            1 :                                         ui_type, period_set)};
    1046            1 :     if (is_absolute)
    1047            0 :         option.set_default_value(gnc_time(nullptr));
    1048            2 :     db->register_option(section, std::move(option));
    1049            1 : }
    1050              : 
    1051              : 
    1052              : static const RelativeDatePeriodVec begin_dates
    1053              : {
    1054              :     RelativeDatePeriod::TODAY,
    1055              :     RelativeDatePeriod::START_THIS_MONTH,
    1056              :     RelativeDatePeriod::START_PREV_MONTH,
    1057              :     RelativeDatePeriod::START_CURRENT_QUARTER,
    1058              :     RelativeDatePeriod::START_PREV_QUARTER,
    1059              :     RelativeDatePeriod::START_CAL_YEAR,
    1060              :     RelativeDatePeriod::START_PREV_YEAR,
    1061              :     RelativeDatePeriod::START_ACCOUNTING_PERIOD
    1062              : };
    1063              : 
    1064              : void
    1065          132 : gnc_register_start_date_option(GncOptionDB* db, const char* section,
    1066              :                                const char* name, const char* key,
    1067              :                                const char* doc_string, bool both)
    1068              : {
    1069          132 :     auto ui_type = both ? GncOptionUIType::DATE_BOTH :
    1070              :         GncOptionUIType::DATE_RELATIVE;
    1071          132 :     GncOption option{GncOptionDateValue(section, name, key, doc_string,
    1072          132 :                                         ui_type, begin_dates)};
    1073          264 :     db->register_option(section, std::move(option));
    1074          132 : }
    1075              : 
    1076              : static const RelativeDatePeriodVec end_dates
    1077              : {
    1078              :     RelativeDatePeriod::TODAY,
    1079              :     RelativeDatePeriod::END_THIS_MONTH,
    1080              :     RelativeDatePeriod::END_PREV_MONTH,
    1081              :     RelativeDatePeriod::END_CURRENT_QUARTER,
    1082              :     RelativeDatePeriod::END_PREV_QUARTER,
    1083              :     RelativeDatePeriod::END_CAL_YEAR,
    1084              :     RelativeDatePeriod::END_PREV_YEAR,
    1085              :     RelativeDatePeriod::END_ACCOUNTING_PERIOD
    1086              : };
    1087              : 
    1088              : void
    1089          151 : gnc_register_end_date_option(GncOptionDB* db, const char* section,
    1090              :                              const char* name, const char* key,
    1091              :                              const char* doc_string, bool both)
    1092              : {
    1093          151 :     auto ui_type = both ? GncOptionUIType::DATE_BOTH :
    1094              :         GncOptionUIType::DATE_RELATIVE;
    1095          151 :     GncOption option{GncOptionDateValue(section, name, key, doc_string,
    1096          151 :                                         ui_type, end_dates)};
    1097          302 :     db->register_option(section, std::move(option));
    1098          151 : }
    1099              : 
    1100              : void
    1101            5 : gnc_register_report_placement_option(GncOptionDBPtr& db,
    1102              :                                      const char* section, const char* name)
    1103              : {
    1104              :     /* This is a special option with it's own UI file so we have fake values to pass
    1105              :      * to the template creation function.
    1106              :      */
    1107            5 :     GncOptionReportPlacementVec value;
    1108            5 :     GncOption option{GncOptionValue<GncOptionReportPlacementVec>{section, name,
    1109              :                                                               "no_key", "nodoc_string",
    1110           10 :                                                               value,GncOptionUIType::REPORT_PLACEMENT}};
    1111           10 :     db->register_option(section, std::move(option));
    1112            5 : }
    1113              : 
    1114              : void
    1115            8 : gnc_register_internal_option(GncOptionDBPtr& db,
    1116              :                              const char* section, const char* name,
    1117              :                              const std::string& value)
    1118              : {
    1119              :     GncOption option{
    1120            8 :         GncOptionValue<std::string>{section, name, "", "", value,
    1121           16 :                                     GncOptionUIType::INTERNAL}};
    1122           16 :     db->register_option(section, std::move(option));
    1123            8 : }
    1124              : 
    1125              : void
    1126           41 : gnc_register_internal_option(GncOptionDBPtr& db,
    1127              :                              const char* section, const char* name,
    1128              :                              bool value)
    1129              : {
    1130              :     GncOption option{
    1131           41 :         GncOptionValue<bool>{section, name, "", "", value,
    1132           41 :                              GncOptionUIType::INTERNAL}};
    1133           82 :     db->register_option(section, std::move(option));
    1134           41 : }
    1135              : 
    1136              : GncOptionDB*
    1137            0 : gnc_option_db_new(void)
    1138              : {
    1139            0 :     return new GncOptionDB;
    1140              : }
    1141              : 
    1142              : void
    1143            0 : gnc_option_db_destroy(GncOptionDB* odb)
    1144              : {
    1145            0 :     PWARN("Direct Destroy called on GncOptionDB %" G_GUINT64_FORMAT, (uint64_t)odb);
    1146            0 : }
    1147              : 
    1148              : GList*
    1149            0 : gnc_option_db_commit(GncOptionDB* odb)
    1150              : {
    1151            0 :     GList* errors{};
    1152            0 :     odb->foreach_section(
    1153            0 :         [&errors](GncOptionSectionPtr& section){
    1154            0 :             section->foreach_option(
    1155            0 :                 [&errors](GncOption& option) {
    1156              :                     try
    1157              :                     {
    1158            0 :                         option.set_option_from_ui_item();
    1159              :                     }
    1160            0 :                     catch (const std::invalid_argument& err)
    1161              :                     {
    1162            0 :                         PWARN("Option %s:%s failed to set its value %s",
    1163              :                               option.get_section().c_str(),
    1164              :                               option.get_name().c_str(), err.what());
    1165            0 :                         errors = g_list_prepend(errors,
    1166            0 :                                                 (void*)option.get_name().c_str());
    1167            0 :                     } });
    1168            0 :         });
    1169            0 :     if (!errors)
    1170            0 :         odb->run_callbacks();
    1171            0 :     return errors;
    1172              : }
    1173              : 
    1174              : void
    1175            0 : gnc_option_db_clean(GncOptionDB* odb)
    1176              : {
    1177            0 :         odb->foreach_section(
    1178            0 :         [](GncOptionSectionPtr& section){
    1179            0 :             section->foreach_option(
    1180            0 :                 [](GncOption& option) {
    1181            0 :                     option.set_ui_item_from_option();
    1182            0 :                 });
    1183            0 :         });
    1184            0 : }
    1185              : 
    1186            0 : void gnc_option_db_load(GncOptionDB* odb, QofBook* book)
    1187              : {
    1188            0 :     odb->load_from_kvp(book);
    1189            0 : }
    1190              : 
    1191              : void
    1192            0 : gnc_option_db_save(GncOptionDB* odb, QofBook* book,
    1193              :                         gboolean clear_options)
    1194              : {
    1195            0 :     odb->save_to_kvp(book, static_cast<bool>(clear_options));
    1196            0 : }
    1197              : 
    1198              : void
    1199            0 : gnc_option_db_book_options(GncOptionDB* odb)
    1200              : {
    1201            0 :     constexpr const char* business_section{N_("Business")};
    1202            0 :     constexpr const char* counter_section{N_("Counters")};
    1203            0 :     static const std::string empty_string{""};
    1204              : 
    1205              : //Accounts Tab
    1206              : 
    1207            0 :     gnc_register_number_range_option<double>(odb, OPTION_SECTION_ACCOUNTS,
    1208              :                                      OPTION_NAME_AUTO_READONLY_DAYS, "a",
    1209              :                                      N_("Choose the number of days after which transactions will be read-only and cannot be edited anymore. This threshold is marked by a red line in the account register windows. If zero, all transactions can be edited and none are read-only."),
    1210              :                                      0.0, 0.0, 3650.0, 1.0);
    1211              : 
    1212            0 :     gnc_register_simple_boolean_option(odb, OPTION_SECTION_ACCOUNTS,
    1213              :                                        OPTION_NAME_NUM_FIELD_SOURCE, "b",
    1214              :                                        N_("Check to have split action field used in registers for 'Num' field in place of transaction number; transaction number shown as 'T-Num' on second line of register. Has corresponding effect on business features, reporting and imports/exports."),
    1215              :                                        false);
    1216            0 :     gnc_register_simple_boolean_option(odb, OPTION_SECTION_ACCOUNTS,
    1217              :                                        OPTION_NAME_TRADING_ACCOUNTS, "a",
    1218              :                                        N_("Check to have trading accounts used for transactions involving more than one currency or commodity."),
    1219              :                                        false);
    1220              : 
    1221              : //Budgeting Tab
    1222              : 
    1223            0 :     gnc_register_budget_option(odb, OPTION_SECTION_BUDGETING,
    1224              :                                OPTION_NAME_DEFAULT_BUDGET, "a",
    1225              :                                N_("Budget to be used when none has been otherwise specified."),
    1226              :                                nullptr);
    1227              : 
    1228              : //Counters Tab
    1229              : 
    1230            0 :     gnc_register_counter_option(odb, counter_section,
    1231              :                                 N_("Customer number"), "gncCustomera",
    1232              :                                 N_("The previous customer number generated. This number will be incremented to generate the next customer number."),
    1233              :                                 0);
    1234            0 :     gnc_register_counter_format_option(odb, counter_section,
    1235              :                                        N_("Customer number format"),
    1236              :                                        "gncCustomerb",
    1237              :                                        N_("The format string to use for generating customer numbers. This is a printf-style format string."),
    1238              :                                        empty_string);
    1239            0 :     gnc_register_counter_option(odb, counter_section,
    1240              :                                 N_("Employee number"), "gncEmployeea",
    1241              :                                 N_("The previous employee number generated. This number will be incremented to generate the next employee number."),
    1242              :                                 0);
    1243            0 :     gnc_register_counter_format_option(odb, counter_section,
    1244              :                                        N_("Employee number format"),
    1245              :                                        "gncEmployeeb",
    1246              :                                        N_("The format string to use for generating employee numbers. This is a printf-style format string."),
    1247              :                                        empty_string);
    1248            0 :     gnc_register_counter_option(odb, counter_section,
    1249              :                                 N_("Invoice number"), "gncInvoicea",
    1250              :                                 N_("The previous invoice number generated. This number will be incremented to generate the next invoice number."),
    1251              :                                 0);
    1252            0 :     gnc_register_counter_format_option(odb, counter_section,
    1253              :                                        N_("Invoice number format"),
    1254              :                                        "gncInvoiceb",
    1255              :                                        N_("The format string to use for generating invoice numbers. This is a printf-style format string."),
    1256              :                                        empty_string);
    1257            0 :     gnc_register_counter_option(odb, counter_section,
    1258              :                                 N_("Bill number"), "gncBilla",
    1259              :                                 N_("The previous bill number generated. This number will be incremented to generate the next bill number."),
    1260              :                                 0);
    1261            0 :     gnc_register_counter_format_option(odb, counter_section,
    1262              :                                        N_("Bill number format"), "gncBillb",
    1263              :                                        N_("The format string to use for generating bill numbers. This is a printf-style format string."),
    1264              :                                        empty_string);
    1265            0 :     gnc_register_counter_option(odb, counter_section,
    1266              :                                 N_("Expense voucher number"), "gncExpVouchera",
    1267              :                                 N_("The previous expense voucher number generated. This number will be incremented to generate the next voucher number."),
    1268              :                                 0);
    1269            0 :     gnc_register_counter_format_option(odb, counter_section,
    1270              :                                        N_("Expense voucher number format"),
    1271              :                                        "gncExpVoucherb",
    1272              :                                        N_("The format string to use for generating expense voucher numbers. This is a printf-style format string."),
    1273              :                                        empty_string);
    1274            0 :     gnc_register_counter_option(odb, counter_section,
    1275              :                                 N_("Job number"), "gncJoba",
    1276              :                                 N_("The previous job number generated. This number will be incremented to generate the next job number."),
    1277              :                                 0);
    1278            0 :     gnc_register_counter_format_option(odb, counter_section,
    1279              :                                        N_("Job number format"), "gncJobb",
    1280              :                                        N_("The format string to use for generating job numbers. This is a printf-style format string."),
    1281              :                                        empty_string);
    1282            0 :     gnc_register_counter_option(odb, counter_section,
    1283              :                                 N_("Order number"), "gncOrdera",
    1284              :                                 N_("The previous order number generated. This number will be incremented to generate the next order number."),
    1285              :                                 0);
    1286            0 :     gnc_register_counter_format_option(odb, counter_section,
    1287              :                                        N_("Order number format"), "gncOrderb",
    1288              :                                        N_("The format string to use for generating order numbers. This is a printf-style format string."),
    1289              :                                        empty_string);
    1290            0 :     gnc_register_counter_option(odb, counter_section,
    1291              :                                 N_("Vendor number"), "gncVendora",
    1292              :                                 N_("The previous vendor number generated. This number will be incremented to generate the next vendor number."),
    1293              :                                 0);
    1294            0 :     gnc_register_counter_format_option(odb, counter_section,
    1295              :                                        N_("Vendor number format"), "gncVendorb",
    1296              :                                        N_("The format string to use for generating vendor numbers. This is a printf-style format string."),
    1297              :                                        empty_string);
    1298              : 
    1299              : //Business Tab
    1300              : 
    1301            0 :     gnc_register_string_option(odb, business_section, N_("Company Name"), "a",
    1302              :                                N_("The name of your business."),
    1303              :                                empty_string);
    1304            0 :     gnc_register_text_option(odb, business_section, N_("Company Address"), "b1",
    1305              :                              N_("The address of your business."),
    1306              :                              empty_string);
    1307            0 :     gnc_register_string_option(odb, business_section,
    1308              :                                N_("Company Contact Person"), "b2",
    1309              :                                N_("The contact person to print on invoices."),
    1310              :                                empty_string);
    1311            0 :     gnc_register_string_option(odb, business_section,
    1312              :                                N_("Company Phone Number"), "c1",
    1313              :                                N_("The contact person to print on invoices."),
    1314              :                                empty_string);
    1315            0 :     gnc_register_string_option(odb, business_section,
    1316              :                                N_("Company Fax Number"), "c2",
    1317              :                                N_("The fax number of your business."),
    1318              :                                empty_string);
    1319            0 :     gnc_register_string_option(odb, business_section,
    1320              :                                N_("Company Email Address"), "c3",
    1321              :                                N_ ("The email address of your business."),
    1322              :                                empty_string);
    1323            0 :     gnc_register_string_option(odb, business_section,
    1324              :                                N_("Company Website URL"), "c4",
    1325              :                                N_("The URL address of your website."),
    1326              :                                empty_string);
    1327            0 :     gnc_register_string_option(odb, business_section, N_("Company ID"), "c5",
    1328              :                                N_("The ID for your company (eg 'Tax-ID: 00-000000)."),
    1329              :                                empty_string);
    1330            0 :     gnc_register_invoice_print_report_option(odb, business_section,
    1331              :                                  OPTION_NAME_DEFAULT_INVOICE_REPORT, "e1",
    1332              :                                  N_("The invoice report to be used for printing."),
    1333              :                                  empty_string);
    1334            0 :     gnc_register_number_range_option<double>(odb, business_section,
    1335              :                                      OPTION_NAME_DEFAULT_INVOICE_REPORT_TIMEOUT, "e2",
    1336              :                                      N_("Length of time to change the used invoice report. A value of 0 means disabled."),
    1337              :                                      0.0, 0.0, 20.0, 1.0);
    1338            0 :     gnc_register_taxtable_option(odb, business_section,
    1339              :                                  N_("Default Customer Tax Table"), "f1",
    1340              :                                  N_("The default tax table to apply to customers."),
    1341              :                                  nullptr);
    1342            0 :     gnc_register_taxtable_option(odb, business_section,
    1343              :                                  N_("Default Vendor Tax Table"), "f2",
    1344              :                                  N_("The default tax table to apply to vendors."),
    1345              :                                  nullptr);
    1346              : 
    1347            0 :     gnc_register_dateformat_option(odb, business_section,
    1348              :                                    N_("Fancy Date Format"), "g",
    1349              :                                    N_("The default date format used for fancy printed dates."),
    1350            0 :                                    {QOF_DATE_FORMAT_UNSET, GNCDATE_MONTH_NUMBER, true, ""});
    1351              : 
    1352              : //Tax Tab
    1353              : 
    1354            0 :     gnc_register_string_option(odb, N_("Tax"), N_("Tax Number"), "a",
    1355              :                                N_("The electronic tax number of your business"),
    1356              :                                empty_string);
    1357            0 : }
    1358              : const QofInstance*
    1359            0 : gnc_option_db_lookup_qofinstance_value(GncOptionDB* odb, const char* section,
    1360              :                                        const char* name)
    1361              : {
    1362            0 :     auto option{odb->find_option(section, name)};
    1363            0 :     if (option)
    1364            0 :         return option->get_value<const QofInstance*>();
    1365              :     else
    1366            0 :         return nullptr;
    1367              : }
    1368              : 
    1369              : // Force creation of templates
    1370              : template void gnc_register_number_range_option(GncOptionDB* db,
    1371              :                                       const char* section, const char* name,
    1372              :                                       const char* key, const char* doc_string,
    1373              :                                       int value, int min, int max, int step);
    1374              : template void gnc_register_number_range_option(GncOptionDB* db,
    1375              :                                       const char* section, const char* name,
    1376              :                                       const char* key, const char* doc_string,
    1377              :                                       double value, double min,
    1378              :                                       double max, double step);
        

Generated by: LCOV version 2.0-1