GnuCash  5.6-150-g038405b370+
gnc-option.cpp
1 /********************************************************************\
2  * gnc-option.cpp -- Application options system *
3  * Copyright (C) 2020 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 "gnc-option.hpp"
25 #include "gnc-option-impl.hpp"
26 #include "gnc-option-uitype.hpp"
27 #include "gnc-option-ui.hpp"
28 #include "gncOwner.h"
29 #include "kvp-value.hpp"
30 
31 static const char* log_module{"gnc.engine.gnc-option"};
32 
33 #include "qoflog.h"
34 
35 template <typename ValueType,
36  typename std::enable_if_t<!is_OptionClassifier_v<ValueType>,
37  int>>
38 GncOption::GncOption(const char* section, const char* name,
39  const char* key, const char* doc_string,
40  ValueType value, GncOptionUIType ui_type) :
41  m_option{std::make_unique<GncOptionVariant>(
42  std::in_place_type<GncOptionValue<ValueType>>,
43  section, name, key, doc_string, value, ui_type)}
44 {
45 }
46 
47 template <typename ValueType> ValueType
48 GncOption::get_value() const
49 {
50  return std::visit(
51  [](const auto& option)->ValueType {
52  if constexpr (is_same_decayed_v<decltype(option.get_value()),
53  ValueType>)
54  return option.get_value();
55  if constexpr (is_same_decayed_v<decltype(option),
57  {
58  if constexpr (is_same_decayed_v<ValueType,
60  return option.get_period();
61  if constexpr (std::is_same_v<ValueType, time64>)
62  return option.get_value();
63  if constexpr (std::is_same_v<ValueType, uint16_t>)
64  return option.get_period_index();
65  return ValueType{};
66  }
67  if constexpr (is_same_decayed_v<decltype(option),
69  {
70  if constexpr (std::is_same_v<ValueType, uint16_t>)
71  return option.get_index();
72  if constexpr (is_same_decayed_v<ValueType,
73  GncMultichoiceOptionIndexVec>)
74  return option.get_multiple();
75  }
76  return ValueType {};
77  }, *m_option);
78 }
79 
80 template <typename ValueType> ValueType
81 GncOption::get_default_value() const
82 {
83  return std::visit(
84  [](const auto& option)->ValueType {
85  if constexpr (is_same_decayed_v<decltype(option.get_value()),
86  ValueType>)
87  return option.get_default_value();
88  if constexpr (is_same_decayed_v<decltype(option),
90  {
91  if constexpr (is_same_decayed_v<ValueType,
93  return option.get_default_period();
94  if constexpr (std::is_same_v<ValueType, time64>)
95  return option.get_value();
96  if constexpr (std::is_same_v<ValueType, uint16_t>)
97  return option.get_default_period_index();
98  return ValueType{};
99  }
100  if constexpr
101  (is_same_decayed_v<decltype(option),
103  is_same_decayed_v<ValueType,
104  GncMultichoiceOptionIndexVec>)
105  return option.get_default_multiple();
106  return ValueType {};
107  }, *m_option);
108 
109 }
110 
111 template <typename ValueType> void
112 GncOption::set_value(ValueType value)
113 {
114  std::visit(
115  [value](auto& option) {
116  if constexpr
117  (is_same_decayed_v<decltype(option.get_value()), ValueType> ||
118  is_same_decayed_v<decltype(option), GncOptionDateFormat> ||
119  (is_same_decayed_v<decltype(option),
121  (is_same_decayed_v<ValueType, RelativeDatePeriod> ||
122  std::is_same_v<ValueType, time64> ||
123  std::is_same_v<ValueType, uint16_t>)))
124  option.set_value(value);
125  else if constexpr (is_same_decayed_v<decltype(option),
127  {
128  if constexpr (is_same_decayed_v<ValueType,
129  GncMultichoiceOptionIndexVec>)
130  option.set_multiple(value);
131  else if constexpr
132  (std::is_same_v<ValueType, uint16_t> ||
133  is_same_decayed_v<ValueType, std::string> ||
134  std::is_same_v<std::remove_cv<ValueType>, char*>)
135  option.set_value(value);
136  }
137  else
138  PWARN("No set_value handler: get_value returns %s, value_type is %s",
139  typeid(option.get_value()).name(), typeid(value).name());
140  }, *m_option);
141 }
142 
143 template <typename ValueType> void
144 GncOption::set_default_value(ValueType value)
145 {
146  std::visit(
147  [value](auto& option) {
148  if constexpr
149  (is_same_decayed_v<decltype(option.get_value()), ValueType>||
150  is_same_decayed_v<decltype(option), GncOptionDateFormat> ||
151  (is_same_decayed_v<decltype(option), GncOptionDateValue> &&
152  (is_same_decayed_v<ValueType, RelativeDatePeriod> ||
153  std::is_same_v<ValueType, time64> ||
154  std::is_same_v<ValueType, uint16_t>)))
155  option.set_default_value(value);
156  if constexpr (is_same_decayed_v<decltype(option),
158  {
159  if constexpr (is_same_decayed_v<ValueType,
160  GncMultichoiceOptionIndexVec>)
161  option.set_default_multiple(value);
162  else if constexpr
163  (std::is_same_v<ValueType, uint16_t> ||
164  is_same_decayed_v<ValueType, std::string> ||
165  std::is_same_v<std::remove_cv<ValueType>, char*>)
166  option.set_default_value(value);
167  }
168  }, *m_option);
169 }
170 void
171 GncOption::reset_default_value()
172 {
173  std::visit([](auto& option) { option.reset_default_value(); }, *m_option);
174 }
175 
176 template <typename ValueType> void
177 GncOption::get_limits(ValueType& max, ValueType& min, ValueType& step) const noexcept
178 {
179  std::visit([&max, &min, &step](const auto& option) {
180  if constexpr
181  (is_same_decayed_v<decltype(option),
183  option.get_limits(max, min, step);
184  }, *m_option);
185 }
186 
187 const std::string&
188 GncOption::get_section() const
189 {
190  return std::visit([](const auto& option)->const std::string& {
191  return option.m_section;
192  }, *m_option);
193 }
194 
195 const std::string&
196 GncOption::get_name() const
197 {
198  return std::visit([](const auto& option)->const std::string& {
199  return option.m_name;
200  }, *m_option);
201 }
202 
203 const std::string&
204 GncOption::get_key() const
205 {
206  return std::visit([](const auto& option)->const std::string& {
207  return option.m_sort_tag;
208  }, *m_option);
209 }
210 
211 const std::string&
212 GncOption::get_docstring() const
213 {
214  return std::visit([](const auto& option)->const std::string& {
215  return option.m_doc_string;
216  }, *m_option);
217 }
218 
219 void
220 GncOption::set_ui_item(GncOptionUIItemPtr&& ui_item)
221 {
222 
223  auto opt_ui_type = std::visit([](const auto& option)->GncOptionUIType {
224  return option.get_ui_type();
225  }, *m_option);
226 
227  //ui_item may be nullptr to free the old m_ui_item.
228  if (ui_item && ui_item->get_ui_type() != opt_ui_type)
229  {
230  PERR("Setting option %s:%s UI element failed, mismatched UI types.",
231  get_section().c_str(), get_name().c_str());
232  return;
233  }
234 
235  m_ui_item = std::move(ui_item);
236 }
237 
238 void
239 GncOption::set_ui_item_selectable(bool selectable) const noexcept
240 {
241  if (m_ui_item)
242  m_ui_item->set_selectable(selectable);
243 }
244 
245 const GncOptionUIType
246 GncOption::get_ui_type() const
247 {
248  return std::visit([](const auto& option)->GncOptionUIType {
249  return option.get_ui_type();
250  }, *m_option);
251 }
252 
253 GncOptionUIItem* const
254 GncOption::get_ui_item() const
255 {
256  return m_ui_item.get();
257 }
258 
259 void
260 GncOption::set_ui_item_from_option()
261 {
262  if (!m_ui_item)
263  return;
264  m_ui_item->set_ui_item_from_option(*this);
265 }
266 
267 void
268 GncOption::set_option_from_ui_item()
269 {
270  if (!m_ui_item)
271  return;
272  m_ui_item->set_option_from_ui_item(*this);
273 }
274 
275 void
276 GncOption::make_internal()
277 {
278  if (m_ui_item)
279  {
280  PERR("Option %s:%s has a UI Element, can't be INTERNAL.",
281  get_section().c_str(), get_name().c_str());
282  return;
283  }
284  std::visit([](auto& option) {
285  option.make_internal();
286  }, *m_option);
287 }
288 
289 bool
290 GncOption::is_internal()
291 {
292  return std::visit([](auto& option)->bool {
293  return option.is_internal();
294  }, *m_option);
295 }
296 
297 void
299 {
300  std::visit([](auto& option)->void {
301  option.mark_saved();
302  }, *m_option);
303 }
304 
305 bool
306 GncOption::is_dirty() const noexcept
307 {
308  return std::visit([](const auto& option)->bool {
309  return option.is_dirty();
310  }, *m_option);
311 }
312 
313 bool
314 GncOption::is_changed() const noexcept
315 {
316  return std::visit([](const auto& option)->bool {
317  return option.is_changed();
318  }, *m_option);
319 }
320 
321 bool
323 {
324  return std::visit(
325  [](const auto& option)->bool {
326  if constexpr (is_same_decayed_v<decltype(option),
328  return option.is_multiselect();
329  else
330  return false;
331  }, *m_option);
332 }
333 
334 template<typename ValueType> bool
335 GncOption::validate(ValueType value) const
336 {
337  return std::visit(
338  [value] (const auto& option) -> bool {
339  if constexpr ((is_same_decayed_v<decltype(option),
341  is_same_decayed_v<ValueType, std::string>) ||
342  (is_same_decayed_v<decltype(option),
344  is_same_decayed_v<ValueType,
345  GncMultichoiceOptionIndexVec>) ||
346  (is_same_decayed_v<decltype(option),
348  is_same_decayed_v<ValueType, gnc_commodity*>))
349  return option.validate(value);
350  else
351  return false;
352  }, *m_option);
353 }
354 
355 std::uint16_t
357 {
358  return std::visit(
359  [] (const auto& option) -> uint16_t {
360  if constexpr (is_same_decayed_v<decltype(option),
362  is_same_decayed_v<decltype(option),
364  return option.num_permissible_values();
365  else
366  return uint16_t_max;
367  }, *m_option);
368 }
369 
370 std::uint16_t
371 GncOption::permissible_value_index(const char* value) const
372 {
373  return std::visit(
374  [&value] (const auto& option) -> uint16_t {
375  if constexpr (is_same_decayed_v<decltype(option),
377  is_same_decayed_v<decltype(option),
379  return option.permissible_value_index(value);
380  else
381  return uint16_t_max;
382  }, *m_option);
383 }
384 
385 const char*
386 GncOption::permissible_value(std::uint16_t index) const
387 {
388  return std::visit([index] (const auto& option) -> const char* {
389  if constexpr (std::is_same_v<std::decay_t<decltype(option)>,
391  std::is_same_v<std::decay_t<decltype(option)>,
393  return option.permissible_value(index);
394  else
395  return "";
396  }, *m_option);
397 }
398 
399 const char*
400 GncOption::permissible_value_name(std::uint16_t index) const
401 {
402  return std::visit([index] (const auto& option) -> const char* {
403  if constexpr (std::is_same_v<std::decay_t<decltype(option)>,
405  std::is_same_v<std::decay_t<decltype(option)>,
407  return option.permissible_value_name(index);
408  else
409  return "";
410  }, *m_option);
411 }
412 
413 GList*
415 {
416  return std::visit([] (const auto& option) -> GList* {
417  if constexpr (std::is_same_v<std::decay_t<decltype(option)>,
419  return option.account_type_list();
420  else
421  return nullptr;
422  }, *m_option);
423 }
424 
425 bool
426 GncOption::is_alternate() const noexcept
427 {
428  return std::visit([](auto& option) -> bool {
429  if constexpr(is_RangeValue_v<decltype(option)>)
430  return option.is_alternate();
431  return false;
432  }, *m_option);
433 }
434 
435 void
436 GncOption::set_alternate(bool alt) noexcept
437 {
438  std::visit([alt](auto& option) {
439  if constexpr(is_RangeValue_v<decltype(option)>)
440  option.set_alternate(alt);
441  }, *m_option);
442 }
443 
444 std::string
446 {
447  if (m_option->valueless_by_exception())
448  return "Valueless Option";
449  return std::visit([&](auto& option) -> std::string {
450  return option.serialize();
451  }, *m_option);
452 }
453 
454 bool
455 GncOption::deserialize(const std::string& str)
456 {
457  return std::visit([&str](auto& option) -> bool {
458  return option.deserialize(str);
459  }, *m_option);
460 }
461 
462 std::istream&
463 GncOption::in_stream(std::istream& iss)
464 {
465  return std::visit([&iss](auto& option) -> std::istream& {
466  iss >> option;
467  return iss;
468  }, *m_option);
469 }
470 
471 /* We must instantiate all of the templates we need here because we don't expose
472  * the template implementation in the public header.
473  */
474 
475 
476 template GncOption::GncOption(const char*, const char*, const char*,
477  const char*, bool, GncOptionUIType);
478 //template GncOption::GncOption(const char*, const char*, const char*,
479 // const char*, int, GncOptionUIType);
480 template GncOption::GncOption(const char*, const char*, const char*,
481  const char*, int64_t, GncOptionUIType);
482 //template GncOption::GncOption(const char*, const char*, const char*,
483 // const char*, const char*, GncOptionUIType);
484 //template GncOption::GncOption(const char*, const char*, const char*,
485 // const char*, double, GncOptionUIType);
486 template GncOption::GncOption(const char*, const char*, const char*,
487  const char*, std::string, GncOptionUIType);
488 template GncOption::GncOption(const char*, const char*, const char*,
489  const char*, const QofQuery*, GncOptionUIType);
490 
491 template GncOption::GncOption(const char *, const char*, const char*,
492  const char *, GncOptionDateFormat,
494 
495 template bool GncOption::get_value<bool>() const;
496 template int GncOption::get_value<int>() const;
497 template int64_t GncOption::get_value<int64_t>() const;
498 template double GncOption::get_value<double>() const;
499 template uint16_t GncOption::get_value<uint16_t>() const;
500 template const char* GncOption::get_value<const char*>() const;
501 template std::string GncOption::get_value<std::string>() const;
502 template const QofInstance* GncOption::get_value<const QofInstance*>() const;
503 template const GncOwner* GncOption::get_value<const GncOwner*>() const;
504 template gnc_commodity* GncOption::get_value<gnc_commodity*>() const;
505 template const Account* GncOption::get_value<const Account*>() const;
506 template RelativeDatePeriod GncOption::get_value<RelativeDatePeriod>() const;
507 template GncOptionAccountList GncOption::get_value<GncOptionAccountList>() const;
508 template GncMultichoiceOptionIndexVec GncOption::get_value<GncMultichoiceOptionIndexVec>() const;
509 template GncOptionReportPlacementVec GncOption::get_value<GncOptionReportPlacementVec>() const;
510 template GncOptionDateFormat GncOption::get_value<GncOptionDateFormat>() const;
511 
512 template bool GncOption::get_default_value<bool>() const;
513 template int GncOption::get_default_value<int>() const;
514 template int64_t GncOption::get_default_value<int64_t>() const;
515 template double GncOption::get_default_value<double>() const;
516 template const char* GncOption::get_default_value<const char*>() const;
517 template std::string GncOption::get_default_value<std::string>() const;
518 template const QofInstance* GncOption::get_default_value<const QofInstance*>() const;
519 template gnc_commodity* GncOption::get_default_value<gnc_commodity*>() const;
520 template const Account* GncOption::get_default_value<const Account*>() const;
521 template RelativeDatePeriod GncOption::get_default_value<RelativeDatePeriod>() const;
522 template GncOptionAccountList GncOption::get_default_value<GncOptionAccountList>() const;
523 template GncMultichoiceOptionIndexVec GncOption::get_default_value<GncMultichoiceOptionIndexVec>() const;
524 template GncOptionReportPlacementVec GncOption::get_default_value<GncOptionReportPlacementVec>() const;
525 template GncOptionDateFormat GncOption::get_default_value<GncOptionDateFormat>() const;
526 
527 template void GncOption::set_value(bool);
528 template void GncOption::set_value(int);
529 template void GncOption::set_value(int64_t);
530 template void GncOption::set_value(double);
531 template void GncOption::set_value(char*);
532 template void GncOption::set_value(const char*);
533 template void GncOption::set_value(std::string);
534 template void GncOption::set_value(const QofInstance*);
535 template void GncOption::set_value(const GncOwner*);
536 template void GncOption::set_value(gnc_commodity*);
537 template void GncOption::set_value(const Account*);
538 template void GncOption::set_value(RelativeDatePeriod);
539 template void GncOption::set_value(uint16_t);
540 template void GncOption::set_value(GncOptionAccountList);
541 template void GncOption::set_value(GncMultichoiceOptionIndexVec);
542 template void GncOption::set_value(GncOptionReportPlacementVec);
543 template void GncOption::set_value(GncOptionDateFormat);
544 
545 template void GncOption::set_default_value(bool);
546 template void GncOption::set_default_value(int);
547 template void GncOption::set_default_value(int64_t);
548 template void GncOption::set_default_value(double);
549 template void GncOption::set_default_value(char*);
550 template void GncOption::set_default_value(const char*);
551 template void GncOption::set_default_value(std::string);
552 template void GncOption::set_default_value(const QofInstance*);
553 template void GncOption::set_default_value(const Account*);
554 template void GncOption::set_default_value(RelativeDatePeriod);
555 template void GncOption::set_default_value(uint16_t);
556 template void GncOption::set_default_value(GncOptionAccountList);
557 template void GncOption::set_default_value(GncMultichoiceOptionIndexVec);
558 template void GncOption::set_default_value(GncOptionReportPlacementVec);
559 template void GncOption::set_default_value(GncOptionDateFormat);
560 
561 template void GncOption::get_limits(double&, double&, double&) const noexcept;
562 template void GncOption::get_limits(int&, int&, int&) const noexcept;
563 template bool GncOption::validate(bool) const;
564 template bool GncOption::validate(int) const;
565 template bool GncOption::validate(int64_t) const;
566 template bool GncOption::validate(double) const;
567 template bool GncOption::validate(const char*) const;
568 template bool GncOption::validate(std::string) const;
569 template bool GncOption::validate(const QofInstance*) const;
570 template bool GncOption::validate(gnc_commodity*) const;
571 template bool GncOption::validate(const Account*) const;
572 template bool GncOption::validate(const QofQuery*) const;
573 template bool GncOption::validate(RelativeDatePeriod) const;
574 template bool GncOption::validate(GncMultichoiceOptionIndexVec) const;
575 template bool GncOption::validate(GncOptionReportPlacementVec) const;
576 template bool GncOption::validate(GncOptionDateFormat) const;
577 
578 template GncOption* gnc_make_option<const std::string&>(const char*,
579  const char*,
580  const char*,
581  const char*,
582  const std::string&,
584 template GncOption* gnc_make_option<bool>(const char*, const char*, const char*,
585  const char*, bool, GncOptionUIType);
586 template GncOption* gnc_make_option<int64_t>(const char*, const char*,
587  const char*, const char*, int64_t,
bool is_multiselect() const noexcept
Definition: gnc-option.cpp:322
Business Interface: Object OWNERs.
void mark_saved() noexcept
Mark the option as needing to be saved.
Definition: gnc-option.cpp:298
STRUCTS.
bool deserialize(const std::string &str)
Set the option&#39;s value from a character sequence.
Definition: gnc-option.cpp:455
uint16_t permissible_value_index(const char *value) const
Implemented only for GncOptionMultiselectValue.
Definition: gnc-option.cpp:371
OptionUITypes.
A legal date value is a pair of either a RelativeDatePeriod, the absolute flag and a time64...
STL namespace.
bool is_changed() const noexcept
Definition: gnc-option.cpp:314
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
Represents the public interface for an option.
Definition: gnc-option.hpp:136
Set one or more accounts on which to report, optionally restricted to certain account types...
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
C++ Public interface for individual options.
bool validate(ValueType value) const
Not implemented for GncOptionValue.
Definition: gnc-option.cpp:335
Multichoice options have a vector of valid options (GncMultichoiceOptionChoices) and validate the sel...
uint16_t num_permissible_values() const
Implemented only for GncOptionMultiselectValue.
Definition: gnc-option.cpp:356
std::string serialize() const
Get a string suitable for storage representing the option&#39;s value.
Definition: gnc-option.cpp:445
RelativeDatePeriod
Reporting periods relative to the current date.
Implementation templates and specializtions for GncOption values.
class GncOptionCommodityValue Commodities are stored with their namespace and mnemonic instead of the...
Used for numeric ranges and plot sizes.
bool is_dirty() const noexcept
Definition: gnc-option.cpp:306
Holds a pointer to the UI item which will control the option and an enum representing the type of the...
const char * permissible_value(uint16_t index) const
Implemented only for GncOptionMultiselectValue.
Definition: gnc-option.cpp:386
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
void get_limits(ValueType &, ValueType &, ValueType &) const noexcept
Implemented only for GncOptionNumericRange.
Definition: gnc-option.cpp:177
const char * permissible_value_name(uint16_t index) const
Implemented only for GncOptionMultiselectValue.
Definition: gnc-option.cpp:400
A Query.
Definition: qofquery.cpp:74
GncOptionUIType
Used by GncOptionClassifier to indicate to dialog-options what control should be displayed for the op...
std::istream & in_stream(std::istream &iss)
Set the option&#39;s value from an input stream.
Definition: gnc-option.cpp:463
GList * account_type_list() const noexcept
Implemented only for GncOptionAccountListValue.
Definition: gnc-option.cpp:414