GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-option-impl.hpp
Go to the documentation of this file.
1/********************************************************************\
2 * gnc-option-impl.hpp -- Application options system *
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
33#ifndef GNC_OPTION_IMPL_HPP_
34#define GNC_OPTION_IMPL_HPP_
35
36#include "gnc-option.hpp"
37
38#include <config.h>
39#include "qof.h"
40#include "Account.h"
41#include "gnc-budget.h"
42#include "gnc-commodity.h"
43#include "gnc-datetime.hpp"
44#include <algorithm>
45#include <string>
46#include <utility>
47#include <vector>
48#include <exception>
49#include <functional>
50#include <variant>
51#include <iostream>
52#include <limits>
53#include <cstdint>
54
55#include "gnc-option-uitype.hpp"
56
57
58#ifndef SWIG
59size_t constexpr classifier_size_max{50};
60size_t constexpr sort_tag_size_max{10};
61#endif
62
70{
71 std::string m_section;
72 std::string m_name;
73 std::string m_sort_tag;
74// std::type_info m_kvp_type;
75 std::string m_doc_string;
76};
77
78
79#ifndef SWIG
80auto constexpr uint16_t_max = std::numeric_limits<uint16_t>::max();
81#endif
82
86template <typename ValueType>
88{
89public:
90 GncOptionValue(const char* section, const char* name,
91 const char* key, const char* doc_string,
92 ValueType value,
93 GncOptionUIType ui_type = GncOptionUIType::INTERNAL) :
94 OptionClassifier{section, name, key, doc_string},
95 m_ui_type(ui_type), m_value{value}, m_default_value{value} { }
96 GncOptionValue(const GncOptionValue&) = default;
97 GncOptionValue(GncOptionValue&&) = default;
98 GncOptionValue& operator=(const GncOptionValue&) = default;
99 GncOptionValue& operator=(GncOptionValue&&) = default;
100 ~GncOptionValue() = default;
101 ValueType get_value() const { return m_value; }
102 ValueType get_default_value() const { return m_default_value; }
103 void set_value(ValueType new_value);
104 void set_default_value(ValueType new_value);
105 void reset_default_value();
106 void mark_saved() noexcept { m_dirty = false; }
107 bool is_dirty() const noexcept { return m_dirty; }
108 bool is_changed() const noexcept { return m_value != m_default_value; }
109 GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
110 void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
111 bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
112 std::string serialize() const noexcept;
113 bool deserialize(const std::string& str) noexcept;
114private:
115 GncOptionUIType m_ui_type;
116 ValueType m_value;
117 ValueType m_default_value;
118 bool m_dirty{false};
119};
120
121
129{
130 void operator()(GncOwner* o) {
131 g_free(o);
132 }
133};
134
135using GncOwnerPtr = std::unique_ptr<GncOwner, GncOwnerDeleter>;
136
138public:
140 const char* section, const char* name,
141 const char* key, const char* doc_string,
142 const GncOwner* value,
143 GncOptionUIType ui_type = GncOptionUIType::INTERNAL);
146 ~GncOptionGncOwnerValue() = default;
147 const GncOwner* get_value() const;
148 const GncOwner* get_default_value() const;
149 void set_value(const GncOwner* new_value);
150 void set_default_value(const GncOwner* new_value);
151 void reset_default_value();
152 void mark_saved() noexcept { m_dirty = false; }
153 bool is_dirty() const noexcept { return m_dirty; }
154 bool is_changed() const noexcept;
155 GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
156 void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
157 bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
158 std::string serialize() const noexcept;
159 bool deserialize(const std::string& str) noexcept;
160private:
161 GncOptionUIType m_ui_type;
162 GncOwnerPtr m_value;
163 GncOwnerPtr m_default_value;
164 bool m_dirty{false};
165};
166
172using GncItem = std::pair<QofIdTypeConst, GncGUID>;
173
175public:
177 const char* section, const char* name,
178 const char* key, const char* doc_string,
179 const QofInstance* value,
180 GncOptionUIType ui_type = GncOptionUIType::INTERNAL);
184 ~GncOptionQofInstanceValue() = default;
185 const QofInstance* get_value() const;
186 const QofInstance* get_default_value() const;
187 GncItem get_item() const { return m_value; }
188 GncItem get_default_item() const { return m_default_value; }
189 void set_value(const QofInstance* new_value);
190 void set_default_value(const QofInstance* new_value);
191 void reset_default_value();
192 void mark_saved() noexcept { m_dirty = false; }
193 bool is_dirty() const noexcept { return m_dirty; }
194 bool is_changed() const noexcept;
195 GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
196 void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
197 bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
198 std::string serialize() const noexcept;
199 bool deserialize(const std::string& str) noexcept;
200private:
201 GncOptionUIType m_ui_type;
202 GncItem m_value;
203 GncItem m_default_value;
204 bool m_dirty{false};
205};
206
216{
217public:
218 GncOptionCommodityValue() = delete;
219 GncOptionCommodityValue(const char* section, const char* name,
220 const char* key, const char* doc_string,
221 gnc_commodity* value,
222 GncOptionUIType ui_type = GncOptionUIType::COMMODITY) :
223 OptionClassifier{section, name, key, doc_string},
224 m_ui_type{ui_type}, m_is_currency{ui_type == GncOptionUIType::CURRENCY},
225 m_namespace{gnc_commodity_get_namespace(value)},
226 m_mnemonic{gnc_commodity_get_mnemonic(value)},
227 m_default_namespace{gnc_commodity_get_namespace(value)},
228 m_default_mnemonic{gnc_commodity_get_mnemonic(value)}
229 {
230 if (!validate(value))
231 throw std::invalid_argument("Attempt to create GncOptionCommodityValue with currency UIType and non-currency value.");
232 }
235 GncOptionCommodityValue& operator=(const GncOptionCommodityValue&) = default;
236 GncOptionCommodityValue& operator=(GncOptionCommodityValue&&) = default;
237 gnc_commodity* get_value() const;
238 gnc_commodity* get_default_value() const;
239 bool validate(gnc_commodity*) const noexcept;
240 void set_value(gnc_commodity* value);
241 void set_default_value(gnc_commodity* value);
242 void reset_default_value();
243 void mark_saved() noexcept { m_dirty = false; }
244 bool is_dirty() const noexcept { return m_dirty; }
245 bool is_changed() const noexcept;
246 GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
247 void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
248 bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
249 std::string serialize() const noexcept;
250 bool deserialize(const std::string& str) noexcept;
251private:
252 GncOptionUIType m_ui_type;
253 bool m_is_currency;
254 std::string m_namespace;
255 std::string m_mnemonic;
256 std::string m_default_namespace;
257 std::string m_default_mnemonic;
258 bool m_dirty{false};
259};
260
261QofInstance* qof_instance_from_string(const std::string& str,
262 GncOptionUIType type);
263QofInstance* qof_instance_from_guid(GncGUID*, GncOptionUIType type);
264std::string qof_instance_to_string(const QofInstance* inst);
265
266template <typename T>
268{
269 static constexpr bool value =
270 std::is_same_v<std::decay_t<T>, GncOptionGncOwnerValue>;
271};
272
273template <typename T> inline constexpr bool
274is_GncOwnerValue_v = is_GncOwnerValue<T>::value;
275
276template <typename T>
278{
279 static constexpr bool value =
280 std::is_same_v<std::decay_t<T>, GncOptionQofInstanceValue>;
281};
282
283template <typename T> inline constexpr bool
284is_QofInstanceValue_v = is_QofInstanceValue<T>::value;
285
286template <typename T>
288{
289 static constexpr bool value =
290 std::is_same_v<std::decay_t<T>, GncOptionValue<const QofQuery*>>;
291};
292
293template <typename T> inline constexpr bool
294is_QofQueryValue_v = is_QofQueryValue<T>::value;
295
296/* These will work when m_value is a built-in class; GnuCash class and container
297 * values will need specialization unless they happen to define operators << and
298 * >>.
299 * Note that SWIG 3.0.12 chokes on elaborate enable_if so just hide the
300 * following templates from SWIG. (Ignoring doesn't work because SWIG still has
301 * to parse the templates to figure out the symbols.
302 */
303#ifndef SWIG
304template<class OptType,
305 typename std::enable_if_t<is_OptionClassifier_v<OptType> &&
306 ! (is_QofInstanceValue_v<OptType> ||
307 is_RangeValue_v<OptType>), int> = 0>
308std::ostream& operator<<(std::ostream& oss, const OptType& opt)
309{
310 oss << opt.get_value();
311 return oss;
312}
313
314template<> inline std::ostream&
315operator<< <GncOptionValue<bool>>(std::ostream& oss,
316 const GncOptionValue<bool>& opt)
317{
318 oss << (opt.get_value() ? "#t" : "#f");
319 return oss;
320}
321
322inline std::ostream&
323operator<< (std::ostream& oss, const GncOptionCommodityValue& opt)
324{
325 oss << opt.serialize();
326 return oss;
327}
328
329template<class OptType,
330 typename std::enable_if_t<is_QofInstanceValue_v<OptType>, int> = 0>
331inline std::ostream&
332operator<< (std::ostream& oss, const OptType& opt)
333{
334 auto value = opt.get_value();
335 oss << qof_instance_to_string(value);
336 return oss;
337}
338
339template<class OptType,
340 typename std::enable_if_t<is_OptionClassifier_v<OptType> &&
341 !(is_QofInstanceValue_v<OptType> ||
342 is_RangeValue_v<OptType>), int> = 0>
343std::istream& operator>>(std::istream& iss, OptType& opt)
344{
345 if constexpr (std::is_same_v<std::decay_t<decltype(opt.get_value())>, const _gncOwner*> ||
346 std::is_same_v<std::decay_t<decltype(opt.get_value())>, const _QofQuery*> ||
347 std::is_same_v<std::decay_t<decltype(opt.get_value())>, GncOptionDateFormat>)
348 return iss;
349 else
350 {
351 std::decay_t<decltype(opt.get_value())> value;
352 iss >> value;
353 opt.set_value(value);
354 return iss;
355 }
356}
357
358std::istream& operator>> (std::istream& iss, GncOptionCommodityValue& opt);
359
360template<class OptType,
361 typename std::enable_if_t<is_QofInstanceValue_v<OptType>, int> = 0>
362std::istream&
363operator>> (std::istream& iss, OptType& opt)
364{
365 std::string instr;
366 iss >> instr;
367 opt.set_value(qof_instance_from_string(instr, opt.get_ui_type()));
368 return iss;
369}
370
371template<> inline std::istream&
372operator>> <GncOptionValue<bool>>(std::istream& iss,
374{
375 std::string instr;
376 iss >> instr;
377 opt.set_value(instr == "#t" ? true : false);
378 return iss;
379}
380
381template<> inline std::istream&
382operator>> <GncOptionValue<GncOptionReportPlacementVec>>(std::istream& iss,
384{
385 uint32_t id, wide, high;
386 iss >> id >> wide >> high;
387 opt.set_value(GncOptionReportPlacementVec{{id, wide, high}});
388 return iss;
389}
390#endif // SWIG
391
396template <typename ValueType>
398{
399public:
400 GncOptionRangeValue(const char* section, const char* name,
401 const char* key, const char* doc_string,
402 ValueType value, ValueType min,
403 ValueType max, ValueType step) :
404 GncOptionRangeValue<ValueType>{section, name, key, doc_string, value, min,
405 max, step, GncOptionUIType::NUMBER_RANGE} {}
406 GncOptionRangeValue(const char* section, const char* name,
407 const char* key, const char* doc_string,
408 ValueType value, ValueType min,
409 ValueType max, ValueType step, GncOptionUIType ui) :
410 OptionClassifier{section, name, key, doc_string}, m_ui_type{ui},
411 m_value{value >= min && value <= max ? value : min},
412 m_default_value{value >= min && value <= max ? value : min},
413 m_min{min}, m_max{max}, m_step{step} {
414 if constexpr(is_same_decayed_v<ValueType, int>)
415 set_alternate(true);}
420 ValueType get_value() const { return m_value; }
421 ValueType get_default_value() const { return m_default_value; }
422 bool validate(ValueType value) { return value >= m_min && value <= m_max; }
423 void set_value(ValueType value)
424 {
425 if (this->validate(value))
426 {
427 m_value = value;
428 m_dirty = true;
429 }
430 else
431 throw std::invalid_argument("Validation failed, value not set.");
432 }
433 void set_default_value(ValueType value)
434 {
435 if (this->validate(value))
436 m_value = m_default_value = value;
437 else
438 throw std::invalid_argument("Validation failed, value not set.");
439 }
440 void get_limits(ValueType& upper, ValueType& lower, ValueType& step) const noexcept
441 {
442 upper = m_max;
443 lower = m_min;
444 step = m_step;
445 }
446 void reset_default_value() { m_value = m_default_value; }
447 void mark_saved() noexcept { m_dirty = false; }
448 bool is_dirty() const noexcept { return m_dirty; }
449 bool is_changed() const noexcept { return m_value != m_default_value; }
450 GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
451 void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
452 bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
453 bool is_alternate() const noexcept { return m_alternate; }
454 void set_alternate(bool value) noexcept { m_alternate = value; }
455 std::string serialize() const noexcept;
456 bool deserialize(const std::string& str) noexcept;
457private:
458 GncOptionUIType m_ui_type = GncOptionUIType::NUMBER_RANGE;
459 ValueType m_value;
460 ValueType m_default_value;
461 ValueType m_min;
462 ValueType m_max;
463 ValueType m_step;
464 bool m_alternate{false};
465 bool m_dirty{false};
466};
467
468template<class OptType,
469 typename std::enable_if_t<is_RangeValue_v<OptType>, int> = 0>
470inline std::ostream&
471operator<< (std::ostream& oss, const OptType& opt)
472{
473 if (opt.get_ui_type() == GncOptionUIType::PLOT_SIZE)
474 oss << (opt.is_alternate() ? "pixels" : "percent") << " ";
475 oss << opt.get_value();
476 return oss;
477}
478
479template<class OptType,
480 typename std::enable_if_t<is_RangeValue_v<OptType>, int> = 0>
481inline std::istream&
482operator>> (std::istream& iss, OptType& opt)
483{
484 if (opt.get_ui_type() == GncOptionUIType::PLOT_SIZE)
485 {
486 std::string alt;
487 iss >> alt;
488 opt.set_alternate(strncmp(alt.c_str(), "percent",
489 strlen("percent")) == 0);
490 }
491 if constexpr (std::is_same_v<std::decay_t<OptType>,
493 {
494 double d;
495 iss >> d;
496 opt.set_value(d);
497 }
498 else
499 {
500 int i;
501 iss >> i;
502 opt.set_value(i);
503 }
504 return iss;
505}
506
507using GncMultichoiceOptionEntry = std::tuple<const std::string,
508 const std::string,
509 GncOptionMultichoiceKeyType>;
510using GncMultichoiceOptionIndexVec = std::vector<uint16_t>;
511using GncMultichoiceOptionChoices = std::vector<GncMultichoiceOptionEntry>;
512
529{
530public:
531 GncOptionMultichoiceValue(const char* section, const char* name,
532 const char* key, const char* doc_string,
533 const char* value,
534 GncMultichoiceOptionChoices&& choices,
535 GncOptionUIType ui_type = GncOptionUIType::MULTICHOICE) :
536 OptionClassifier{section, name, key, doc_string},
537 m_ui_type{ui_type},
538 m_value{}, m_default_value{}, m_choices{std::move(choices)}
539 {
540 if (value)
541 {
542 if (auto index = find_key(value);
543 index != uint16_t_max)
544 {
545 m_value.push_back(index);
546 m_default_value.push_back(index);
547 }
548 }
549 }
550
551 GncOptionMultichoiceValue(const char* section, const char* name,
552 const char* key, const char* doc_string,
553 uint16_t index,
554 GncMultichoiceOptionChoices&& choices,
555 GncOptionUIType ui_type = GncOptionUIType::MULTICHOICE) :
556 OptionClassifier{section, name, key, doc_string},
557 m_ui_type{ui_type},
558 m_value{}, m_default_value{}, m_choices{std::move(choices)}
559 {
560 if (index < m_choices.size())
561 {
562 m_value.push_back(index);
563 m_default_value.push_back(index);
564 }
565 }
566
567 GncOptionMultichoiceValue(const char* section, const char* name,
568 const char* key, const char* doc_string,
569 GncMultichoiceOptionIndexVec&& indices,
570 GncMultichoiceOptionChoices&& choices,
571 GncOptionUIType ui_type = GncOptionUIType::LIST) :
572 OptionClassifier{section, name, key, doc_string},
573 m_ui_type{ui_type},
574 m_value{indices}, m_default_value{std::move(indices)},
575 m_choices{std::move(choices)} {}
578 GncOptionMultichoiceValue& operator=(const GncOptionMultichoiceValue&) = default;
580
581 const std::string& get_value() const
582 {
583 auto vec{m_value.size() > 0 ? m_value : m_default_value};
584 if (vec.size() == 0)
585 return c_empty_string;
586 if (vec.size() == 1)
587 return std::get<0>(m_choices.at(vec[0]));
588 else
589 return c_list_string;
590
591 }
592 const std::string& get_default_value() const
593 {
594 if (m_default_value.size() == 1)
595 return std::get<0>(m_choices.at(m_default_value[0]));
596 else if (m_default_value.size() == 0)
597 return c_empty_string;
598 else
599 return c_list_string;
600 }
601
602 uint16_t get_index() const
603 {
604 if (m_value.size() > 0)
605 return m_value[0];
606 if (m_default_value.size() > 0)
607 return m_default_value[0];
608 return 0;
609 }
610 const GncMultichoiceOptionIndexVec& get_multiple() const noexcept
611 {
612 return m_value;
613 }
614 const GncMultichoiceOptionIndexVec& get_default_multiple() const noexcept
615 {
616 return m_default_value;
617 }
618 bool validate(const std::string& value) const noexcept
619 {
620 auto index = find_key(value);
621 return index != uint16_t_max;
622
623 }
624 bool validate(const GncMultichoiceOptionIndexVec& indexes) const noexcept
625 {
626 for (auto index : indexes)
627 if (index >= m_choices.size())
628 return false;
629 return true;
630
631 }
632 void set_value(const std::string& value)
633 {
634 auto index = find_key(value);
635 if (index != uint16_t_max)
636 {
637 m_value.clear();
638 m_value.push_back(index);
639 m_dirty = true;
640 }
641 else
642 throw std::invalid_argument("Value not a valid choice.");
643
644 }
645 void set_value(uint16_t index)
646 {
647 if (index < m_choices.size())
648 {
649 m_value.clear();
650 m_value.push_back(index);
651 m_dirty = true;
652 }
653 else
654 throw std::invalid_argument("Value not a valid choice.");
655
656 }
657 void set_default_value(const std::string& value)
658 {
659 auto index = find_key(value);
660 if (index != uint16_t_max)
661 {
662 m_value.clear();
663 m_value.push_back(index);
664 m_default_value.clear();
665 m_default_value.push_back(index);
666 }
667 else
668 throw std::invalid_argument("Value not a valid choice.");
669
670 }
671 void set_default_value(uint16_t index)
672 {
673 if (index < m_choices.size())
674 {
675 m_value.clear();
676 m_value.push_back(index);
677 m_default_value.clear();
678 m_default_value.push_back(index);
679 }
680 else
681 throw std::invalid_argument("Value not a valid choice.");
682
683 }
684 void set_multiple(const GncMultichoiceOptionIndexVec& indexes)
685 {
686 if (validate(indexes))
687 m_value = indexes;
688 else
689 throw std::invalid_argument("One of the supplied indexes was out of range.");
690 }
691 void set_default_multiple(const GncMultichoiceOptionIndexVec& indexes)
692 {
693 if (validate(indexes))
694 m_value = m_default_value = indexes;
695 else
696 throw std::invalid_argument("One of the supplied indexes was out of range.");
697 }
698 uint16_t num_permissible_values() const noexcept
699 {
700 return m_choices.size();
701 }
702 uint16_t permissible_value_index(const char* key) const noexcept
703 {
704 return find_key(key);
705 }
706 const char* permissible_value(uint16_t index) const
707 {
708 return std::get<0>(m_choices.at(index)).c_str();
709 }
710 const char* permissible_value_name(uint16_t index) const
711 {
712 return std::get<1>(m_choices.at(index)).c_str();
713 }
714 void reset_default_value() { m_value = m_default_value; }
715 void mark_saved() noexcept { m_dirty = false; }
716 bool is_dirty() const noexcept { return m_dirty; }
717 bool is_changed() const noexcept { return m_value != m_default_value; }
718 GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
719 void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
720 bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
721 GncOptionMultichoiceKeyType get_keytype(unsigned i) const { return std::get<2>(m_choices.at(i)); }
722 std::string serialize() const noexcept;
723 bool deserialize(const std::string& str) noexcept;
724private:
725 uint16_t find_key (const std::string& key) const noexcept
726 {
727 auto iter = std::find_if(m_choices.begin(), m_choices.end(),
728 [key](auto choice) {
729 return std::get<0>(choice) == key; });
730 if (iter != m_choices.end())
731 return iter - m_choices.begin();
732 else
733 return uint16_t_max;
734
735 }
736 GncOptionUIType m_ui_type;
737 GncMultichoiceOptionIndexVec m_value;
738 GncMultichoiceOptionIndexVec m_default_value;
739 GncMultichoiceOptionChoices m_choices;
740 bool m_dirty{false};
741 static const std::string c_empty_string;
742 static const std::string c_list_string;
743};
744
745template<> inline std::ostream&
746operator<< <GncOptionMultichoiceValue>(std::ostream& oss,
747 const GncOptionMultichoiceValue& opt)
748{
749 auto vec{opt.get_multiple()};
750 bool first{true};
751 for (auto index : vec)
752 {
753 if (first)
754 first = false;
755 else
756 oss << " ";
757 oss << opt.permissible_value(index);
758 }
759 return oss;
760}
761
762template<> inline std::istream&
763operator>> <GncOptionMultichoiceValue>(std::istream& iss,
765{
766 GncMultichoiceOptionIndexVec values;
767 while (true)
768 {
769 std::string str;
770 std::getline(iss, str, ' ');
771 if (!str.empty())
772 {
773 auto index = opt.permissible_value_index(str.c_str());
774 if (index != uint16_t_max)
775 values.push_back(index);
776 else
777 {
778 std::string err = str + " is not one of ";
779 err += opt.m_name;
780 err += "'s permissible values.";
781 throw std::invalid_argument(err);
782 }
783 }
784 else
785 break;
786 }
787 opt.set_multiple(values);
788 iss.clear();
789 return iss;
790}
791
792
793using GncOptionAccountList = std::vector<GncGUID>;
794
795using GncOptionAccountTypeList = std::vector<GNCAccountType>;
796
815{
816public:
817 GncOptionAccountListValue(const char* section, const char* name,
818 const char* key, const char* doc_string,
819 GncOptionUIType ui_type, bool multi=true) :
820 OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
821 m_value{}, m_default_value{}, m_allowed{}, m_multiselect{multi} {}
822
823 GncOptionAccountListValue(const char* section, const char* name,
824 const char* key, const char* doc_string,
825 GncOptionUIType ui_type,
826 const GncOptionAccountList& value, bool multi=true) :
827 OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
828 m_value{value}, m_default_value{std::move(value)}, m_allowed{},
829 m_multiselect{multi} {}
830 GncOptionAccountListValue(const char* section, const char* name,
831 const char* key, const char* doc_string,
832 GncOptionUIType ui_type,
833 GncOptionAccountTypeList&& allowed, bool multi=true) :
834 OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
835 m_value{}, m_default_value{}, m_allowed{std::move(allowed)},
836 m_multiselect{multi} {}
837 GncOptionAccountListValue(const char* section, const char* name,
838 const char* key, const char* doc_string,
839 GncOptionUIType ui_type,
840 const GncOptionAccountList& value,
841 GncOptionAccountTypeList&& allowed, bool multi=true) :
842 OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
843 m_value{}, m_default_value{}, m_allowed{std::move(allowed)},
844 m_multiselect{multi} {
845 if (!validate(value))
846 throw std::invalid_argument("Supplied Value not in allowed set.");
847 m_value = value;
848 m_default_value = std::move(value);
849 }
850
851 /* These aren't const& because if m_default_value hasn't been set
852 * get_default_value finds the first account that matches the allowed types
853 * and returns a GncOptionAccountList containing it. That's a stack variable
854 * and must be returned by value.
855 */
856 GncOptionAccountList get_value() const;
857 GncOptionAccountList get_default_value() const;
858 bool validate (const GncOptionAccountList& values) const;
859 void set_value (GncOptionAccountList values) {
860 if (validate(values))
861 {
862 //throw!
863 m_value = values;
864 m_dirty = true;
865 }
866 }
867 void set_default_value (GncOptionAccountList values) {
868 if (validate(values))
869 //throw!
870 m_value = m_default_value = values;
871 }
872 GList* account_type_list() const noexcept;
873 void reset_default_value() { m_value = m_default_value; }
874 void mark_saved() noexcept { m_dirty = false; }
875 bool is_dirty() const noexcept { return m_dirty; }
876 bool is_changed() const noexcept;
877 GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
878 void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
879 bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
880 bool is_multiselect() const noexcept { return m_multiselect; }
881 std::string serialize() const noexcept;
882 bool deserialize(const std::string& str) noexcept;
883private:
884 GncOptionUIType m_ui_type;
885 GncOptionAccountList m_value;
886 GncOptionAccountList m_default_value;
887 GncOptionAccountTypeList m_allowed;
888 bool m_multiselect;
889 bool m_dirty{false};
890};
891
892template<> inline std::ostream&
893operator<< <GncOptionAccountListValue>(std::ostream& oss,
894 const GncOptionAccountListValue& opt)
895{
896 auto values{opt.get_value()};
897 bool first = true;
898 for (auto value : values)
899 {
900 if (first)
901 first = false;
902 else
903 oss << " ";
904 char strbuff[GUID_ENCODING_LENGTH+1];
905 guid_to_string_buff (&value, strbuff);
906 oss << strbuff;
907 }
908 return oss;
909}
910
911template<> inline std::istream&
912operator>> <GncOptionAccountListValue>(std::istream& iss,
914{
915 GncOptionAccountList values;
916 while (true)
917 {
918 std::string str;
919 std::getline(iss, str, ' ');
920 if (!str.empty())
921 {
922 auto guid{qof_entity_get_guid(qof_instance_from_string(str, opt.get_ui_type()))};
923 values.push_back(*guid);
924 }
925 else
926 break;
927 }
928 opt.set_value(values);
929 iss.clear();
930 return iss;
931}
932
933/* @class GncOptionAccountSelValue
934 * Like GncOptionAccountListValue but contains only a single account.
935 */
936
938{
939public:
940 GncOptionAccountSelValue(const char* section, const char* name,
941 const char* key, const char* doc_string,
942 GncOptionUIType ui_type) :
943 OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
944 m_value{*guid_null()}, m_default_value{*guid_null()}, m_allowed{} {}
945
946 GncOptionAccountSelValue(const char* section, const char* name,
947 const char* key, const char* doc_string,
948 GncOptionUIType ui_type,
949 const Account* value) :
950 OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
951 m_value{*qof_entity_get_guid(value)},
952 m_default_value{*qof_entity_get_guid(value)}, m_allowed{} {}
953 GncOptionAccountSelValue(const char* section, const char* name,
954 const char* key, const char* doc_string,
955 GncOptionUIType ui_type,
956 GncOptionAccountTypeList&& allowed) :
957 OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
958 m_value{*guid_null()}, m_default_value{*guid_null()},
959 m_allowed{std::move(allowed)} {}
960 GncOptionAccountSelValue(const char* section, const char* name,
961 const char* key, const char* doc_string,
962 GncOptionUIType ui_type,
963 const Account* value,
964 GncOptionAccountTypeList&& allowed) :
965 OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
966 m_value{*guid_null()}, m_default_value{*guid_null()}, m_allowed{std::move(allowed)} {
967 if (!validate(value))
968 throw std::invalid_argument("Supplied Value not in allowed set.");
969 m_value = m_default_value = *qof_entity_get_guid(value);
970 }
971
972 const Account* get_value() const;
973 const Account* get_default_value() const;
974 bool validate (const Account* value) const;
975 void set_value (const Account* value) {
976 if (validate(value))
977 {
978 auto guid{qof_entity_get_guid(value)};
979 m_value = *guid;
980 m_dirty = true;
981 }
982 //else throw
983 }
984 void set_default_value (const Account* value) {
985 if (validate(value))
986 {
987 auto guid{qof_entity_get_guid(value)};
988 m_value = m_default_value = *guid;
989 }
990 //else throw
991 }
992 GList* account_type_list() const noexcept;
993 void reset_default_value() { m_value = m_default_value; }
994 void mark_saved() noexcept { m_dirty = false; }
995 bool is_dirty() const noexcept { return m_dirty; }
996 bool is_changed() const noexcept { return !guid_equal(&m_value, &m_default_value); }
997 GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
998 void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
999 bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
1000 std::string serialize() const noexcept;
1001 bool deserialize(const std::string& str) noexcept;
1002private:
1003 GncOptionUIType m_ui_type;
1004 GncGUID m_value;
1005 GncGUID m_default_value;
1006 GncOptionAccountTypeList m_allowed;
1007 bool m_dirty{false};
1008};
1009
1010template<> inline std::ostream&
1011operator<< <GncOptionAccountSelValue>(std::ostream& oss,
1012 const GncOptionAccountSelValue& opt)
1013{
1014 auto value{opt.get_value()};
1015 oss << qof_instance_to_string(QOF_INSTANCE(value));
1016 return oss;
1017}
1018
1019template<> inline std::istream&
1020operator>> <GncOptionAccountSelValue>(std::istream& iss,
1022{
1023 Account* value{nullptr};
1024 std::string str;
1025 std::getline(iss, str, ' ');
1026 if (!str.empty())
1027 value = (Account*)qof_instance_from_string(str, opt.get_ui_type());
1028 opt.set_value(value);
1029 iss.clear();
1030 return iss;
1031}
1032
1037/*
1038gnc-date-option-show-time? -- option_data[1]
1039gnc-date-option-get-subtype -- option_data[0]
1040gnc-date-option-value-type m_value
1041gnc-date-option-absolute-time m_type == RelativeDatePeriod::ABSOLUTE
1042gnc-date-option-relative-time m_type != RelativeDatePeriod::ABSOLUTE
1043 */
1044
1046{
1047public:
1048 GncOptionDateValue(const char* section, const char* name,
1049 const char* key, const char* doc_string,
1050 GncOptionUIType ui_type) :
1051 OptionClassifier{section, name, key, doc_string},
1052 m_ui_type{ui_type}, m_date{INT64_MAX}, m_default_date{INT64_MAX},
1053 m_period{RelativeDatePeriod::TODAY},
1054 m_default_period{RelativeDatePeriod::TODAY},
1055 m_period_set{} {}
1056 GncOptionDateValue(const char* section, const char* name,
1057 const char* key, const char* doc_string,
1058 GncOptionUIType ui_type, time64 time) :
1059 OptionClassifier{section, name, key, doc_string},
1060 m_ui_type{ui_type}, m_date{time}, m_default_date{time},
1061 m_period{RelativeDatePeriod::ABSOLUTE},
1062 m_default_period{RelativeDatePeriod::ABSOLUTE},
1063 m_period_set{} {}
1064 GncOptionDateValue(const char* section, const char* name,
1065 const char* key, const char* doc_string,
1066 GncOptionUIType ui_type,
1067 RelativeDatePeriod period) :
1068 OptionClassifier{section, name, key, doc_string},
1069 m_ui_type{ui_type}, m_date{INT64_MAX}, m_default_date{INT64_MAX},
1070 m_period{period}, m_default_period{period},
1071 m_period_set{} {}
1072 GncOptionDateValue(const char* section, const char* name,
1073 const char* key, const char* doc_string,
1074 GncOptionUIType ui_type,
1075 const RelativeDatePeriodVec& period_set) :
1076 OptionClassifier{section, name, key, doc_string},
1077 m_ui_type{ui_type}, m_date{INT64_MAX}, m_default_date{INT64_MAX},
1078 m_period{period_set.back()},
1079 m_default_period{period_set.back()},
1080 m_period_set{period_set} {}
1081 GncOptionDateValue(const GncOptionDateValue&) = default;
1083 GncOptionDateValue& operator=(const GncOptionDateValue&) = default;
1084 GncOptionDateValue& operator=(GncOptionDateValue&&) = default;
1085 time64 get_value() const noexcept;
1086 time64 get_default_value() const noexcept;
1087 RelativeDatePeriod get_period() const noexcept { return m_period; }
1088 RelativeDatePeriod get_default_period() const noexcept { return m_default_period; }
1089 uint16_t get_period_index() const noexcept;
1090 uint16_t get_default_period_index() const noexcept;
1091 std::ostream& out_stream(std::ostream& oss) const noexcept;
1092 std::istream& in_stream(std::istream& iss);
1093 bool validate(RelativeDatePeriod value);
1094 bool validate(time64 time) {
1095 if (time > MINTIME && time < MAXTIME)
1096 return true;
1097 return false;
1098 }
1099 void set_value(RelativeDatePeriod value) {
1100 if (validate(value))
1101 {
1102 m_period = value;
1103 m_date = INT64_MAX;
1104 m_dirty = true;
1105 }
1106 }
1107 void set_value(time64 time) {
1108 if (validate(time))
1109 {
1110 m_period = RelativeDatePeriod::ABSOLUTE;
1111 m_date = time;
1112 m_dirty = true;
1113 }
1114 }
1115 void set_value(uint16_t index) noexcept;
1116 void set_default_value(RelativeDatePeriod value) {
1117 if (validate(value))
1118 {
1119 m_period = m_default_period = value;
1120 m_date = m_default_date = INT64_MAX;
1121 }
1122 }
1123 void set_default_value(time64 time) {
1124 if (validate(time))
1125 {
1126 m_period = m_default_period = RelativeDatePeriod::ABSOLUTE;
1127 m_date = m_default_date = time;
1128 }
1129 }
1130 uint16_t num_permissible_values() const noexcept
1131 {
1132 return m_period_set.size();
1133 }
1134 uint16_t permissible_value_index(const char* key) const noexcept;
1135 const char* permissible_value(uint16_t index) const
1136 {
1137 return gnc_relative_date_storage_string(m_period_set.at(index));
1138 }
1139 const char* permissible_value_name(uint16_t index) const
1140 {
1141 return gnc_relative_date_display_string(m_period_set.at(index));
1142 }
1143 void reset_default_value() {
1144 m_period = m_default_period;
1145 m_date = m_default_date;
1146 }
1147 void mark_saved() noexcept { m_dirty = false; }
1148 bool is_dirty() const noexcept { return m_dirty; }
1149 bool is_changed() const noexcept { return m_period != m_default_period &&
1150 m_date != m_default_date; }
1151 GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
1152 void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
1153 bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
1154 const RelativeDatePeriodVec& get_period_set() const { return m_period_set; }
1155 std::string serialize() const noexcept;
1156 bool deserialize(const std::string& str) noexcept;
1157private:
1158 GncOptionUIType m_ui_type;
1159 time64 m_date;
1160 time64 m_default_date;
1161 RelativeDatePeriod m_period;
1162 RelativeDatePeriod m_default_period;
1163 RelativeDatePeriodVec m_period_set;
1164 bool m_dirty{false};
1165};
1166
1167template<> inline std::ostream&
1168operator<< <GncOptionDateValue>(std::ostream& oss,
1169 const GncOptionDateValue& opt)
1170{
1171 return opt.out_stream(oss);
1172}
1173
1174template<> inline std::istream&
1175operator>> <GncOptionDateValue>(std::istream& iss,
1176 GncOptionDateValue& opt)
1177{
1178 return opt.in_stream(iss);
1179}
1180
1181
1182#endif //GNC_OPTION_IMPL_HPP_
Account handling public routines.
Set one or more accounts on which to report, optionally restricted to certain account types.
class GncOptionCommodityValue Commodities are stored with their namespace and mnemonic instead of the...
A legal date value is a pair of either a RelativeDatePeriod, the absolute flag and a time64,...
Multichoice options have a vector of valid options (GncMultichoiceOptionChoices) and validate the sel...
Used for numeric ranges and plot sizes.
The generic option-value class.
GnuCash Budgets.
Commodity handling public routines.
OptionUITypes.
C++ Public interface for individual options.
const char * gnc_commodity_get_namespace(const gnc_commodity *cm)
Retrieve the namespace for the specified commodity.
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
GList * account_type_list() const noexcept
Create a GList of account types to pass to gnc_account_sel_set_acct_filters.
GList * account_type_list() const noexcept
Create a GList of account types to pass to gnc_account_sel_set_acct_filters.
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition guid.cpp:165
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition guid.h:84
gboolean guid_equal(const GncGUID *guid_1, const GncGUID *guid_2)
Given two GUIDs, return TRUE if they are non-NULL and equal.
Definition guid.cpp:237
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition guid.cpp:208
const GncGUID * qof_entity_get_guid(gconstpointer ent)
RelativeDatePeriod
Reporting periods relative to the current date.
GncOptionUIType
Used by GncOptionClassifier to indicate to dialog-options what control should be displayed for the op...
const char * gnc_relative_date_display_string(RelativeDatePeriod per)
Provide the string representation of a relative date for displaying value to a user.
const char * gnc_relative_date_storage_string(RelativeDatePeriod per)
Provide the string representation of a relative date for persisting the value.
std::pair< QofIdTypeConst, GncGUID > GncItem
class GncOptionQofinstanceValue
STRUCTS.
The type used to store guids in C.
Definition guid.h:75
class GncOptionGncOwnerValue
This class is the parent of all option implementations.
A Query.
Definition qofquery.cpp:75