LCOV - code coverage report
Current view: top level - libgnucash/engine - gnc-optiondb.cpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 53.5 % 608 325
Test Date: 2025-02-07 16:25:45 Functions: 56.0 % 100 56
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     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                 :       56489 :     static const AliasedOption* find_alias (const char* old_name)
      51                 :             :     {
      52                 :       56489 :         if (!old_name) return nullptr;
      53                 :             :         const auto alias =
      54                 :       56489 :             std::find_if(c_option_aliases.begin(), c_option_aliases.end(),
      55                 :     2227906 :                          [old_name](auto alias){
      56                 :     2227906 :                              return std::strcmp(old_name, alias.first) == 0;
      57                 :             :                          });
      58                 :       56489 :         if (alias == c_option_aliases.end())
      59                 :       54211 :             return nullptr;
      60                 :             : 
      61                 :        2278 :         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                 :      832020 : operator==(const std::string& str, const char* cstr)
     126                 :             : {
     127                 :      832020 :     return strcmp(str.c_str(), cstr) == 0;
     128                 :             : }
     129                 :             : 
     130                 :             : void
     131                 :        8311 : GncOptionSection::foreach_option(std::function<void(GncOption&)> func)
     132                 :             : {
     133                 :        8311 :     std::for_each(m_options.begin(), m_options.end(), func);
     134                 :        8311 : }
     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                 :       83284 : GncOptionSection::add_option(GncOption&& option)
     144                 :             : {
     145                 :       83284 :     m_options.push_back(std::move(option));
     146                 :       83284 :     if (!std::is_sorted(m_options.begin(), m_options.end()))
     147                 :       22623 :         std::sort(m_options.begin(), m_options.end());
     148                 :       83284 : }
     149                 :             : 
     150                 :             : void
     151                 :           7 : GncOptionSection::remove_option(const char* name)
     152                 :             : {
     153                 :           7 :     m_options.erase(std::remove_if(m_options.begin(), m_options.end(),
     154                 :          19 :                                    [name](const auto& option) -> bool
     155                 :             :                                    {
     156                 :          19 :                                        return option.get_name() == name;
     157                 :           7 :                                    }), m_options.end());
     158                 :           7 : }
     159                 :             : 
     160                 :             : const GncOption*
     161                 :      130583 : GncOptionSection::find_option(const char* name) const
     162                 :             : {
     163                 :      130583 :     auto option = std::find_if(m_options.begin(), m_options.end(),
     164                 :      832001 :                                [name](auto& option) -> bool {
     165                 :      832001 :                                    return option.get_name() == name;
     166                 :             :                                });
     167                 :      130583 :     if (option != m_options.end())
     168                 :      107239 :         return &*option;
     169                 :             : 
     170                 :       23344 :     auto alias = Aliases::find_alias(name);
     171                 :       23344 :     if (!alias || alias->first) // No alias or the alias
     172                 :       23321 :         return nullptr;         // is in a different section.
     173                 :          23 :     return find_option(alias->second);
     174                 :             : }
     175                 :             : 
     176                 :        2446 : GncOptionDB::GncOptionDB() : m_default_section{} {}
     177                 :             : 
     178                 :           0 : GncOptionDB::GncOptionDB(QofBook* book) : GncOptionDB() {}
     179                 :             : 
     180                 :             : void
     181                 :       83284 : GncOptionDB::register_option(const char* sectname, GncOption&& option)
     182                 :             : {
     183                 :       83284 :     auto section = find_section(sectname);
     184                 :             : 
     185                 :       83284 :     if (section)
     186                 :             :     {
     187                 :       72877 :         section->add_option(std::move(option));
     188                 :       72877 :         return;
     189                 :             :     }
     190                 :             : 
     191                 :       10407 :     m_sections.push_back(std::make_shared<GncOptionSection>(sectname));
     192                 :       10407 :     m_sections.back()->add_option(std::move(option));
     193                 :       10407 :     if (!std::is_sorted(m_sections.begin(), m_sections.end()))
     194                 :        5825 :         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                 :           7 : GncOptionDB::unregister_option(const char* sectname, const char* name)
     206                 :             : {
     207                 :           7 :     auto section = find_section(sectname);
     208                 :           7 :     if (section)
     209                 :           7 :         section->remove_option(name);
     210                 :           7 : }
     211                 :             : 
     212                 :             : void
     213                 :        2354 : GncOptionDB::set_default_section(const char* sectname)
     214                 :             : {
     215                 :        2354 :     m_default_section = find_section(sectname);
     216                 :        2354 : }
     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                 :      226029 : GncOptionDB::find_section(const std::string& section) const
     226                 :             : {
     227                 :      226029 :     auto db_section = std::find_if(m_sections.begin(), m_sections.end(),
     228                 :      658899 :                                    [&section](auto& sect) -> bool
     229                 :             :                                    {
     230                 :      658899 :                                        return section == sect->get_name();
     231                 :             :                                    });
     232                 :      226029 :     return db_section == m_sections.end() ? nullptr : db_section->get();
     233                 :             : }
     234                 :             : 
     235                 :             : const GncOption*
     236                 :      140384 : GncOptionDB::find_option(const std::string& section, const char* name) const
     237                 :             : {
     238                 :      140384 :     auto db_section = const_cast<GncOptionDB*>(this)->find_section(section);
     239                 :      140384 :     const GncOption* option = nullptr;
     240                 :      140384 :     if (db_section)
     241                 :      130560 :         option = db_section->find_option(name);
     242                 :      140384 :     if (option)
     243                 :      107239 :         return option;
     244                 :       33145 :     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                 :       33145 :     if (alias && alias->first && section != alias->first)
     250                 :        6699 :         return find_option(alias->first, alias->second);
     251                 :       30912 :     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                 :          82 : GncOptionDB::make_internal(const char* section, const char* name)
     267                 :             : {
     268                 :             : 
     269                 :          82 :     auto db_opt = find_option(section, name);
     270                 :          82 :     if (db_opt)
     271                 :          82 :         db_opt->make_internal();
     272                 :          82 : }
     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                 :           2 :         [book](GncOptionSectionPtr& section)
     471                 :             :         {
     472                 :          16 :             section->foreach_option(
     473                 :           8 :                 [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                 :        4542 : 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                 :        4542 :             GncOptionUIType::STRING};
     632                 :        4542 :     db->register_option(section, std::move(option));
     633                 :        4542 : }
     634                 :             : 
     635                 :             : void
     636                 :         156 : 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                 :         156 :             GncOptionUIType::TEXT};
     642                 :         156 :     db->register_option(section, std::move(option));
     643                 :             : 
     644                 :         156 : }
     645                 :             : 
     646                 :             : void
     647                 :         174 : 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                 :         174 :             GncOptionUIType::FONT};
     653                 :         174 :     db->register_option(section, std::move(option));
     654                 :         174 : }
     655                 :             : 
     656                 :             : void
     657                 :          21 : 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                 :          42 :     GncOption option{GncOptionQofInstanceValue{section, name, key, doc_string,
     662                 :             :                                                (const QofInstance*)value,
     663                 :          21 :                                                GncOptionUIType::BUDGET}};
     664                 :          21 :     db->register_option(section, std::move(option));
     665                 :          21 : }
     666                 :             : 
     667                 :             : void
     668                 :          50 : 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                 :          50 :             GncOptionUIType::COLOR};
     674                 :          50 :     db->register_option(section, std::move(option));
     675                 :          50 : }
     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                 :           5 : 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                 :           5 :     gnc_commodity* commodity{};
     694                 :           5 :     const auto book{qof_session_get_book(gnc_get_current_session())};
     695                 :           5 :     const auto commodity_table{gnc_commodity_table_get_table(book)};
     696                 :           5 :     const auto namespaces{gnc_commodity_table_get_namespaces(commodity_table)};
     697                 :           5 :     for (auto node = namespaces; node && commodity == nullptr;
     698                 :           0 :          node = g_list_next(node))
     699                 :             :     {
     700                 :          10 :         commodity = gnc_commodity_table_lookup(commodity_table,
     701                 :           5 :                                                (const char*)(node->data),
     702                 :             :                                                value);
     703                 :           5 :         if (commodity)
     704                 :           5 :             break;
     705                 :             :     }
     706                 :          10 :     GncOption option{GncOptionCommodityValue{section, name, key, doc_string,
     707                 :             :                 commodity,
     708                 :           5 :                 GncOptionUIType::COMMODITY}};
     709                 :           5 :     db->register_option(section, std::move(option));
     710                 :           5 :     g_list_free (namespaces);
     711                 :           5 : }
     712                 :             : 
     713                 :             : void
     714                 :       37112 : 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                 :       37112 :             GncOptionUIType::BOOLEAN};
     721                 :       37112 :     db->register_option(section, std::move(option));
     722                 :       37112 : }
     723                 :             : 
     724                 :             : void
     725                 :          61 : 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                 :          61 :             GncOptionUIType::PIXMAP};
     731                 :          61 :     db->register_option(section, std::move(option));
     732                 :          61 : }
     733                 :             : 
     734                 :             : void
     735                 :        3175 : 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                 :        6350 :     GncOption option{GncOptionAccountListValue{section, name, key, doc_string,
     741                 :        3175 :                 GncOptionUIType::ACCOUNT_LIST, value}};
     742                 :        3175 :     db->register_option(section, std::move(option));
     743                 :        3175 : }
     744                 :             : 
     745                 :             : void
     746                 :         158 : 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                 :         313 :         GncOption option{GncOptionAccountListValue{section, name, key, doc_string,
     756                 :         313 :                     GncOptionUIType::ACCOUNT_LIST, value, std::move(allowed)}};
     757                 :         155 :         db->register_option(section, std::move(option));
     758                 :         155 :     }
     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                 :         158 : }
     764                 :             : 
     765                 :             : using AccountPair = std::pair<GncOptionAccountList&,
     766                 :             :                               const GncOptionAccountTypeList&>;
     767                 :             : static void
     768                 :         179 : find_children(Account* account, void* data)
     769                 :             : {
     770                 :         179 :     auto datapair =
     771                 :             :         (AccountPair*)data;
     772                 :         179 :     GncOptionAccountList& list = datapair->first;
     773                 :         179 :     const GncOptionAccountTypeList& types = datapair->second;
     774                 :         179 :     if (std::find(types.begin(), types.end(),
     775                 :         358 :                   xaccAccountGetType(account)) != types.end())
     776                 :          73 :         list.push_back(*qof_entity_get_guid(account));
     777                 :         179 : }
     778                 :             : 
     779                 :             : GncOptionAccountList
     780                 :          19 : gnc_account_list_from_types(QofBook *book,
     781                 :             :                             const GncOptionAccountTypeList& types)
     782                 :             : {
     783                 :          19 :     GncOptionAccountList list;
     784                 :          19 :     AccountPair funcdata{list, types};
     785                 :          19 :     Account* base_acct = gnc_book_get_root_account(book);
     786                 :          19 :     gnc_account_foreach_descendant(base_acct, (AccountCb)find_children,
     787                 :             :                                    &funcdata);
     788                 :          38 :     return list;
     789                 :           0 : }
     790                 :             : 
     791                 :             : 
     792                 :             : void
     793                 :          32 : 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                 :          64 :         GncOption option{GncOptionAccountSelValue{section, name, key, doc_string,
     802                 :          64 :                     GncOptionUIType::ACCOUNT_SEL, value, std::move(allowed)}};
     803                 :          32 :     db->register_option(section, std::move(option));
     804                 :          32 :     }
     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                 :          32 : }
     810                 :             : 
     811                 :             : void
     812                 :       15738 : 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                 :       31476 :     std::string defval{default_val};
     818                 :       15738 :     auto found{std::find_if(choices.begin(), choices.end(),
     819                 :       25952 :                             [&defval](auto& choice)->bool {
     820                 :       25952 :                                 return defval == std::get<0>(choice);
     821                 :             :                             })};
     822                 :       15738 :     if (found == choices.end())
     823                 :          20 :         defval = (choices.empty() ? std::string{"None"} :
     824                 :           5 :                   std::get<0>(choices.at(0)));
     825                 :       47214 :     GncOption option{GncOptionMultichoiceValue{section, name, key, doc_string,
     826                 :       31476 :                 defval.c_str(), std::move(choices)}};
     827                 :       15738 :     db->register_option(section, std::move(option));
     828                 :       15738 : }
     829                 :             : 
     830                 :             : void
     831                 :          11 : 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                 :          22 :     GncOption option{GncOptionMultichoiceValue{section, name, key, doc_string,
     837                 :          22 :                 value,  std::move(list), GncOptionUIType::LIST}};
     838                 :          11 :     db->register_option(section, std::move(option));
     839                 :          11 : }
     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                 :         298 : 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                 :         298 :         GncOption option{GncOptionRangeValue<ValueType>{section, name, key,
     853                 :             :                                                         doc_string, value, min,
     854                 :             :                                                         max, step}};
     855                 :         298 :         db->register_option(section, std::move(option));
     856                 :         298 :     }
     857                 :           0 :     catch(const std::invalid_argument& err)
     858                 :             :     {
     859                 :           0 :         PWARN("Number Range Option %s, option not registerd.",
     860                 :             :               err.what());
     861                 :             :     }
     862                 :         298 : }
     863                 :             : 
     864                 :             : void
     865                 :         412 : 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                 :         824 :     GncOption option{GncOptionRangeValue<int>{section, name, key, doc_string,
     872                 :         412 :             value, 10, UINT16_MAX, 1, GncOptionUIType::PLOT_SIZE}};
     873                 :         412 :     db->register_option(section, std::move(option));
     874                 :         412 : }
     875                 :             : 
     876                 :             : void
     877                 :           7 : gnc_register_query_option(GncOptionDB* db, const char* section,
     878                 :             :                           const char* name, const QofQuery* value)
     879                 :             : {
     880                 :             :     GncOption option{section, name, "", "", value,
     881                 :           7 :             GncOptionUIType::INTERNAL};
     882                 :           7 :     db->register_option(section, std::move(option));
     883                 :           7 : }
     884                 :             : 
     885                 :             : void
     886                 :          20 : 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                 :          20 :     switch (type)
     893                 :             :     {
     894                 :          11 :     case GNC_OWNER_CUSTOMER:
     895                 :          11 :         uitype = GncOptionUIType::CUSTOMER;
     896                 :          11 :         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                 :          40 :     GncOption option{GncOptionGncOwnerValue{section, name, key, doc_string,
     910                 :          40 :                                             value, uitype}};
     911                 :          20 :     db->register_option(section, std::move(option));
     912                 :          20 : }
     913                 :             : 
     914                 :             : void
     915                 :          39 : 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                 :          78 :     GncOption option{GncOptionQofInstanceValue{section, name, key, doc_string,
     920                 :             :                                                (const QofInstance*)value,
     921                 :          39 :                                                GncOptionUIType::INVOICE}};
     922                 :          39 :     db->register_option(section, std::move(option));
     923                 :          39 : }
     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                 :        2271 : 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                 :        4542 :     GncOption option{GncOptionCommodityValue{
     984                 :             :         section, name, key, doc_string, value, GncOptionUIType::CURRENCY
     985                 :        2271 :         }};
     986                 :        2271 :     db->register_option(section, std::move(option));
     987                 :        2271 : }
     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                 :           2 :     GncOption option{GncOptionDateValue(section, name, key, doc_string,
    1015                 :           1 :                                         ui_type, time)};
    1016                 :           1 :     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                 :          10 :     GncOption option{GncOptionDateValue(section, name, key, doc_string,
    1029                 :           5 :                                         ui_type, period)};
    1030                 :           5 :     db->register_option(section, std::move(option));
    1031                 :           5 : }
    1032                 :             : 
    1033                 :             : void
    1034                 :          10 : 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                 :          13 :     auto is_absolute = period_set.size() == 1 &&
    1041                 :           3 :                        period_set.front() == RelativeDatePeriod::ABSOLUTE;
    1042                 :          16 :     auto ui_type = both ? GncOptionUIType::DATE_BOTH :
    1043                 :           6 :         is_absolute ? GncOptionUIType::DATE_ABSOLUTE : GncOptionUIType::DATE_RELATIVE;
    1044                 :          20 :     GncOption option{GncOptionDateValue(section, name, key, doc_string,
    1045                 :          10 :                                         ui_type, period_set)};
    1046                 :          10 :     if (is_absolute)
    1047                 :           3 :         option.set_default_value(gnc_time(nullptr));
    1048                 :          10 :     db->register_option(section, std::move(option));
    1049                 :          10 : }
    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                 :        2253 : 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                 :        2253 :     auto ui_type = both ? GncOptionUIType::DATE_BOTH :
    1070                 :             :         GncOptionUIType::DATE_RELATIVE;
    1071                 :        4506 :     GncOption option{GncOptionDateValue(section, name, key, doc_string,
    1072                 :        2253 :                                         ui_type, begin_dates)};
    1073                 :        2253 :     db->register_option(section, std::move(option));
    1074                 :        2253 : }
    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                 :        2296 : 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                 :        2296 :     auto ui_type = both ? GncOptionUIType::DATE_BOTH :
    1094                 :             :         GncOptionUIType::DATE_RELATIVE;
    1095                 :        4592 :     GncOption option{GncOptionDateValue(section, name, key, doc_string,
    1096                 :        2296 :                                         ui_type, end_dates)};
    1097                 :        2296 :     db->register_option(section, std::move(option));
    1098                 :        2296 : }
    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                 :          10 :     GncOption option{GncOptionValue<GncOptionReportPlacementVec>{section, name,
    1109                 :             :                                                               "no_key", "nodoc_string",
    1110                 :           5 :                                                               value,GncOptionUIType::REPORT_PLACEMENT}};
    1111                 :           5 :     db->register_option(section, std::move(option));
    1112                 :           5 : }
    1113                 :             : 
    1114                 :             : void
    1115                 :          14 : gnc_register_internal_option(GncOptionDBPtr& db,
    1116                 :             :                              const char* section, const char* name,
    1117                 :             :                              const std::string& value)
    1118                 :             : {
    1119                 :             :     GncOption option{
    1120                 :          28 :         GncOptionValue<std::string>{section, name, "", "", value,
    1121                 :          14 :                                     GncOptionUIType::INTERNAL}};
    1122                 :          14 :     db->register_option(section, std::move(option));
    1123                 :          14 : }
    1124                 :             : 
    1125                 :             : void
    1126                 :        1038 : gnc_register_internal_option(GncOptionDBPtr& db,
    1127                 :             :                              const char* section, const char* name,
    1128                 :             :                              bool value)
    1129                 :             : {
    1130                 :             :     GncOption option{
    1131                 :        2076 :         GncOptionValue<bool>{section, name, "", "", value,
    1132                 :        1038 :                              GncOptionUIType::INTERNAL}};
    1133                 :        1038 :     db->register_option(section, std::move(option));
    1134                 :        1038 : }
    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 TaxTable"), "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 TaxTable"), "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