Line data Source code
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 3699 : GncOption::GncOption(const char* section, const char* name,
39 : const char* key, const char* doc_string,
40 : ValueType value, GncOptionUIType ui_type) :
41 3699 : m_option{std::make_unique<GncOptionVariant>(
42 : std::in_place_type<GncOptionValue<ValueType>>,
43 3699 : section, name, key, doc_string, value, ui_type)}
44 : {
45 3699 : }
46 :
47 : template <typename ValueType> ValueType
48 80 : GncOption::get_value() const
49 : {
50 48 : return std::visit(
51 160 : [](const auto& option)->ValueType {
52 : if constexpr (is_same_decayed_v<decltype(option.get_value()),
53 : ValueType>)
54 0 : return option.get_value();
55 : if constexpr (is_same_decayed_v<decltype(option),
56 : GncOptionDateValue>)
57 : {
58 : if constexpr (is_same_decayed_v<ValueType,
59 : RelativeDatePeriod>)
60 8 : 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 4 : return option.get_period_index();
65 0 : return ValueType{};
66 : }
67 : if constexpr (is_same_decayed_v<decltype(option),
68 : GncOptionMultichoiceValue>)
69 : {
70 : if constexpr (std::is_same_v<ValueType, uint16_t>)
71 2 : return option.get_index();
72 : if constexpr (is_same_decayed_v<ValueType,
73 : GncMultichoiceOptionIndexVec>)
74 2 : return option.get_multiple();
75 : }
76 0 : return ValueType {};
77 208 : }, *m_option);
78 : }
79 :
80 : template <typename ValueType> ValueType
81 7 : GncOption::get_default_value() const
82 : {
83 4 : return std::visit(
84 14 : [](const auto& option)->ValueType {
85 : if constexpr (is_same_decayed_v<decltype(option.get_value()),
86 : ValueType>)
87 0 : return option.get_default_value();
88 : if constexpr (is_same_decayed_v<decltype(option),
89 : GncOptionDateValue>)
90 : {
91 : if constexpr (is_same_decayed_v<ValueType,
92 : RelativeDatePeriod>)
93 0 : 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 0 : return ValueType{};
99 : }
100 : if constexpr
101 : (is_same_decayed_v<decltype(option),
102 : GncOptionMultichoiceValue> &&
103 : is_same_decayed_v<ValueType,
104 : GncMultichoiceOptionIndexVec>)
105 0 : return option.get_default_multiple();
106 0 : return ValueType {};
107 18 : }, *m_option);
108 :
109 : }
110 :
111 : template <typename ValueType> void
112 45 : GncOption::set_value(ValueType value)
113 : {
114 45 : std::visit(
115 140 : [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),
120 : GncOptionDateValue> &&
121 : (is_same_decayed_v<ValueType, RelativeDatePeriod> ||
122 : std::is_same_v<ValueType, time64> ||
123 : std::is_same_v<ValueType, uint16_t>)))
124 42 : option.set_value(value);
125 : else if constexpr (is_same_decayed_v<decltype(option),
126 : GncOptionMultichoiceValue>)
127 : {
128 : if constexpr (is_same_decayed_v<ValueType,
129 : GncMultichoiceOptionIndexVec>)
130 2 : 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 0 : option.set_value(value);
136 : }
137 : else
138 0 : PWARN("No set_value handler: get_value returns %s, value_type is %s",
139 : typeid(option.get_value()).name(), typeid(value).name());
140 45 : }, *m_option);
141 40 : }
142 :
143 : template <typename ValueType> void
144 0 : GncOption::set_default_value(ValueType value)
145 : {
146 0 : std::visit(
147 0 : [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 0 : option.set_default_value(value);
156 : if constexpr (is_same_decayed_v<decltype(option),
157 : GncOptionMultichoiceValue>)
158 : {
159 : if constexpr (is_same_decayed_v<ValueType,
160 : GncMultichoiceOptionIndexVec>)
161 0 : 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 0 : option.set_default_value(value);
167 : }
168 0 : }, *m_option);
169 0 : }
170 : void
171 0 : GncOption::reset_default_value()
172 : {
173 0 : std::visit([](auto& option) { option.reset_default_value(); }, *m_option);
174 0 : }
175 :
176 : template <typename ValueType> void
177 2 : GncOption::get_limits(ValueType& max, ValueType& min, ValueType& step) const noexcept
178 : {
179 6 : std::visit([&max, &min, &step](const auto& option) {
180 : if constexpr
181 : (is_same_decayed_v<decltype(option),
182 : GncOptionRangeValue<ValueType>>)
183 2 : option.get_limits(max, min, step);
184 2 : }, *m_option);
185 2 : }
186 :
187 : const std::string&
188 171 : GncOption::get_section() const
189 : {
190 513 : return std::visit([](const auto& option)->const std::string& {
191 171 : return option.m_section;
192 513 : }, *m_option);
193 : }
194 :
195 : const std::string&
196 122578 : GncOption::get_name() const
197 : {
198 367734 : return std::visit([](const auto& option)->const std::string& {
199 122578 : return option.m_name;
200 367734 : }, *m_option);
201 : }
202 :
203 : const std::string&
204 135905 : GncOption::get_key() const
205 : {
206 407715 : return std::visit([](const auto& option)->const std::string& {
207 135905 : return option.m_sort_tag;
208 407715 : }, *m_option);
209 : }
210 :
211 : const std::string&
212 1 : GncOption::get_docstring() const
213 : {
214 3 : return std::visit([](const auto& option)->const std::string& {
215 1 : return option.m_doc_string;
216 3 : }, *m_option);
217 : }
218 :
219 : void
220 3 : GncOption::set_ui_item(GncOptionUIItemPtr&& ui_item)
221 : {
222 :
223 6 : auto opt_ui_type = std::visit([](const auto& option)->GncOptionUIType {
224 3 : return option.get_ui_type();
225 3 : }, *m_option);
226 :
227 : //ui_item may be nullptr to free the old m_ui_item.
228 3 : if (ui_item && ui_item->get_ui_type() != opt_ui_type)
229 : {
230 0 : PERR("Setting option %s:%s UI element failed, mismatched UI types.",
231 : get_section().c_str(), get_name().c_str());
232 0 : return;
233 : }
234 :
235 3 : m_ui_item = std::move(ui_item);
236 : }
237 :
238 : void
239 0 : GncOption::set_ui_item_selectable(bool selectable) const noexcept
240 : {
241 0 : if (m_ui_item)
242 0 : m_ui_item->set_selectable(selectable);
243 0 : }
244 :
245 : const GncOptionUIType
246 37 : GncOption::get_ui_type() const
247 : {
248 111 : return std::visit([](const auto& option)->GncOptionUIType {
249 37 : return option.get_ui_type();
250 111 : }, *m_option);
251 : }
252 :
253 : GncOptionUIItem* const
254 2 : GncOption::get_ui_item() const
255 : {
256 2 : return m_ui_item.get();
257 : }
258 :
259 : void
260 1 : GncOption::set_ui_item_from_option()
261 : {
262 1 : if (!m_ui_item)
263 0 : return;
264 1 : m_ui_item->set_ui_item_from_option(*this);
265 : }
266 :
267 : void
268 1 : GncOption::set_option_from_ui_item()
269 : {
270 1 : if (!m_ui_item)
271 0 : return;
272 1 : m_ui_item->set_option_from_ui_item(*this);
273 : }
274 :
275 : void
276 40 : GncOption::make_internal()
277 : {
278 40 : if (m_ui_item)
279 : {
280 0 : PERR("Option %s:%s has a UI Element, can't be INTERNAL.",
281 : get_section().c_str(), get_name().c_str());
282 0 : return;
283 : }
284 80 : std::visit([](auto& option) {
285 40 : option.make_internal();
286 80 : }, *m_option);
287 : }
288 :
289 : bool
290 0 : GncOption::is_internal()
291 : {
292 0 : return std::visit([](auto& option)->bool {
293 0 : return option.is_internal();
294 0 : }, *m_option);
295 : }
296 :
297 : void
298 1 : GncOption::mark_saved() noexcept
299 : {
300 2 : std::visit([](auto& option)->void {
301 1 : option.mark_saved();
302 2 : }, *m_option);
303 1 : }
304 :
305 : bool
306 12 : GncOption::is_dirty() const noexcept
307 : {
308 36 : return std::visit([](const auto& option)->bool {
309 12 : return option.is_dirty();
310 24 : }, *m_option);
311 : }
312 :
313 : bool
314 2 : GncOption::is_changed() const noexcept
315 : {
316 6 : return std::visit([](const auto& option)->bool {
317 2 : return option.is_changed();
318 4 : }, *m_option);
319 : }
320 :
321 : bool
322 0 : GncOption::is_multiselect() const noexcept
323 : {
324 0 : return std::visit(
325 0 : [](const auto& option)->bool {
326 : if constexpr (is_same_decayed_v<decltype(option),
327 : GncOptionAccountListValue>)
328 0 : return option.is_multiselect();
329 : else
330 0 : return false;
331 0 : }, *m_option);
332 : }
333 :
334 : template<typename ValueType> bool
335 7 : GncOption::validate(ValueType value) const
336 : {
337 9 : return std::visit(
338 21 : [value] (const auto& option) -> bool {
339 : if constexpr ((is_same_decayed_v<decltype(option),
340 : GncOptionMultichoiceValue> &&
341 : is_same_decayed_v<ValueType, std::string>) ||
342 : (is_same_decayed_v<decltype(option),
343 : GncOptionMultichoiceValue> &&
344 : is_same_decayed_v<ValueType,
345 : GncMultichoiceOptionIndexVec>) ||
346 : (is_same_decayed_v<decltype(option),
347 : GncOptionCommodityValue> &&
348 : is_same_decayed_v<ValueType, gnc_commodity*>))
349 7 : return option.validate(value);
350 : else
351 0 : return false;
352 21 : }, *m_option);
353 : }
354 :
355 : std::uint16_t
356 33 : GncOption::num_permissible_values() const
357 : {
358 33 : return std::visit(
359 66 : [] (const auto& option) -> uint16_t {
360 : if constexpr (is_same_decayed_v<decltype(option),
361 : GncOptionMultichoiceValue> ||
362 : is_same_decayed_v<decltype(option),
363 : GncOptionDateValue>)
364 33 : return option.num_permissible_values();
365 : else
366 0 : return uint16_t_max;
367 99 : }, *m_option);
368 : }
369 :
370 : std::uint16_t
371 2 : GncOption::permissible_value_index(const char* value) const
372 : {
373 4 : return std::visit(
374 6 : [&value] (const auto& option) -> uint16_t {
375 : if constexpr (is_same_decayed_v<decltype(option),
376 : GncOptionMultichoiceValue> ||
377 : is_same_decayed_v<decltype(option),
378 : GncOptionDateValue>)
379 2 : return option.permissible_value_index(value);
380 : else
381 0 : return uint16_t_max;
382 6 : }, *m_option);
383 : }
384 :
385 : const char*
386 42 : GncOption::permissible_value(std::uint16_t index) const
387 : {
388 125 : return std::visit([index] (const auto& option) -> const char* {
389 : if constexpr (std::is_same_v<std::decay_t<decltype(option)>,
390 : GncOptionMultichoiceValue> ||
391 : std::is_same_v<std::decay_t<decltype(option)>,
392 : GncOptionDateValue>)
393 42 : return option.permissible_value(index);
394 : else
395 0 : return "";
396 124 : }, *m_option);
397 : }
398 :
399 : const char*
400 2 : GncOption::permissible_value_name(std::uint16_t index) const
401 : {
402 5 : return std::visit([index] (const auto& option) -> const char* {
403 : if constexpr (std::is_same_v<std::decay_t<decltype(option)>,
404 : GncOptionMultichoiceValue> ||
405 : std::is_same_v<std::decay_t<decltype(option)>,
406 : GncOptionDateValue>)
407 2 : return option.permissible_value_name(index);
408 : else
409 0 : return "";
410 4 : }, *m_option);
411 : }
412 :
413 : GList*
414 0 : GncOption::account_type_list() const noexcept
415 : {
416 0 : return std::visit([] (const auto& option) -> GList* {
417 : if constexpr (std::is_same_v<std::decay_t<decltype(option)>,
418 : GncOptionAccountListValue>)
419 0 : return option.account_type_list();
420 : else
421 0 : return nullptr;
422 0 : }, *m_option);
423 : }
424 :
425 : bool
426 0 : GncOption::is_alternate() const noexcept
427 : {
428 0 : return std::visit([](auto& option) -> bool {
429 : if constexpr(is_RangeValue_v<decltype(option)>)
430 0 : return option.is_alternate();
431 0 : return false;
432 0 : }, *m_option);
433 : }
434 :
435 : void
436 0 : GncOption::set_alternate(bool alt) noexcept
437 : {
438 0 : std::visit([alt](auto& option) {
439 : if constexpr(is_RangeValue_v<decltype(option)>)
440 0 : option.set_alternate(alt);
441 0 : }, *m_option);
442 0 : }
443 :
444 : std::string
445 46 : GncOption::serialize() const
446 : {
447 46 : if (m_option->valueless_by_exception())
448 0 : return "Valueless Option";
449 92 : return std::visit([&](auto& option) -> std::string {
450 46 : return option.serialize();
451 46 : }, *m_option);
452 : }
453 :
454 : bool
455 0 : GncOption::deserialize(const std::string& str)
456 : {
457 0 : return std::visit([&str](auto& option) -> bool {
458 0 : return option.deserialize(str);
459 0 : }, *m_option);
460 : }
461 :
462 : std::istream&
463 33 : GncOption::in_stream(std::istream& iss)
464 : {
465 94 : return std::visit([&iss](auto& option) -> std::istream& {
466 33 : iss >> option;
467 28 : return iss;
468 89 : }, *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,
493 : GncOptionUIType);
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&,
583 : GncOptionUIType);
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,
588 : GncOptionUIType);
|