GnuCash  5.6-150-g038405b370+
gnc-optiondb.cpp
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  static const AliasedOption* find_alias (const char* old_name)
51  {
52  if (!old_name) return nullptr;
53  const auto alias =
54  std::find_if(c_option_aliases.begin(), c_option_aliases.end(),
55  [old_name](auto alias){
56  return std::strcmp(old_name, alias.first) == 0;
57  });
58  if (alias == c_option_aliases.end())
59  return nullptr;
60 
61  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 operator==(const std::string& str, const char* cstr)
126 {
127  return strcmp(str.c_str(), cstr) == 0;
128 }
129 
130 void
131 GncOptionSection::foreach_option(std::function<void(GncOption&)> func)
132 {
133  std::for_each(m_options.begin(), m_options.end(), func);
134 }
135 
136 void
137 GncOptionSection::foreach_option(std::function<void(const GncOption&)> func) const
138 {
139  std::for_each(m_options.begin(), m_options.end(), func);
140 }
141 
142 void
143 GncOptionSection::add_option(GncOption&& option)
144 {
145  m_options.push_back(std::move(option));
146  if (!std::is_sorted(m_options.begin(), m_options.end()))
147  std::sort(m_options.begin(), m_options.end());
148 }
149 
150 void
151 GncOptionSection::remove_option(const char* name)
152 {
153  m_options.erase(std::remove_if(m_options.begin(), m_options.end(),
154  [name](const auto& option) -> bool
155  {
156  return option.get_name() == name;
157  }), m_options.end());
158 }
159 
160 const GncOption*
161 GncOptionSection::find_option(const char* name) const
162 {
163  auto option = std::find_if(m_options.begin(), m_options.end(),
164  [name](auto& option) -> bool {
165  return option.get_name() == name;
166  });
167  if (option != m_options.end())
168  return &*option;
169 
170  auto alias = Aliases::find_alias(name);
171  if (!alias || alias->first) // No alias or the alias
172  return nullptr; // is in a different section.
173  return find_option(alias->second);
174 }
175 
176 GncOptionDB::GncOptionDB() : m_default_section{} {}
177 
178 GncOptionDB::GncOptionDB(QofBook* book) : GncOptionDB() {}
179 
180 void
181 GncOptionDB::register_option(const char* sectname, GncOption&& option)
182 {
183  auto section = find_section(sectname);
184 
185  if (section)
186  {
187  section->add_option(std::move(option));
188  return;
189  }
190 
191  m_sections.push_back(std::make_shared<GncOptionSection>(sectname));
192  m_sections.back()->add_option(std::move(option));
193  if (!std::is_sorted(m_sections.begin(), m_sections.end()))
194  std::sort(m_sections.begin(), m_sections.end());
195 }
196 
197 void
198 GncOptionDB::register_option(const char* sectname, GncOption* option)
199 {
200  register_option(sectname, std::move(*option));
201  delete option;
202 }
203 
204 void
205 GncOptionDB::unregister_option(const char* sectname, const char* name)
206 {
207  auto section = find_section(sectname);
208  if (section)
209  section->remove_option(name);
210 }
211 
212 void
213 GncOptionDB::set_default_section(const char* sectname)
214 {
215  m_default_section = find_section(sectname);
216 }
217 
218 const GncOptionSection* const
219 GncOptionDB::get_default_section() const noexcept
220 {
221  return m_default_section;
222 }
223 
224 const GncOptionSection*
225 GncOptionDB::find_section(const std::string& section) const
226 {
227  auto db_section = std::find_if(m_sections.begin(), m_sections.end(),
228  [&section](auto& sect) -> bool
229  {
230  return section == sect->get_name();
231  });
232  return db_section == m_sections.end() ? nullptr : db_section->get();
233 }
234 
235 const GncOption*
236 GncOptionDB::find_option(const std::string& section, const char* name) const
237 {
238  auto db_section = const_cast<GncOptionDB*>(this)->find_section(section);
239  const GncOption* option = nullptr;
240  if (db_section)
241  option = db_section->find_option(name);
242  if (option)
243  return option;
244  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  if (alias && alias->first && section != alias->first)
250  return find_option(alias->first, alias->second);
251  return nullptr;
252 }
253 
254 std::string
255 GncOptionDB::lookup_string_option(const char* section, const char* name)
256 {
257  static const std::string empty_string{};
258 
259  auto db_opt = find_option(section, name);
260  if (!db_opt)
261  return empty_string;
262  return db_opt->get_value<std::string>();
263 }
264 
265 void
266 GncOptionDB::make_internal(const char* section, const char* name)
267 {
268 
269  auto db_opt = find_option(section, name);
270  if (db_opt)
271  db_opt->make_internal();
272 }
273 
274 std::ostream&
275 GncOptionDB::save_option_key_value(std::ostream& oss,
276  const std::string& section,
277  const std::string& name) const noexcept
278 {
279 
280  auto db_opt = find_option(section, name.c_str());
281  if (!db_opt || !db_opt->is_changed())
282  return oss;
283  oss << section.substr(0, classifier_size_max) << ":" <<
284  name.substr(0, classifier_size_max) << "=" << *db_opt << ";";
285  return oss;
286 }
287 
288 std::istream&
289 GncOptionDB::load_option_key_value(std::istream& iss)
290 {
291 
292  char section[classifier_size_max], name[classifier_size_max];
293  iss.getline(section, classifier_size_max, ':');
294  iss.getline(name, classifier_size_max, '=');
295  if (!iss)
296  throw std::invalid_argument("Section or name delimiter not found or values too long");
297  auto option = find_option(section, name);
298  if (!option)
299  iss.ignore(stream_max, ';');
300  else
301  {
302  std::string value;
303  std::getline(iss, value, ';');
304  std::istringstream item_iss{value};
305  item_iss >> *option;
306  }
307  return iss;
308 }
309 
310 std::ostream&
311 GncOptionDB::save_to_key_value(std::ostream& oss) const noexcept
312 {
313 
314  foreach_section(
315  [&oss](const GncOptionSectionPtr& section)
316  {
317  oss << "[Options]\n";
318  section->foreach_option(
319  [&oss, &section](auto& option)
320  {
321  if (option.is_changed())
322  oss << section->get_name().substr(0, classifier_size_max) <<
323  ':' << option.get_name().substr(0, classifier_size_max) <<
324  '=' << option << '\n';
325  });
326  });
327  return oss;
328 }
329 
330 std::istream&
331 GncOptionDB::load_from_key_value(std::istream& iss)
332 {
333  if (iss.peek() == '[')
334  {
335  char buf[classifier_size_max];
336  iss.getline(buf, classifier_size_max);
337  if (strcmp(buf, "[Options]") != 0) // safe
338  throw std::runtime_error("Wrong secion header for options.");
339  }
340  // Otherwise assume we were sent here correctly:
341  while (iss.peek() != '[') //Indicates the start of the next file section
342  {
343  load_option_key_value(iss);
344  }
345  return iss;
346 }
347 
348 size_t
349 GncOptionDB::register_callback(GncOptionDBChangeCallback cb, void* data)
350 {
351  constexpr std::hash<GncOptionDBChangeCallback> cb_hash;
352  auto id{cb_hash(cb)};
353  if (std::find_if(m_callbacks.begin(), m_callbacks.end(),
354  [id](auto&cb)->bool{ return cb.m_id == id; }) == m_callbacks.end())
355  m_callbacks.emplace_back(id, cb, data);
356  return id;
357 }
358 
359 void
360 GncOptionDB::unregister_callback(size_t id)
361 {
362  m_callbacks.erase(std::remove_if(m_callbacks.begin(), m_callbacks.end(),
363  [id](auto& cb)->bool { return cb.m_id == id; }),
364  m_callbacks.end());
365 }
366 
367 void
368 GncOptionDB::run_callbacks()
369 {
370  std::for_each(m_callbacks.begin(), m_callbacks.end(),
371  [](auto& cb)->void { cb.m_func(cb.m_data); });
372 }
373 
374 static inline void
375 counter_option_path(const GncOption& option, GSList* list, std::string& name)
376 {
377  constexpr const char* counters{"counters"};
378  constexpr const char* formats{"counter_formats"};
379  auto key = option.get_key();
380  name = key.substr(0, key.size() - 1);
381  list->next->data = (void*)name.c_str();
382  if (option.get_name().rfind("format")
383  != std::string::npos)
384  list->data = (void*)formats;
385  else
386  list->data = (void*)counters;
387 }
388 
389 static inline void
390 option_path(const GncOption& option, GSList* list)
391 {
392  list->next->data = (void*)option.get_name().c_str();
393  list->data = (void*)option.get_section().c_str();
394 }
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 kvp_value_from_bool_option(const GncOption& option)
406 {
407  auto val{option.template get_value<bool>()};
408  // ~KvpValue will g_free the value.
409  return new KvpValue(val ? g_strdup("t") : g_strdup("f"));
410 }
411 
412 static bool
413 is_qofinstance_ui_type(GncOptionUIType type)
414 {
415  switch (type)
416  {
417  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  return true;
427  default:
428  return false;
429  }
430 }
431 
432 static inline KvpValue*
433 kvp_value_from_qof_instance_option(const GncOption& option)
434 {
435  const QofInstance* inst{QOF_INSTANCE(option.template get_value<const QofInstance*>())};
436  auto guid = guid_copy(qof_instance_get_guid(inst));
437  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 kvp_frame_from_date_format_option(const GncOption& option)
450 {
451  auto [format, months, years, custom] = option.get_value<GncOptionDateFormat>();
452 
453  if (format == QOF_DATE_FORMAT_UNSET)
454  return nullptr;
455 
456  auto frame{new KvpFrame};
457  frame->set({date_format_format_key}, new KvpValue(g_strdup(gnc_date_dateformat_to_string(format))));
458  frame->set({date_format_months_key}, new KvpValue(g_strdup(gnc_date_monthformat_to_string(months))));
459  frame->set({date_format_years_key}, new KvpValue(static_cast<int64_t>(years)));
460  frame->set({date_format_custom_key}, new KvpValue(g_strdup(custom.c_str())));
461  return new KvpValue(frame);
462 };
463 
464 void
465 GncOptionDB::save_to_kvp(QofBook* book, bool clear_options) const noexcept
466 {
467  if (clear_options)
468  qof_book_options_delete(book, nullptr);
469  const_cast<GncOptionDB*>(this)->foreach_section(
470  [book](GncOptionSectionPtr& section)
471  {
472  section->foreach_option(
473  [book, &section](GncOption& option) {
474  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  std::string name;
480  /* qof_book_set_option wants a GSList path. Let's avoid
481  * allocating and make one here. */
482  GSList list_tail{}, list_head{nullptr, &list_tail};
483  if (strcmp(section->get_name().c_str(), "Counters") == 0)
484  counter_option_path(option, &list_head, name);
485  else
486  option_path(option, &list_head);
487  auto type{option.get_ui_type()};
488  KvpValue* kvp{};
489  if (type == GncOptionUIType::BOOLEAN)
490  kvp = kvp_value_from_bool_option(option);
491  else if (is_qofinstance_ui_type(type))
492  kvp = kvp_value_from_qof_instance_option(option);
493  else if (type == GncOptionUIType::NUMBER_RANGE)
494  {
495  if (option.is_alternate())
496  {
497  kvp = new KvpValue(static_cast<int64_t>(option.template get_value<int>()));
498  }
499  else
500  {
501  kvp = new KvpValue(option.template get_value<double>());
502  }
503  }
504  else if (type == GncOptionUIType::DATE_FORMAT)
505  kvp = kvp_frame_from_date_format_option(option);
506  else
507  {
508  auto str{option.template get_value<std::string>()};
509  kvp = new KvpValue{g_strdup(str.c_str())};
510  }
511  qof_book_set_option(book, kvp, &list_head);
512  option.mark_saved();
513  }
514  });
515  });
516 }
517 
518 static inline void
519 fill_option_from_string_kvp(GncOption& option, KvpValue* kvp)
520 {
521  auto str{kvp->get<const char*>()};
522  if (option.get_ui_type() == GncOptionUIType::BOOLEAN)
523  option.set_value(*str == 't' ? true : false);
524  else
525  option.set_value(std::string{str});
526 }
527 
528 static inline void
529 fill_option_from_guid_kvp(GncOption& option, KvpValue* kvp)
530 {
531  auto guid{kvp->get<GncGUID*>()};
532  option.set_value(
533  (const QofInstance*)qof_instance_from_guid(guid, option.get_ui_type()));
534 }
535 
536 static inline void
537 fill_option_from_date_format_kvp(GncOption& option, KvpValue* kvp)
538 {
539  GncOptionDateFormat default_fmt{QOF_DATE_FORMAT_UNSET, GNCDATE_MONTH_NUMBER, true, ""};
540  auto frame{kvp->get<KvpFrame*>()};
541  if (!frame)
542  {
543  option.set_value(default_fmt);
544  return;
545  }
546  auto format_str{frame->get_slot({date_format_format_key})->get<const char*>()};
547  QofDateFormat format;
548  if (!format_str || gnc_date_string_to_dateformat(format_str, &format))
549  {
550  option.set_value(default_fmt);
551  return;
552  }
553  GNCDateMonthFormat months = GNCDATE_MONTH_NUMBER;
554  auto months_str{frame->get_slot({date_format_months_key})->get<const char*>()};
555  if (months_str)
556  gnc_date_string_to_monthformat(months_str, &months);
557  auto years_num{frame->get_slot({date_format_years_key})->get<int64_t>()};
558  bool years = static_cast<bool>(years_num);
559  auto custom_str{frame->get_slot({date_format_custom_key})->get<const char*>()};
560  option.set_value<GncOptionDateFormat>({format, months, years, custom_str ? custom_str : ""});
561 }
562 
563 void
564 GncOptionDB::load_from_kvp(QofBook* book) noexcept
565 {
566  foreach_section(
567  [book](GncOptionSectionPtr& section)
568  {
569  section->foreach_option(
570  [book, &section](GncOption& option)
571  {
572  // Make path list as above.
573  std::string name;
574  /* qof_book_set_option wants a GSList path. Let's avoid
575  * allocating and make one here. */
576  GSList list_tail{}, list_head{nullptr, &list_tail};
577  if (strcmp(section->get_name().c_str(), "Counters") == 0)
578  counter_option_path(option, &list_head, name);
579  else
580  option_path(option, &list_head);
581  auto kvp = qof_book_get_option(book, &list_head);
582  if (!kvp)
583  return;
584 
585  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  constexpr const char *counters{"counters"};
592  auto value{kvp->get<double>()};
593  if (strcmp(static_cast<char*>(list_head.data), counters) == 0)
594  option.set_value(static_cast<int>(value));
595  else
596  option.set_value(value);
597  };
598 
599  switch (kvp->get_type())
600  {
601  case KvpValue::Type::DOUBLE:
602  set_double();
603  break;
604  case KvpValue::Type::INT64:
605  option.set_value(static_cast<int>(kvp->get<int64_t>()));
606  break;
607  case KvpValue::Type::STRING:
608  fill_option_from_string_kvp(option, kvp);
609  break;
610  case KvpValue::Type::GUID:
611  fill_option_from_guid_kvp(option, kvp);
612  break;
613  case KvpValue::Type::FRAME:
614  if (g_strcmp0(option.get_name().c_str(), date_format_frame_key) == 0)
615  fill_option_from_date_format_kvp(option, kvp);
616  break;
617  default:
618  return;
619  break;
620  }
621  });
622  });
623 }
624 
625 void
626 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  GncOptionUIType::STRING};
632  db->register_option(section, std::move(option));
633 }
634 
635 void
636 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  GncOptionUIType::TEXT};
642  db->register_option(section, std::move(option));
643 
644 }
645 
646 void
647 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  GncOptionUIType::FONT};
653  db->register_option(section, std::move(option));
654 }
655 
656 void
657 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  GncOption option{GncOptionQofInstanceValue{section, name, key, doc_string,
662  (const QofInstance*)value,
663  GncOptionUIType::BUDGET}};
664  db->register_option(section, std::move(option));
665 }
666 
667 void
668 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  GncOptionUIType::COLOR};
674  db->register_option(section, std::move(option));
675 }
676 
677 void
679  const char* name, const char* key,
680  const char* doc_string, gnc_commodity *value)
681 {
682  GncOption option{GncOptionCommodityValue{section, name, key, doc_string,
683  value,
684  GncOptionUIType::COMMODITY}};
685  db->register_option(section, std::move(option));
686 }
687 
688 void
690  const char* name, const char* key,
691  const char* doc_string, const char* value)
692 {
693  gnc_commodity* commodity{};
694  const auto book{qof_session_get_book(gnc_get_current_session())};
695  const auto commodity_table{gnc_commodity_table_get_table(book)};
696  const auto namespaces{gnc_commodity_table_get_namespaces(commodity_table)};
697  for (auto node = namespaces; node && commodity == nullptr;
698  node = g_list_next(node))
699  {
700  commodity = gnc_commodity_table_lookup(commodity_table,
701  (const char*)(node->data),
702  value);
703  if (commodity)
704  break;
705  }
706  GncOption option{GncOptionCommodityValue{section, name, key, doc_string,
707  commodity,
708  GncOptionUIType::COMMODITY}};
709  db->register_option(section, std::move(option));
710  g_list_free (namespaces);
711 }
712 
713 void
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  GncOptionUIType::BOOLEAN};
721  db->register_option(section, std::move(option));
722 }
723 
724 void
725 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  GncOptionUIType::PIXMAP};
731  db->register_option(section, std::move(option));
732 }
733 
734 void
736  const char* name, const char* key,
737  const char* doc_string,
738  const GncOptionAccountList& value)
739 {
740  GncOption option{GncOptionAccountListValue{section, name, key, doc_string,
741  GncOptionUIType::ACCOUNT_LIST, value}};
742  db->register_option(section, std::move(option));
743 }
744 
745 void
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  GncOption option{GncOptionAccountListValue{section, name, key, doc_string,
756  GncOptionUIType::ACCOUNT_LIST, value, std::move(allowed)}};
757  db->register_option(section, std::move(option));
758  }
759  catch (const std::invalid_argument& err)
760  {
761  PWARN("Account List Limited Option, value failed validation, option not registered.");
762  }
763 }
764 
765 using AccountPair = std::pair<GncOptionAccountList&,
766  const GncOptionAccountTypeList&>;
767 static void
768 find_children(Account* account, void* data)
769 {
770  auto datapair =
771  (AccountPair*)data;
772  GncOptionAccountList& list = datapair->first;
773  const GncOptionAccountTypeList& types = datapair->second;
774  if (std::find(types.begin(), types.end(),
775  xaccAccountGetType(account)) != types.end())
776  list.push_back(*qof_entity_get_guid(account));
777 }
778 
779 GncOptionAccountList
781  const GncOptionAccountTypeList& types)
782 {
783  GncOptionAccountList list;
784  AccountPair funcdata{list, types};
785  Account* base_acct = gnc_book_get_root_account(book);
786  gnc_account_foreach_descendant(base_acct, (AccountCb)find_children,
787  &funcdata);
788  return list;
789 }
790 
791 
792 void
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  GncOption option{GncOptionAccountSelValue{section, name, key, doc_string,
802  GncOptionUIType::ACCOUNT_SEL, value, std::move(allowed)}};
803  db->register_option(section, std::move(option));
804  }
805  catch (const std::invalid_argument& err)
806  {
807  PWARN("Account Sel Limited Option, value failed validation, option not registerd.");
808  }
809 }
810 
811 void
813  const char* name, const char* key,
814  const char* doc_string, const char* default_val,
815  GncMultichoiceOptionChoices&& choices)
816 {
817  std::string defval{default_val};
818  auto found{std::find_if(choices.begin(), choices.end(),
819  [&defval](auto& choice)->bool {
820  return defval == std::get<0>(choice);
821  })};
822  if (found == choices.end())
823  defval = (choices.empty() ? std::string{"None"} :
824  std::get<0>(choices.at(0)));
825  GncOption option{GncOptionMultichoiceValue{section, name, key, doc_string,
826  defval.c_str(), std::move(choices)}};
827  db->register_option(section, std::move(option));
828 }
829 
830 void
831 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  GncOption option{GncOptionMultichoiceValue{section, name, key, doc_string,
837  value, std::move(list), GncOptionUIType::LIST}};
838  db->register_option(section, std::move(option));
839 }
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
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  GncOption option{GncOptionRangeValue<ValueType>{section, name, key,
853  doc_string, value, min,
854  max, step}};
855  db->register_option(section, std::move(option));
856  }
857  catch(const std::invalid_argument& err)
858  {
859  PWARN("Number Range Option %s, option not registerd.",
860  err.what());
861  }
862 }
863 
864 void
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  GncOption option{GncOptionRangeValue<int>{section, name, key, doc_string,
872  value, 10, UINT16_MAX, 1, GncOptionUIType::PLOT_SIZE}};
873  db->register_option(section, std::move(option));
874 }
875 
876 void
877 gnc_register_query_option(GncOptionDB* db, const char* section,
878  const char* name, const QofQuery* value)
879 {
880  GncOption option{section, name, "", "", value,
881  GncOptionUIType::INTERNAL};
882  db->register_option(section, std::move(option));
883 }
884 
885 void
886 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  switch (type)
893  {
894  case GNC_OWNER_CUSTOMER:
895  uitype = GncOptionUIType::CUSTOMER;
896  break;
897  case GNC_OWNER_EMPLOYEE:
898  uitype = GncOptionUIType::EMPLOYEE;
899  break;
900  case GNC_OWNER_JOB:
901  uitype = GncOptionUIType::JOB;
902  break;
903  case GNC_OWNER_VENDOR:
904  uitype = GncOptionUIType::VENDOR;
905  break;
906  default:
907  uitype = GncOptionUIType::INTERNAL;
908  };
909  GncOption option{GncOptionGncOwnerValue{section, name, key, doc_string,
910  value, uitype}};
911  db->register_option(section, std::move(option));
912 }
913 
914 void
915 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  GncOption option{GncOptionQofInstanceValue{section, name, key, doc_string,
920  (const QofInstance*)value,
921  GncOptionUIType::INVOICE}};
922  db->register_option(section, std::move(option));
923 }
924 
925 void
926 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  GncOption option{GncOptionQofInstanceValue{section, name, key, doc_string,
931  (const QofInstance*)value,
932  GncOptionUIType::TAX_TABLE}};
933  db->register_option(section, std::move(option));
934 }
935 
936 void
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  value, GncOptionUIType::INV_REPORT};
943  db->register_option(section, std::move(option));
944 }
945 
946 void
947 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  GncOption option{GncOptionRangeValue<int>{section, name, key, doc_string,
952  value, 0, 999999999, 1}};
953  option.set_alternate(true);
954  db->register_option(section, std::move(option));
955 }
956 
957 void
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  GncOptionUIType::STRING};
965  db->register_option(section, std::move(option));
966 }
967 
968 void
970  const char* name, const char* key,
971  const char* doc_string, GncOptionDateFormat&& value)
972 {
973  GncOption option{section, name, key, doc_string, std::move(value),
974  GncOptionUIType::DATE_FORMAT};
975  db->register_option(section, std::move(option));
976 }
977 
978 void
979 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 {
984  section, name, key, doc_string, value, GncOptionUIType::CURRENCY
985  }};
986  db->register_option(section, std::move(option));
987 }
988 
989 void
990 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  const auto book{qof_session_get_book(gnc_get_current_session())};
995  const auto commodity_table{gnc_commodity_table_get_table(book)};
996  const auto commodity = gnc_commodity_table_lookup(commodity_table,
997  "CURRENCY",
998  value);
1000  section, name, key, doc_string, commodity, GncOptionUIType::CURRENCY
1001  }};
1002  db->register_option(section, std::move(option));
1003 }
1004 
1005 void
1006 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  auto ui_type = ui == RelativeDateUI::BOTH ? GncOptionUIType::DATE_BOTH :
1012  ui == RelativeDateUI::RELATIVE ? GncOptionUIType::DATE_RELATIVE :
1013  GncOptionUIType::DATE_ABSOLUTE;
1014  GncOption option{GncOptionDateValue(section, name, key, doc_string,
1015  ui_type, time)};
1016  db->register_option(section, std::move(option));
1017 }
1018 
1019 void
1020 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  auto ui_type = ui == RelativeDateUI::BOTH ? GncOptionUIType::DATE_BOTH :
1026  ui == RelativeDateUI::RELATIVE ? GncOptionUIType::DATE_RELATIVE :
1027  GncOptionUIType::DATE_ABSOLUTE;
1028  GncOption option{GncOptionDateValue(section, name, key, doc_string,
1029  ui_type, period)};
1030  db->register_option(section, std::move(option));
1031 }
1032 
1033 void
1035  const char* section, const char* name,
1036  const char* key, const char* doc_string,
1037  RelativeDatePeriodVec& period_set,
1038  bool both)
1039 {
1040  auto is_absolute = period_set.size() == 1 &&
1041  period_set.front() == RelativeDatePeriod::ABSOLUTE;
1042  auto ui_type = both ? GncOptionUIType::DATE_BOTH :
1043  is_absolute ? GncOptionUIType::DATE_ABSOLUTE : GncOptionUIType::DATE_RELATIVE;
1044  GncOption option{GncOptionDateValue(section, name, key, doc_string,
1045  ui_type, period_set)};
1046  if (is_absolute)
1047  option.set_default_value(gnc_time(nullptr));
1048  db->register_option(section, std::move(option));
1049 }
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
1066  const char* name, const char* key,
1067  const char* doc_string, bool both)
1068 {
1069  auto ui_type = both ? GncOptionUIType::DATE_BOTH :
1070  GncOptionUIType::DATE_RELATIVE;
1071  GncOption option{GncOptionDateValue(section, name, key, doc_string,
1072  ui_type, begin_dates)};
1073  db->register_option(section, std::move(option));
1074 }
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
1090  const char* name, const char* key,
1091  const char* doc_string, bool both)
1092 {
1093  auto ui_type = both ? GncOptionUIType::DATE_BOTH :
1094  GncOptionUIType::DATE_RELATIVE;
1095  GncOption option{GncOptionDateValue(section, name, key, doc_string,
1096  ui_type, end_dates)};
1097  db->register_option(section, std::move(option));
1098 }
1099 
1100 void
1101 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  GncOptionReportPlacementVec value;
1109  "no_key", "nodoc_string",
1110  value,GncOptionUIType::REPORT_PLACEMENT}};
1111  db->register_option(section, std::move(option));
1112 }
1113 
1114 void
1115 gnc_register_internal_option(GncOptionDBPtr& db,
1116  const char* section, const char* name,
1117  const std::string& value)
1118 {
1119  GncOption option{
1120  GncOptionValue<std::string>{section, name, "", "", value,
1121  GncOptionUIType::INTERNAL}};
1122  db->register_option(section, std::move(option));
1123 }
1124 
1125 void
1126 gnc_register_internal_option(GncOptionDBPtr& db,
1127  const char* section, const char* name,
1128  bool value)
1129 {
1130  GncOption option{
1131  GncOptionValue<bool>{section, name, "", "", value,
1132  GncOptionUIType::INTERNAL}};
1133  db->register_option(section, std::move(option));
1134 }
1135 
1136 GncOptionDB*
1138 {
1139  return new GncOptionDB;
1140 }
1141 
1142 void
1144 {
1145  PWARN("Direct Destroy called on GncOptionDB %" G_GUINT64_FORMAT, (uint64_t)odb);
1146 }
1147 
1148 GList*
1150 {
1151  GList* errors{};
1152  odb->foreach_section(
1153  [&errors](GncOptionSectionPtr& section){
1154  section->foreach_option(
1155  [&errors](GncOption& option) {
1156  try
1157  {
1158  option.set_option_from_ui_item();
1159  }
1160  catch (const std::invalid_argument& err)
1161  {
1162  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  errors = g_list_prepend(errors,
1166  (void*)option.get_name().c_str());
1167  } });
1168  });
1169  if (!errors)
1170  odb->run_callbacks();
1171  return errors;
1172 }
1173 
1174 void
1176 {
1177  odb->foreach_section(
1178  [](GncOptionSectionPtr& section){
1179  section->foreach_option(
1180  [](GncOption& option) {
1181  option.set_ui_item_from_option();
1182  });
1183  });
1184 }
1185 
1186 void gnc_option_db_load(GncOptionDB* odb, QofBook* book)
1187 {
1188  odb->load_from_kvp(book);
1189 }
1190 
1191 void
1192 gnc_option_db_save(GncOptionDB* odb, QofBook* book,
1193  gboolean clear_options)
1194 {
1195  odb->save_to_kvp(book, static_cast<bool>(clear_options));
1196 }
1197 
1198 void
1200 {
1201  constexpr const char* business_section{N_("Business")};
1202  constexpr const char* counter_section{N_("Counters")};
1203  static const std::string empty_string{""};
1204 
1205 //Accounts Tab
1206 
1207  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  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  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  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  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  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  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  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  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  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  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  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  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  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  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  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  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  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  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  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  gnc_register_string_option(odb, business_section, N_("Company Name"), "a",
1302  N_("The name of your business."),
1303  empty_string);
1304  gnc_register_text_option(odb, business_section, N_("Company Address"), "b1",
1305  N_("The address of your business."),
1306  empty_string);
1307  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  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  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  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  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  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  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  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  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  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  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  {QOF_DATE_FORMAT_UNSET, GNCDATE_MONTH_NUMBER, true, ""});
1351 
1352 //Tax Tab
1353 
1354  gnc_register_string_option(odb, N_("Tax"), N_("Tax Number"), "a",
1355  N_("The electronic tax number of your business"),
1356  empty_string);
1357 }
1358 const QofInstance*
1360  const char* name)
1361 {
1362  auto option{odb->find_option(section, name)};
1363  if (option)
1364  return option->get_value<const QofInstance*>();
1365  else
1366  return nullptr;
1367 }
1368 
1369 // Force creation of templates
1371  const char* section, const char* name,
1372  const char* key, const char* doc_string,
1373  int value, int min, int max, int step);
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);
Holds all of the options for a book, report, or stylesheet, organized by GncOptionSections.
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Returns the commodity table associated with a book.
void gnc_option_db_clean(GncOptionDB *odb)
Reset all ui_items to the option value.
const QofInstance * gnc_option_db_lookup_qofinstance_value(GncOptionDB *odb, const char *section, const char *name)
Retrieve the QofInstance value of an option in the GncOptionDB.
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
void gnc_register_simple_boolean_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, bool value)
Create a new simple boolean option and register it in the options database.
KvpValue * qof_book_get_option(QofBook *book, GSList *path)
Read a single option value.
Definition: qofbook.cpp:1374
The generic option-value class.
gboolean gnc_date_string_to_monthformat(const gchar *format_string, GNCDateMonthFormat *format)
Converts the month format to a printable string.
const char * gnc_date_dateformat_to_string(QofDateFormat format)
The string->value versions return FALSE on success and TRUE on failure.
Definition: gnc-date.cpp:280
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3217
void mark_saved() noexcept
Mark the option as needing to be saved.
Definition: gnc-option.cpp:298
void gnc_register_invoice_print_report_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, std::string value)
Create a new print report option and register it in the options database.
STRUCTS.
GncGUID * guid_copy(const GncGUID *guid)
Returns a newly allocated GncGUID that matches the passed-in GUID.
Definition: guid.cpp:120
void gnc_register_number_range_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, ValueType value, ValueType min, ValueType max, ValueType step)
Create a new number range option and register it in the options database.
OptionUITypes.
No Fancy Date Format, use Global.
Definition: gnc-date.h:131
A legal date value is a pair of either a RelativeDatePeriod, the absolute flag and a time64...
void gnc_register_counter_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, int value)
Create a new counter option and register it in the options database.
bool is_changed() const noexcept
Definition: gnc-option.cpp:314
C public interface for the Options Database.
void gnc_option_db_save(GncOptionDB *odb, QofBook *book, gboolean clear_options)
Save the GncOptionDB contents into a book&#39;s options store.
void gnc_register_multichoice_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, const char *default_val, GncMultichoiceOptionChoices &&choices)
Create a new multichoice option and register it in the options database.
Represents the public interface for an option.
Definition: gnc-option.hpp:136
Set one or more accounts on which to report, optionally restricted to certain account types...
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
void gnc_register_query_option(GncOptionDB *db, const char *section, const char *name, const QofQuery *value)
Create a new QofQuery option and register it in the options database.
void gnc_register_number_plot_size_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, int value)
Create a new plot-size option and register it in the options database.
QofBook * qof_session_get_book(const QofSession *session)
Returns the QofBook of this session.
Definition: qofsession.cpp:574
void gnc_register_date_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, time64 time, RelativeDateUI ui)
Create a new date option and register it in the options database.
Multichoice options have a vector of valid options (GncMultichoiceOptionChoices) and validate the sel...
void gnc_register_account_sel_limited_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, const Account *value, GncOptionAccountTypeList &&allowed)
Create a limited account selection option and register it in the options database.
GList * gnc_commodity_table_get_namespaces(const gnc_commodity_table *table)
Return a list of all namespaces in the commodity table.
void gnc_register_start_date_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, bool both)
Create a new start-date option and register it in the options database.
void gnc_option_db_load(GncOptionDB *odb, QofBook *book)
Load a book&#39;s options into the GncOptionDB.
void gnc_register_list_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, const char *value, GncMultichoiceOptionChoices &&list)
Create a new list option and register it in the options database.
void gnc_option_db_destroy(GncOptionDB *odb)
Destruct and release a GncOptionDB.
RelativeDatePeriod
Reporting periods relative to the current date.
void gnc_register_color_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, std::string value)
Create a new color option and register it in the options database.
class GncOptionSection The upper-level classification implementation.
void gnc_register_string_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, std::string value)
Create a new string option and register it in the options database.
void gnc_register_account_list_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, const GncOptionAccountList &value)
Create a new account list option and register it in the options database.
void gnc_register_commodity_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, gnc_commodity *value)
Create a new commodity option and register it in the options database.
class GncOptionCommodityValue Commodities are stored with their namespace and mnemonic instead of the...
Used for numeric ranges and plot sizes.
GNCDateMonthFormat
This is how to format the month, as a number, an abbreviated string, or the full name.
Definition: gnc-date.h:148
bool is_dirty() const noexcept
Definition: gnc-option.cpp:306
const GncGUID * qof_entity_get_guid(gconstpointer ent)
void gnc_register_end_date_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, bool both)
Create a new end-date option and register it in the options database.
The primary C++ interface to options for books, reports, and stylesheets.
GList * gnc_option_db_commit(GncOptionDB *odb)
Write all changed ui_item values to their options.
void gnc_register_taxtable_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, GncTaxTable *value)
Create a new taxtable option and register it in the options database.
void gnc_register_font_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, std::string value)
Create a new font option and register it in the options database.
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:261
Implementation details for GncOptionDB.
void gnc_register_pixmap_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, std::string value)
Create a new pixmap option and register it in the options database.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
void gnc_register_budget_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, GncBudget *value)
Create a new budget option and register it in the options database.
void gnc_register_currency_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, gnc_commodity *value)
Create a new currency option and register it in the options database.
void qof_book_set_option(QofBook *book, KvpValue *value, GSList *path)
Save a single option value.
Definition: qofbook.cpp:1361
void gnc_register_dateformat_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, GncOptionDateFormat &&value)
Create a new date format option and register it in the options database.
void qof_book_options_delete(QofBook *book, GSList *path)
Delete the options.
Definition: qofbook.cpp:1381
gboolean gnc_date_string_to_dateformat(const gchar *format_string, QofDateFormat *format)
Converts the date format to a printable string.
void gnc_option_db_book_options(GncOptionDB *odb)
Register the standard option set for a QofBook.
The type used to store guids in C.
Definition: guid.h:75
A Query.
Definition: qofquery.cpp:74
void gnc_register_invoice_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, GncInvoice *value)
Create a new invoice option and register it in the options database.
QofDateFormat
Enum for determining a date format.
Definition: gnc-date.h:122
GncOptionAccountList gnc_account_list_from_types(QofBook *book, const GncOptionAccountTypeList &types)
Extract a list of accounts in the book having one of the GNCAccountTypes in types.
void gnc_register_counter_format_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, std::string value)
Create a new counter format option and register it in the options database.
void gnc_register_text_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, std::string value)
Create a new text option and register it in the options database.
GncOptionUIType
Used by GncOptionClassifier to indicate to dialog-options what control should be displayed for the op...
modtime is the internal date of the last modtime See libgnucash/engine/TaxTableBillTermImmutability.txt for an explanation of the following Code that handles refcount, parent, child, invisible and children is identical to that in ::GncBillTerm
void gnc_register_owner_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, const GncOwner *value, GncOwnerType type)
Create a new GncOwner option and register it in the options database.
GncOptionDB * gnc_option_db_new(void)
Create an empty option database.
void gnc_register_account_list_limited_option(GncOptionDB *db, const char *section, const char *name, const char *key, const char *doc_string, const GncOptionAccountList &value, GncOptionAccountTypeList &&allowed)
Create a new limited account list option and register it in the options database. ...