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