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 }
711 
712 void
714  const char* section, const char* name,
715  const char* key, const char* doc_string,
716  bool value)
717 {
718  GncOption option{section, name, key, doc_string, value,
719  GncOptionUIType::BOOLEAN};
720  db->register_option(section, std::move(option));
721 }
722 
723 void
724 gnc_register_pixmap_option(GncOptionDB* db, const char* section,
725  const char* name, const char* key,
726  const char* doc_string, std::string value)
727 {
728  GncOption option{section, name, key, doc_string, value,
729  GncOptionUIType::PIXMAP};
730  db->register_option(section, std::move(option));
731 }
732 
733 void
735  const char* name, const char* key,
736  const char* doc_string,
737  const GncOptionAccountList& value)
738 {
739  GncOption option{GncOptionAccountListValue{section, name, key, doc_string,
740  GncOptionUIType::ACCOUNT_LIST, value}};
741  db->register_option(section, std::move(option));
742 }
743 
744 void
746  const char* section, const char* name,
747  const char* key,
748  const char* doc_string,
749  const GncOptionAccountList& value,
750  GncOptionAccountTypeList&& allowed)
751 {
752  try
753  {
754  GncOption option{GncOptionAccountListValue{section, name, key, doc_string,
755  GncOptionUIType::ACCOUNT_LIST, value, std::move(allowed)}};
756  db->register_option(section, std::move(option));
757  }
758  catch (const std::invalid_argument& err)
759  {
760  PWARN("Account List Limited Option, value failed validation, option not registered.");
761  }
762 }
763 
764 using AccountPair = std::pair<GncOptionAccountList&,
765  const GncOptionAccountTypeList&>;
766 static void
767 find_children(Account* account, void* data)
768 {
769  auto datapair =
770  (AccountPair*)data;
771  GncOptionAccountList& list = datapair->first;
772  const GncOptionAccountTypeList& types = datapair->second;
773  if (std::find(types.begin(), types.end(),
774  xaccAccountGetType(account)) != types.end())
775  list.push_back(*qof_entity_get_guid(account));
776 }
777 
778 GncOptionAccountList
780  const GncOptionAccountTypeList& types)
781 {
782  GncOptionAccountList list;
783  AccountPair funcdata{list, types};
784  Account* base_acct = gnc_book_get_root_account(book);
785  gnc_account_foreach_descendant(base_acct, (AccountCb)find_children,
786  &funcdata);
787  return list;
788 }
789 
790 
791 void
793  const char* section, const char* name,
794  const char* key, const char* doc_string,
795  const Account* value,
796  GncOptionAccountTypeList&& allowed)
797 {
798  try
799  {
800  GncOption option{GncOptionAccountSelValue{section, name, key, doc_string,
801  GncOptionUIType::ACCOUNT_SEL, value, std::move(allowed)}};
802  db->register_option(section, std::move(option));
803  }
804  catch (const std::invalid_argument& err)
805  {
806  PWARN("Account Sel Limited Option, value failed validation, option not registerd.");
807  }
808 }
809 
810 void
812  const char* name, const char* key,
813  const char* doc_string, const char* default_val,
814  GncMultichoiceOptionChoices&& choices)
815 {
816  std::string defval{default_val};
817  auto found{std::find_if(choices.begin(), choices.end(),
818  [&defval](auto& choice)->bool {
819  return defval == std::get<0>(choice);
820  })};
821  if (found == choices.end())
822  defval = (choices.empty() ? std::string{"None"} :
823  std::get<0>(choices.at(0)));
824  GncOption option{GncOptionMultichoiceValue{section, name, key, doc_string,
825  defval.c_str(), std::move(choices)}};
826  db->register_option(section, std::move(option));
827 }
828 
829 void
830 gnc_register_list_option(GncOptionDB* db, const char* section,
831  const char* name, const char* key,
832  const char* doc_string, const char* value,
833  GncMultichoiceOptionChoices&& list)
834 {
835  GncOption option{GncOptionMultichoiceValue{section, name, key, doc_string,
836  value, std::move(list), GncOptionUIType::LIST}};
837  db->register_option(section, std::move(option));
838 }
839 
840 /* Only balance-forecast.scm, sample-report.scm, and net-charts.scm
841  * use decimals and fractional steps and they can be worked around.
842  */
843 template <typename ValueType> void
845  const char* name, const char* key,
846  const char* doc_string, ValueType value,
847  ValueType min, ValueType max, ValueType step)
848 {
849  try
850  {
851  GncOption option{GncOptionRangeValue<ValueType>{section, name, key,
852  doc_string, value, min,
853  max, step}};
854  db->register_option(section, std::move(option));
855  }
856  catch(const std::invalid_argument& err)
857  {
858  PWARN("Number Range Option %s, option not registerd.",
859  err.what());
860  }
861 }
862 
863 void
865  const char* section, const char* name,
866  const char* key, const char* doc_string,
867  int value)
868 {
869 //65K is 10x reasonable, but it's a convenient constant.
870  GncOption option{GncOptionRangeValue<int>{section, name, key, doc_string,
871  value, 10, UINT16_MAX, 1, GncOptionUIType::PLOT_SIZE}};
872  db->register_option(section, std::move(option));
873 }
874 
875 void
876 gnc_register_query_option(GncOptionDB* db, const char* section,
877  const char* name, const QofQuery* value)
878 {
879  GncOption option{section, name, "", "", value,
880  GncOptionUIType::INTERNAL};
881  db->register_option(section, std::move(option));
882 }
883 
884 void
885 gnc_register_owner_option(GncOptionDB* db, const char* section,
886  const char* name, const char* key,
887  const char* doc_string, const GncOwner* value,
888  GncOwnerType type)
889 {
890  GncOptionUIType uitype;
891  switch (type)
892  {
893  case GNC_OWNER_CUSTOMER:
894  uitype = GncOptionUIType::CUSTOMER;
895  break;
896  case GNC_OWNER_EMPLOYEE:
897  uitype = GncOptionUIType::EMPLOYEE;
898  break;
899  case GNC_OWNER_JOB:
900  uitype = GncOptionUIType::JOB;
901  break;
902  case GNC_OWNER_VENDOR:
903  uitype = GncOptionUIType::VENDOR;
904  break;
905  default:
906  uitype = GncOptionUIType::INTERNAL;
907  };
908  GncOption option{GncOptionGncOwnerValue{section, name, key, doc_string,
909  value, uitype}};
910  db->register_option(section, std::move(option));
911 }
912 
913 void
914 gnc_register_invoice_option(GncOptionDB* db, const char* section,
915  const char* name, const char* key,
916  const char* doc_string, GncInvoice* value)
917 {
918  GncOption option{GncOptionQofInstanceValue{section, name, key, doc_string,
919  (const QofInstance*)value,
920  GncOptionUIType::INVOICE}};
921  db->register_option(section, std::move(option));
922 }
923 
924 void
925 gnc_register_taxtable_option(GncOptionDB* db, const char* section,
926  const char* name, const char* key,
927  const char* doc_string, GncTaxTable* value)
928 {
929  GncOption option{GncOptionQofInstanceValue{section, name, key, doc_string,
930  (const QofInstance*)value,
931  GncOptionUIType::TAX_TABLE}};
932  db->register_option(section, std::move(option));
933 }
934 
935 void
937  const char* name, const char* key,
938  const char* doc_string, std::string value)
939 {
940  GncOption option{section, name, key, doc_string,
941  value, GncOptionUIType::INV_REPORT};
942  db->register_option(section, std::move(option));
943 }
944 
945 void
946 gnc_register_counter_option(GncOptionDB* db, const char* section,
947  const char* name, const char* key,
948  const char* doc_string, int value)
949 {
950  GncOption option{GncOptionRangeValue<int>{section, name, key, doc_string,
951  value, 0, 999999999, 1}};
952  option.set_alternate(true);
953  db->register_option(section, std::move(option));
954 }
955 
956 void
958  const char* section, const char* name,
959  const char* key, const char* doc_string,
960  std::string value)
961 {
962  GncOption option{section, name, key, doc_string, value,
963  GncOptionUIType::STRING};
964  db->register_option(section, std::move(option));
965 }
966 
967 void
969  const char* name, const char* key,
970  const char* doc_string, GncOptionDateFormat&& value)
971 {
972  GncOption option{section, name, key, doc_string, std::move(value),
973  GncOptionUIType::DATE_FORMAT};
974  db->register_option(section, std::move(option));
975 }
976 
977 void
978 gnc_register_currency_option(GncOptionDB* db, const char* section,
979  const char* name, const char* key,
980  const char* doc_string, gnc_commodity *value)
981 {
983  section, name, key, doc_string, value, GncOptionUIType::CURRENCY
984  }};
985  db->register_option(section, std::move(option));
986 }
987 
988 void
989 gnc_register_currency_option(GncOptionDB* db, const char* section,
990  const char* name, const char* key,
991  const char* doc_string, const char* value)
992 {
993  const auto book{qof_session_get_book(gnc_get_current_session())};
994  const auto commodity_table{gnc_commodity_table_get_table(book)};
995  const auto commodity = gnc_commodity_table_lookup(commodity_table,
996  "CURRENCY",
997  value);
999  section, name, key, doc_string, commodity, GncOptionUIType::CURRENCY
1000  }};
1001  db->register_option(section, std::move(option));
1002 }
1003 
1004 void
1005 gnc_register_date_option(GncOptionDB* db, const char* section,
1006  const char* name, const char* key,
1007  const char* doc_string, time64 time,
1008  RelativeDateUI ui)
1009 {
1010  auto ui_type = ui == RelativeDateUI::BOTH ? GncOptionUIType::DATE_BOTH :
1011  ui == RelativeDateUI::RELATIVE ? GncOptionUIType::DATE_RELATIVE :
1012  GncOptionUIType::DATE_ABSOLUTE;
1013  GncOption option{GncOptionDateValue(section, name, key, doc_string,
1014  ui_type, time)};
1015  db->register_option(section, std::move(option));
1016 }
1017 
1018 void
1019 gnc_register_date_option(GncOptionDB* db, const char* section,
1020  const char* name, const char* key,
1021  const char* doc_string, RelativeDatePeriod period,
1022  RelativeDateUI ui)
1023 {
1024  auto ui_type = ui == RelativeDateUI::BOTH ? GncOptionUIType::DATE_BOTH :
1025  ui == RelativeDateUI::RELATIVE ? GncOptionUIType::DATE_RELATIVE :
1026  GncOptionUIType::DATE_ABSOLUTE;
1027  GncOption option{GncOptionDateValue(section, name, key, doc_string,
1028  ui_type, period)};
1029  db->register_option(section, std::move(option));
1030 }
1031 
1032 void
1034  const char* section, const char* name,
1035  const char* key, const char* doc_string,
1036  RelativeDatePeriodVec& period_set,
1037  bool both)
1038 {
1039  auto is_absolute = period_set.size() == 1 &&
1040  period_set.front() == RelativeDatePeriod::ABSOLUTE;
1041  auto ui_type = both ? GncOptionUIType::DATE_BOTH :
1042  is_absolute ? GncOptionUIType::DATE_ABSOLUTE : GncOptionUIType::DATE_RELATIVE;
1043  GncOption option{GncOptionDateValue(section, name, key, doc_string,
1044  ui_type, period_set)};
1045  if (is_absolute)
1046  option.set_default_value(gnc_time(nullptr));
1047  db->register_option(section, std::move(option));
1048 }
1049 
1050 
1051 static const RelativeDatePeriodVec begin_dates
1052 {
1053  RelativeDatePeriod::TODAY,
1054  RelativeDatePeriod::START_THIS_MONTH,
1055  RelativeDatePeriod::START_PREV_MONTH,
1056  RelativeDatePeriod::START_CURRENT_QUARTER,
1057  RelativeDatePeriod::START_PREV_QUARTER,
1058  RelativeDatePeriod::START_CAL_YEAR,
1059  RelativeDatePeriod::START_PREV_YEAR,
1060  RelativeDatePeriod::START_ACCOUNTING_PERIOD
1061 };
1062 
1063 void
1065  const char* name, const char* key,
1066  const char* doc_string, bool both)
1067 {
1068  auto ui_type = both ? GncOptionUIType::DATE_BOTH :
1069  GncOptionUIType::DATE_RELATIVE;
1070  GncOption option{GncOptionDateValue(section, name, key, doc_string,
1071  ui_type, begin_dates)};
1072  db->register_option(section, std::move(option));
1073 }
1074 
1075 static const RelativeDatePeriodVec end_dates
1076 {
1077  RelativeDatePeriod::TODAY,
1078  RelativeDatePeriod::END_THIS_MONTH,
1079  RelativeDatePeriod::END_PREV_MONTH,
1080  RelativeDatePeriod::END_CURRENT_QUARTER,
1081  RelativeDatePeriod::END_PREV_QUARTER,
1082  RelativeDatePeriod::END_CAL_YEAR,
1083  RelativeDatePeriod::END_PREV_YEAR,
1084  RelativeDatePeriod::END_ACCOUNTING_PERIOD
1085 };
1086 
1087 void
1089  const char* name, const char* key,
1090  const char* doc_string, bool both)
1091 {
1092  auto ui_type = both ? GncOptionUIType::DATE_BOTH :
1093  GncOptionUIType::DATE_RELATIVE;
1094  GncOption option{GncOptionDateValue(section, name, key, doc_string,
1095  ui_type, end_dates)};
1096  db->register_option(section, std::move(option));
1097 }
1098 
1099 void
1100 gnc_register_report_placement_option(GncOptionDBPtr& db,
1101  const char* section, const char* name)
1102 {
1103  /* This is a special option with it's own UI file so we have fake values to pass
1104  * to the template creation function.
1105  */
1106  GncOptionReportPlacementVec value;
1108  "no_key", "nodoc_string",
1109  value,GncOptionUIType::REPORT_PLACEMENT}};
1110  db->register_option(section, std::move(option));
1111 }
1112 
1113 void
1114 gnc_register_internal_option(GncOptionDBPtr& db,
1115  const char* section, const char* name,
1116  const std::string& value)
1117 {
1118  GncOption option{
1119  GncOptionValue<std::string>{section, name, "", "", value,
1120  GncOptionUIType::INTERNAL}};
1121  db->register_option(section, std::move(option));
1122 }
1123 
1124 void
1125 gnc_register_internal_option(GncOptionDBPtr& db,
1126  const char* section, const char* name,
1127  bool value)
1128 {
1129  GncOption option{
1130  GncOptionValue<bool>{section, name, "", "", value,
1131  GncOptionUIType::INTERNAL}};
1132  db->register_option(section, std::move(option));
1133 }
1134 
1135 GncOptionDB*
1137 {
1138  return new GncOptionDB;
1139 }
1140 
1141 void
1143 {
1144  PWARN("Direct Destroy called on GncOptionDB %" G_GUINT64_FORMAT, (uint64_t)odb);
1145 }
1146 
1147 GList*
1149 {
1150  GList* errors{};
1151  odb->foreach_section(
1152  [&errors](GncOptionSectionPtr& section){
1153  section->foreach_option(
1154  [&errors](GncOption& option) {
1155  try
1156  {
1157  option.set_option_from_ui_item();
1158  }
1159  catch (const std::invalid_argument& err)
1160  {
1161  PWARN("Option %s:%s failed to set its value %s",
1162  option.get_section().c_str(),
1163  option.get_name().c_str(), err.what());
1164  errors = g_list_prepend(errors,
1165  (void*)option.get_name().c_str());
1166  } });
1167  });
1168  if (!errors)
1169  odb->run_callbacks();
1170  return errors;
1171 }
1172 
1173 void
1175 {
1176  odb->foreach_section(
1177  [](GncOptionSectionPtr& section){
1178  section->foreach_option(
1179  [](GncOption& option) {
1180  option.set_ui_item_from_option();
1181  });
1182  });
1183 }
1184 
1185 void gnc_option_db_load(GncOptionDB* odb, QofBook* book)
1186 {
1187  odb->load_from_kvp(book);
1188 }
1189 
1190 void
1191 gnc_option_db_save(GncOptionDB* odb, QofBook* book,
1192  gboolean clear_options)
1193 {
1194  odb->save_to_kvp(book, static_cast<bool>(clear_options));
1195 }
1196 
1197 void
1199 {
1200  constexpr const char* business_section{N_("Business")};
1201  constexpr const char* counter_section{N_("Counters")};
1202  static const std::string empty_string{""};
1203 
1204 //Accounts Tab
1205 
1206  gnc_register_number_range_option<double>(odb, OPTION_SECTION_ACCOUNTS,
1207  OPTION_NAME_AUTO_READONLY_DAYS, "a",
1208  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."),
1209  0.0, 0.0, 3650.0, 1.0);
1210 
1211  gnc_register_simple_boolean_option(odb, OPTION_SECTION_ACCOUNTS,
1212  OPTION_NAME_NUM_FIELD_SOURCE, "b",
1213  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."),
1214  false);
1215  gnc_register_simple_boolean_option(odb, OPTION_SECTION_ACCOUNTS,
1216  OPTION_NAME_TRADING_ACCOUNTS, "a",
1217  N_("Check to have trading accounts used for transactions involving more than one currency or commodity."),
1218  false);
1219 
1220 //Budgeting Tab
1221 
1222  gnc_register_budget_option(odb, OPTION_SECTION_BUDGETING,
1223  OPTION_NAME_DEFAULT_BUDGET, "a",
1224  N_("Budget to be used when none has been otherwise specified."),
1225  nullptr);
1226 
1227 //Counters Tab
1228 
1229  gnc_register_counter_option(odb, counter_section,
1230  N_("Customer number"), "gncCustomera",
1231  N_("The previous customer number generated. This number will be incremented to generate the next customer number."),
1232  0);
1233  gnc_register_counter_format_option(odb, counter_section,
1234  N_("Customer number format"),
1235  "gncCustomerb",
1236  N_("The format string to use for generating customer numbers. This is a printf-style format string."),
1237  empty_string);
1238  gnc_register_counter_option(odb, counter_section,
1239  N_("Employee number"), "gncEmployeea",
1240  N_("The previous employee number generated. This number will be incremented to generate the next employee number."),
1241  0);
1242  gnc_register_counter_format_option(odb, counter_section,
1243  N_("Employee number format"),
1244  "gncEmployeeb",
1245  N_("The format string to use for generating employee numbers. This is a printf-style format string."),
1246  empty_string);
1247  gnc_register_counter_option(odb, counter_section,
1248  N_("Invoice number"), "gncInvoicea",
1249  N_("The previous invoice number generated. This number will be incremented to generate the next invoice number."),
1250  0);
1251  gnc_register_counter_format_option(odb, counter_section,
1252  N_("Invoice number format"),
1253  "gncInvoiceb",
1254  N_("The format string to use for generating invoice numbers. This is a printf-style format string."),
1255  empty_string);
1256  gnc_register_counter_option(odb, counter_section,
1257  N_("Bill number"), "gncBilla",
1258  N_("The previous bill number generated. This number will be incremented to generate the next bill number."),
1259  0);
1260  gnc_register_counter_format_option(odb, counter_section,
1261  N_("Bill number format"), "gncBillb",
1262  N_("The format string to use for generating bill numbers. This is a printf-style format string."),
1263  empty_string);
1264  gnc_register_counter_option(odb, counter_section,
1265  N_("Expense voucher number"), "gncExpVouchera",
1266  N_("The previous expense voucher number generated. This number will be incremented to generate the next voucher number."),
1267  0);
1268  gnc_register_counter_format_option(odb, counter_section,
1269  N_("Expense voucher number format"),
1270  "gncExpVoucherb",
1271  N_("The format string to use for generating expense voucher numbers. This is a printf-style format string."),
1272  empty_string);
1273  gnc_register_counter_option(odb, counter_section,
1274  N_("Job number"), "gncJoba",
1275  N_("The previous job number generated. This number will be incremented to generate the next job number."),
1276  0);
1277  gnc_register_counter_format_option(odb, counter_section,
1278  N_("Job number format"), "gncJobb",
1279  N_("The format string to use for generating job numbers. This is a printf-style format string."),
1280  empty_string);
1281  gnc_register_counter_option(odb, counter_section,
1282  N_("Order number"), "gncOrdera",
1283  N_("The previous order number generated. This number will be incremented to generate the next order number."),
1284  0);
1285  gnc_register_counter_format_option(odb, counter_section,
1286  N_("Order number format"), "gncOrderb",
1287  N_("The format string to use for generating order numbers. This is a printf-style format string."),
1288  empty_string);
1289  gnc_register_counter_option(odb, counter_section,
1290  N_("Vendor number"), "gncVendora",
1291  N_("The previous vendor number generated. This number will be incremented to generate the next vendor number."),
1292  0);
1293  gnc_register_counter_format_option(odb, counter_section,
1294  N_("Vendor number format"), "gncVendorb",
1295  N_("The format string to use for generating vendor numbers. This is a printf-style format string."),
1296  empty_string);
1297 
1298 //Business Tab
1299 
1300  gnc_register_string_option(odb, business_section, N_("Company Name"), "a",
1301  N_("The name of your business."),
1302  empty_string);
1303  gnc_register_text_option(odb, business_section, N_("Company Address"), "b1",
1304  N_("The address of your business."),
1305  empty_string);
1306  gnc_register_string_option(odb, business_section,
1307  N_("Company Contact Person"), "b2",
1308  N_("The contact person to print on invoices."),
1309  empty_string);
1310  gnc_register_string_option(odb, business_section,
1311  N_("Company Phone Number"), "c1",
1312  N_("The contact person to print on invoices."),
1313  empty_string);
1314  gnc_register_string_option(odb, business_section,
1315  N_("Company Fax Number"), "c2",
1316  N_("The fax number of your business."),
1317  empty_string);
1318  gnc_register_string_option(odb, business_section,
1319  N_("Company Email Address"), "c3",
1320  N_ ("The email address of your business."),
1321  empty_string);
1322  gnc_register_string_option(odb, business_section,
1323  N_("Company Website URL"), "c4",
1324  N_("The URL address of your website."),
1325  empty_string);
1326  gnc_register_string_option(odb, business_section, N_("Company ID"), "c5",
1327  N_("The ID for your company (eg 'Tax-ID: 00-000000)."),
1328  empty_string);
1329  gnc_register_invoice_print_report_option(odb, business_section,
1330  OPTION_NAME_DEFAULT_INVOICE_REPORT, "e1",
1331  N_("The invoice report to be used for printing."),
1332  empty_string);
1333  gnc_register_number_range_option<double>(odb, business_section,
1334  OPTION_NAME_DEFAULT_INVOICE_REPORT_TIMEOUT, "e2",
1335  N_("Length of time to change the used invoice report. A value of 0 means disabled."),
1336  0.0, 0.0, 20.0, 1.0);
1337  gnc_register_taxtable_option(odb, business_section,
1338  N_("Default Customer TaxTable"), "f1",
1339  N_("The default tax table to apply to customers."),
1340  nullptr);
1341  gnc_register_taxtable_option(odb, business_section,
1342  N_("Default Vendor TaxTable"), "f2",
1343  N_("The default tax table to apply to vendors."),
1344  nullptr);
1345 
1346  gnc_register_dateformat_option(odb, business_section,
1347  N_("Fancy Date Format"), "g",
1348  N_("The default date format used for fancy printed dates."),
1349  {QOF_DATE_FORMAT_UNSET, GNCDATE_MONTH_NUMBER, true, ""});
1350 
1351 //Tax Tab
1352 
1353  gnc_register_string_option(odb, N_("Tax"), N_("Tax Number"), "a",
1354  N_("The electronic tax number of your business"),
1355  empty_string);
1356 }
1357 const QofInstance*
1359  const char* name)
1360 {
1361  auto option{odb->find_option(section, name)};
1362  if (option)
1363  return option->get_value<const QofInstance*>();
1364  else
1365  return nullptr;
1366 }
1367 
1368 // Force creation of templates
1370  const char* section, const char* name,
1371  const char* key, const char* doc_string,
1372  int value, int min, int max, int step);
1374  const char* section, const char* name,
1375  const char* key, const char* doc_string,
1376  double value, double min,
1377  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.
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
This method will traverse all children of this accounts and their descendants, calling &#39;func&#39; on each...
Definition: Account.cpp:3195
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:279
#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:3226
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:135
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. ...