GnuCash  4.12-527-g05ffd3d4eb
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 extern "C"
38 {
39 #include <config.h>
40 #include "qof.h"
41 #include "Account.h"
42 #include "gnc-budget.h"
43 #include "gnc-commodity.h"
44 }
45 #include "gnc-datetime.hpp"
46 #include <string>
47 #include <utility>
48 #include <vector>
49 #include <exception>
50 #include <functional>
51 #include <variant>
52 #include <iostream>
53 #include <limits>
54 
55 #include "gnc-option-uitype.hpp"
56 
57 
58 #ifndef SWIG
59 size_t constexpr classifier_size_max{50};
60 size_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
80 auto constexpr uint16_t_max = std::numeric_limits<uint16_t>::max();
81 #endif
82 
86 template <typename ValueType>
88 {
89 public:
90  GncOptionValue<ValueType>(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} { }
97  OptionClassifier{from.m_section, from.m_name, from.m_sort_tag,
98  from.m_doc_string},
99  m_ui_type(from.get_ui_type()), m_value{from.get_value()},
100  m_default_value{from.get_default_value()}{}
102  GncOptionValue<ValueType>& operator=(const GncOptionValue<ValueType>&) = default;
104  ~GncOptionValue<ValueType>() = default;
105  ValueType get_value() const { return m_value; }
106  ValueType get_default_value() const { return m_default_value; }
107  void set_value(ValueType new_value);
108  void set_default_value(ValueType new_value);
109  void reset_default_value();
110  bool is_changed() const noexcept { return m_value != m_default_value; }
111  GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
112  void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
113  bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
114  std::string serialize() const noexcept;
115  bool deserialize(const std::string& str) noexcept;
116 private:
117  GncOptionUIType m_ui_type;
118  ValueType m_value;
119  ValueType m_default_value;
120 };
121 
122 using GncItem = std::pair<QofIdTypeConst, GncGUID>;
123 
125 public:
127  const char* section, const char* name,
128  const char* key, const char* doc_string,
129  const QofInstance* value,
130  GncOptionUIType ui_type = GncOptionUIType::INTERNAL);
134  ~GncOptionQofInstanceValue() = default;
135  const QofInstance* get_value() const;
136  const QofInstance* get_default_value() const;
137  GncItem get_item() const { return m_value; }
138  GncItem get_default_item() const { return m_default_value; }
139  void set_value(const QofInstance* new_value);
140  void set_default_value(const QofInstance* new_value);
141  void reset_default_value();
142  bool is_changed() const noexcept;
143  GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
144  void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
145  bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
146  std::string serialize() const noexcept;
147  bool deserialize(const std::string& str) noexcept;
148 private:
149  GncOptionUIType m_ui_type;
150  GncItem m_value;
151  GncItem m_default_value;
152 };
153 
163 {
164 public:
165  GncOptionCommodityValue() = delete;
166  GncOptionCommodityValue(const char* section, const char* name,
167  const char* key, const char* doc_string,
168  gnc_commodity* value,
169  GncOptionUIType ui_type = GncOptionUIType::COMMODITY) :
170  OptionClassifier{section, name, key, doc_string},
171  m_ui_type{ui_type}, m_is_currency{ui_type == GncOptionUIType::CURRENCY},
172  m_namespace{gnc_commodity_get_namespace(value)},
173  m_mnemonic{gnc_commodity_get_mnemonic(value)},
174  m_default_namespace{gnc_commodity_get_namespace(value)},
175  m_default_mnemonic{gnc_commodity_get_mnemonic(value)}
176  {
177  if (!validate(value))
178  throw std::invalid_argument("Attempt to create GncOptionCommodityValue with currency UIType and non-currency value.");
179  }
182  GncOptionCommodityValue& operator=(const GncOptionCommodityValue&) = default;
183  GncOptionCommodityValue& operator=(GncOptionCommodityValue&&) = default;
184  gnc_commodity* get_value() const;
185  gnc_commodity* get_default_value() const;
186  bool validate(gnc_commodity*) const noexcept;
187  void set_value(gnc_commodity* value);
188  void set_default_value(gnc_commodity* value);
189  void reset_default_value();
190  bool is_changed() const noexcept;
191  GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
192  void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
193  bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
194  std::string serialize() const noexcept;
195  bool deserialize(const std::string& str) noexcept;
196 private:
197  GncOptionUIType m_ui_type;
198  bool m_is_currency;
199  std::string m_namespace;
200  std::string m_mnemonic;
201  std::string m_default_namespace;
202  std::string m_default_mnemonic;
203 };
204 
205 QofInstance* qof_instance_from_string(const std::string& str,
206  GncOptionUIType type);
207 QofInstance* qof_instance_from_guid(GncGUID*, GncOptionUIType type);
208 std::string qof_instance_to_string(const QofInstance* inst);
209 
210 template <typename T>
212 {
213  static constexpr bool value =
214  std::is_same_v<std::decay_t<T>, GncOptionQofInstanceValue>;
215 };
216 
217 template <typename T> inline constexpr bool
218 is_QofInstanceValue_v = is_QofInstanceValue<T>::value;
219 
220 template <typename T>
222 {
223  static constexpr bool value =
224  std::is_same_v<std::decay_t<T>, GncOptionValue<const QofQuery*>>;
225 };
226 
227 template <typename T> inline constexpr bool
228 is_QofQueryValue_v = is_QofQueryValue<T>::value;
229 
230 /* These will work when m_value is a built-in class; GnuCash class and container
231  * values will need specialization unless they happen to define operators << and
232  * >>.
233  * Note that SWIG 3.0.12 chokes on elaborate enable_if so just hide the
234  * following templates from SWIG. (Ignoring doesn't work because SWIG still has
235  * to parse the templates to figure out the symbols.
236  */
237 #ifndef SWIG
238 template<class OptType,
239  typename std::enable_if_t<is_OptionClassifier_v<OptType> &&
240  ! (is_QofInstanceValue_v<OptType> ||
241  is_RangeValue_v<OptType>), int> = 0>
242 std::ostream& operator<<(std::ostream& oss, const OptType& opt)
243 {
244  oss << opt.get_value();
245  return oss;
246 }
247 
248 template<> inline std::ostream&
249 operator<< <GncOptionValue<bool>>(std::ostream& oss,
250  const GncOptionValue<bool>& opt)
251 {
252  oss << (opt.get_value() ? "#t" : "#f");
253  return oss;
254 }
255 
256 inline std::ostream&
257 operator<< (std::ostream& oss, const GncOptionCommodityValue& opt)
258 {
259  oss << opt.serialize();
260  return oss;
261 }
262 
263 template<class OptType,
264  typename std::enable_if_t<is_QofInstanceValue_v<OptType>, int> = 0>
265 inline std::ostream&
266 operator<< (std::ostream& oss, const OptType& opt)
267 {
268  auto value = opt.get_value();
269  oss << qof_instance_to_string(value);
270  return oss;
271 }
272 
273 template<class OptType,
274  typename std::enable_if_t<is_OptionClassifier_v<OptType> &&
275  !(is_QofInstanceValue_v<OptType> ||
276  is_RangeValue_v<OptType>), int> = 0>
277 std::istream& operator>>(std::istream& iss, OptType& opt)
278 {
279  std::decay_t<decltype(opt.get_value())> value;
280  if constexpr (std::is_same_v<std::decay_t<decltype(opt.get_value())>, const _gncOwner*> ||
281  std::is_same_v<std::decay_t<decltype(opt.get_value())>, const _QofQuery*>)
282  return iss;
283  else
284  {
285  iss >> value;
286  opt.set_value(value);
287  return iss;
288  }
289 }
290 
291 std::istream& operator>> (std::istream& iss, GncOptionCommodityValue& opt);
292 
293 template<class OptType,
294  typename std::enable_if_t<is_QofInstanceValue_v<OptType>, int> = 0>
295 std::istream&
296 operator>> (std::istream& iss, OptType& opt)
297 {
298  std::string instr;
299  iss >> instr;
300  opt.set_value(qof_instance_from_string(instr, opt.get_ui_type()));
301  return iss;
302 }
303 
304 template<> inline std::istream&
305 operator>> <GncOptionValue<bool>>(std::istream& iss,
307 {
308  std::string instr;
309  iss >> instr;
310  opt.set_value(instr == "#t" ? true : false);
311  return iss;
312 }
313 
314 template<> inline std::istream&
315 operator>> <GncOptionValue<GncOptionReportPlacementVec>>(std::istream& iss,
317 {
318  uint32_t id, wide, high;
319  iss >> id >> wide >> high;
320  opt.set_value(GncOptionReportPlacementVec{{id, wide, high}});
321  return iss;
322 }
323 #endif // SWIG
324 
329 template <typename ValueType>
331 {
332 public:
333  GncOptionRangeValue<ValueType>(const char* section, const char* name,
334  const char* key, const char* doc_string,
335  ValueType value, ValueType min,
336  ValueType max, ValueType step) :
337  OptionClassifier{section, name, key, doc_string},
338  m_value{value >= min && value <= max ? value : min},
339  m_default_value{value >= min && value <= max ? value : min},
340  m_min{min}, m_max{max}, m_step{step} {
341  if constexpr(is_same_decayed_v<ValueType, int>)
342  set_alternate(true);}
347  ValueType get_value() const { return m_value; }
348  ValueType get_default_value() const { return m_default_value; }
349  bool validate(ValueType value) { return value >= m_min && value <= m_max; }
350  void set_value(ValueType value)
351  {
352  if (this->validate(value))
353  m_value = value;
354  else
355  throw std::invalid_argument("Validation failed, value not set.");
356  }
357  void set_default_value(ValueType value)
358  {
359  if (this->validate(value))
360  m_value = m_default_value = value;
361  else
362  throw std::invalid_argument("Validation failed, value not set.");
363  }
364  void get_limits(ValueType& upper, ValueType& lower, ValueType& step) const noexcept
365  {
366  upper = m_max;
367  lower = m_min;
368  step = m_step;
369  }
370  void reset_default_value() { m_value = m_default_value; }
371  bool is_changed() const noexcept { return m_value != m_default_value; }
372  GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
373  void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
374  bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
375  bool is_alternate() const noexcept { return m_alternate; }
376  void set_alternate(bool value) noexcept { m_alternate = value; }
377  std::string serialize() const noexcept;
378  bool deserialize(const std::string& str) noexcept;
379 private:
380  GncOptionUIType m_ui_type = GncOptionUIType::NUMBER_RANGE;
381  ValueType m_value;
382  ValueType m_default_value;
383  ValueType m_min;
384  ValueType m_max;
385  ValueType m_step;
386  bool m_alternate = false;
387 };
388 
389 template<class OptType,
390  typename std::enable_if_t<is_RangeValue_v<OptType>, int> = 0>
391 inline std::ostream&
392 operator<< (std::ostream& oss, const OptType& opt)
393 {
394  if (opt.get_ui_type() == GncOptionUIType::PLOT_SIZE)
395  oss << (opt.is_alternate() ? "pixels" : "percent") << " ";
396  oss << opt.get_value();
397  return oss;
398 }
399 
400 template<class OptType,
401  typename std::enable_if_t<is_RangeValue_v<OptType>, int> = 0>
402 inline std::istream&
403 operator>> (std::istream& iss, OptType& opt)
404 {
405  if (opt.get_ui_type() == GncOptionUIType::PLOT_SIZE)
406  {
407  std::string alt;
408  iss >> alt;
409  opt.set_alternate(strncmp(alt.c_str(), "percent",
410  strlen("percent")) == 0);
411  }
412  if constexpr (std::is_same_v<std::decay_t<OptType>,
414  {
415  double d;
416  iss >> d;
417  opt.set_value(d);
418  }
419  else
420  {
421  int i;
422  iss >> i;
423  opt.set_value(i);
424  }
425  return iss;
426 }
427 
428 using GncMultichoiceOptionEntry = std::tuple<const std::string,
429  const std::string,
430  GncOptionMultichoiceKeyType>;
431 using GncMultichoiceOptionIndexVec = std::vector<uint16_t>;
432 using GncMultichoiceOptionChoices = std::vector<GncMultichoiceOptionEntry>;
433 
450 {
451 public:
452  GncOptionMultichoiceValue(const char* section, const char* name,
453  const char* key, const char* doc_string,
454  const char* value,
455  GncMultichoiceOptionChoices&& choices,
456  GncOptionUIType ui_type = GncOptionUIType::MULTICHOICE) :
457  OptionClassifier{section, name, key, doc_string},
458  m_ui_type{ui_type},
459  m_value{}, m_default_value{}, m_choices{std::move(choices)}
460  {
461  if (value)
462  {
463  if (auto index = find_key(value);
464  index != uint16_t_max)
465  {
466  m_value.push_back(index);
467  m_default_value.push_back(index);
468  }
469  }
470  }
471 
472  GncOptionMultichoiceValue(const char* section, const char* name,
473  const char* key, const char* doc_string,
474  uint16_t index,
475  GncMultichoiceOptionChoices&& choices,
476  GncOptionUIType ui_type = GncOptionUIType::MULTICHOICE) :
477  OptionClassifier{section, name, key, doc_string},
478  m_ui_type{ui_type},
479  m_value{}, m_default_value{}, m_choices{std::move(choices)}
480  {
481  if (index < m_choices.size())
482  {
483  m_value.push_back(index);
484  m_default_value.push_back(index);
485  }
486  }
487 
488  GncOptionMultichoiceValue(const char* section, const char* name,
489  const char* key, const char* doc_string,
490  GncMultichoiceOptionIndexVec&& indices,
491  GncMultichoiceOptionChoices&& choices,
492  GncOptionUIType ui_type = GncOptionUIType::LIST) :
493  OptionClassifier{section, name, key, doc_string},
494  m_ui_type{ui_type},
495  m_value{indices}, m_default_value{std::move(indices)},
496  m_choices{std::move(choices)} {}
499  GncOptionMultichoiceValue& operator=(const GncOptionMultichoiceValue&) = default;
501 
502  const std::string& get_value() const
503  {
504  auto vec{m_value.size() > 0 ? m_value : m_default_value};
505  if (vec.size() == 0)
506  return c_empty_string;
507  if (vec.size() == 1)
508  return std::get<0>(m_choices.at(vec[0]));
509  else
510  return c_list_string;
511 
512  }
513  const std::string& get_default_value() const
514  {
515  if (m_default_value.size() == 1)
516  return std::get<0>(m_choices.at(m_default_value[0]));
517  else if (m_default_value.size() == 0)
518  return c_empty_string;
519  else
520  return c_list_string;
521  }
522 
523  uint16_t get_index() const
524  {
525  if (m_value.size() > 0)
526  return m_value[0];
527  if (m_default_value.size() > 0)
528  return m_default_value[0];
529  return 0;
530  }
531  const GncMultichoiceOptionIndexVec& get_multiple() const noexcept
532  {
533  return m_value;
534  }
535  const GncMultichoiceOptionIndexVec& get_default_multiple() const noexcept
536  {
537  return m_default_value;
538  }
539  bool validate(const std::string& value) const noexcept
540  {
541  auto index = find_key(value);
542  return index != uint16_t_max;
543 
544  }
545  bool validate(const GncMultichoiceOptionIndexVec& indexes) const noexcept
546  {
547  for (auto index : indexes)
548  if (index >= m_choices.size())
549  return false;
550  return true;
551 
552  }
553  void set_value(const std::string& value)
554  {
555  auto index = find_key(value);
556  if (index != uint16_t_max)
557  {
558  m_value.clear();
559  m_value.push_back(index);
560  }
561  else
562  throw std::invalid_argument("Value not a valid choice.");
563 
564  }
565  void set_value(uint16_t index)
566  {
567  if (index < m_choices.size())
568  {
569  m_value.clear();
570  m_value.push_back(index);
571  }
572  else
573  throw std::invalid_argument("Value not a valid choice.");
574 
575  }
576  void set_default_value(const std::string& value)
577  {
578  auto index = find_key(value);
579  if (index != uint16_t_max)
580  {
581  m_value.clear();
582  m_value.push_back(index);
583  m_default_value.clear();
584  m_default_value.push_back(index);
585  }
586  else
587  throw std::invalid_argument("Value not a valid choice.");
588 
589  }
590  void set_default_value(uint16_t index)
591  {
592  if (index < m_choices.size())
593  {
594  m_value.clear();
595  m_value.push_back(index);
596  m_default_value.clear();
597  m_default_value.push_back(index);
598  }
599  else
600  throw std::invalid_argument("Value not a valid choice.");
601 
602  }
603  void set_multiple(const GncMultichoiceOptionIndexVec& indexes)
604  {
605  if (validate(indexes))
606  m_value = indexes;
607  else
608  throw std::invalid_argument("One of the supplied indexes was out of range.");
609  }
610  void set_default_multiple(const GncMultichoiceOptionIndexVec& indexes)
611  {
612  if (validate(indexes))
613  m_value = m_default_value = indexes;
614  else
615  throw std::invalid_argument("One of the supplied indexes was out of range.");
616  }
617  uint16_t num_permissible_values() const noexcept
618  {
619  return m_choices.size();
620  }
621  uint16_t permissible_value_index(const char* key) const noexcept
622  {
623  return find_key(key);
624  }
625  const char* permissible_value(uint16_t index) const
626  {
627  return std::get<0>(m_choices.at(index)).c_str();
628  }
629  const char* permissible_value_name(uint16_t index) const
630  {
631  return std::get<1>(m_choices.at(index)).c_str();
632  }
633  void reset_default_value() { m_value = m_default_value; }
634  bool is_changed() const noexcept { return m_value != m_default_value; }
635  GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
636  void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
637  bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
638  GncOptionMultichoiceKeyType get_keytype(unsigned i) const { return std::get<2>(m_choices.at(i)); }
639  std::string serialize() const noexcept;
640  bool deserialize(const std::string& str) noexcept;
641 private:
642  uint16_t find_key (const std::string& key) const noexcept
643  {
644  auto iter = std::find_if(m_choices.begin(), m_choices.end(),
645  [key](auto choice) {
646  return std::get<0>(choice) == key; });
647  if (iter != m_choices.end())
648  return iter - m_choices.begin();
649  else
650  return uint16_t_max;
651 
652  }
653  GncOptionUIType m_ui_type;
654  GncMultichoiceOptionIndexVec m_value;
655  GncMultichoiceOptionIndexVec m_default_value;
656  GncMultichoiceOptionChoices m_choices;
657  static const std::string c_empty_string;
658  static const std::string c_list_string;
659 };
660 
661 template<> inline std::ostream&
662 operator<< <GncOptionMultichoiceValue>(std::ostream& oss,
663  const GncOptionMultichoiceValue& opt)
664 {
665  auto vec{opt.get_multiple()};
666  bool first{true};
667  for (auto index : vec)
668  {
669  if (first)
670  first = false;
671  else
672  oss << " ";
673  oss << opt.permissible_value(index);
674  }
675  return oss;
676 }
677 
678 template<> inline std::istream&
679 operator>> <GncOptionMultichoiceValue>(std::istream& iss,
681 {
682  GncMultichoiceOptionIndexVec values;
683  while (true)
684  {
685  std::string str;
686  std::getline(iss, str, ' ');
687  if (!str.empty())
688  {
689  auto index = opt.permissible_value_index(str.c_str());
690  if (index != uint16_t_max)
691  values.push_back(index);
692  else
693  {
694  std::string err = str + " is not one of ";
695  err += opt.m_name;
696  err += "'s permissible values.";
697  throw std::invalid_argument(err);
698  }
699  }
700  else
701  break;
702  }
703  opt.set_multiple(values);
704  iss.clear();
705  return iss;
706 }
707 
708 
709 using GncOptionAccountList = std::vector<GncGUID>;
710 
711 using GncOptionAccountTypeList = std::vector<GNCAccountType>;
712 
731 {
732 public:
733  GncOptionAccountListValue(const char* section, const char* name,
734  const char* key, const char* doc_string,
735  GncOptionUIType ui_type, bool multi=true) :
736  OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
737  m_value{}, m_default_value{}, m_allowed{}, m_multiselect{multi} {}
738 
739  GncOptionAccountListValue(const char* section, const char* name,
740  const char* key, const char* doc_string,
741  GncOptionUIType ui_type,
742  const GncOptionAccountList& value, bool multi=true) :
743  OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
744  m_value{value}, m_default_value{std::move(value)}, m_allowed{},
745  m_multiselect{multi} {}
746  GncOptionAccountListValue(const char* section, const char* name,
747  const char* key, const char* doc_string,
748  GncOptionUIType ui_type,
749  GncOptionAccountTypeList&& allowed, bool multi=true) :
750  OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
751  m_value{}, m_default_value{}, m_allowed{std::move(allowed)},
752  m_multiselect{multi} {}
753  GncOptionAccountListValue(const char* section, const char* name,
754  const char* key, const char* doc_string,
755  GncOptionUIType ui_type,
756  const GncOptionAccountList& value,
757  GncOptionAccountTypeList&& allowed, bool multi=true) :
758  OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
759  m_value{}, m_default_value{}, m_allowed{std::move(allowed)},
760  m_multiselect{multi} {
761  if (!validate(value))
762  throw std::invalid_argument("Supplied Value not in allowed set.");
763  m_value = value;
764  m_default_value = std::move(value);
765  }
766 
767  /* These aren't const& because if m_default_value hasn't been set
768  * get_default_value finds the first account that matches the allowed types
769  * and returns a GncOptionAccountList containing it. That's a stack variable
770  * and must be returned by value.
771  */
772  GncOptionAccountList get_value() const;
773  GncOptionAccountList get_default_value() const;
774  bool validate (const GncOptionAccountList& values) const;
775  void set_value (GncOptionAccountList values) {
776  if (validate(values))
777  //throw!
778  m_value = values;
779  }
780  void set_default_value (GncOptionAccountList values) {
781  if (validate(values))
782  //throw!
783  m_value = m_default_value = values;
784  }
785  GList* account_type_list() const noexcept;
786  void reset_default_value() { m_value = m_default_value; }
787  bool is_changed() const noexcept;
788  GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
789  void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
790  bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
791  bool is_multiselect() const noexcept { return m_multiselect; }
792  std::string serialize() const noexcept;
793  bool deserialize(const std::string& str) noexcept;
794 private:
795  GncOptionUIType m_ui_type;
796  GncOptionAccountList m_value;
797  GncOptionAccountList m_default_value;
798  GncOptionAccountTypeList m_allowed;
799  bool m_multiselect;
800 };
801 
802 template<> inline std::ostream&
803 operator<< <GncOptionAccountListValue>(std::ostream& oss,
804  const GncOptionAccountListValue& opt)
805 {
806  auto values{opt.get_value()};
807  bool first = true;
808  for (auto value : values)
809  {
810  if (first)
811  first = false;
812  else
813  oss << " ";
814  oss << guid_to_string(&value);
815  }
816  return oss;
817 }
818 
819 template<> inline std::istream&
820 operator>> <GncOptionAccountListValue>(std::istream& iss,
822 {
823  GncOptionAccountList values;
824  while (true)
825  {
826  std::string str;
827  std::getline(iss, str, ' ');
828  if (!str.empty())
829  {
830  auto guid{qof_entity_get_guid(qof_instance_from_string(str, opt.get_ui_type()))};
831  values.push_back(*guid);
832  }
833  else
834  break;
835  }
836  opt.set_value(values);
837  iss.clear();
838  return iss;
839 }
840 
841 /* @class GncOptionAccountSelValue
842  * Like GncOptionAccountListValue but contains only a single account.
843  */
844 
846 {
847 public:
848  GncOptionAccountSelValue(const char* section, const char* name,
849  const char* key, const char* doc_string,
850  GncOptionUIType ui_type) :
851  OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
852  m_value{*guid_null()}, m_default_value{*guid_null()}, m_allowed{} {}
853 
854  GncOptionAccountSelValue(const char* section, const char* name,
855  const char* key, const char* doc_string,
856  GncOptionUIType ui_type,
857  const Account* value) :
858  OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
859  m_value{*qof_entity_get_guid(value)},
860  m_default_value{*qof_entity_get_guid(value)}, m_allowed{} {}
861  GncOptionAccountSelValue(const char* section, const char* name,
862  const char* key, const char* doc_string,
863  GncOptionUIType ui_type,
864  GncOptionAccountTypeList&& allowed) :
865  OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
866  m_value{*guid_null()}, m_default_value{*guid_null()},
867  m_allowed{std::move(allowed)} {}
868  GncOptionAccountSelValue(const char* section, const char* name,
869  const char* key, const char* doc_string,
870  GncOptionUIType ui_type,
871  const Account* value,
872  GncOptionAccountTypeList&& allowed) :
873  OptionClassifier{section, name, key, doc_string}, m_ui_type{ui_type},
874  m_value{*guid_null()}, m_default_value{*guid_null()}, m_allowed{std::move(allowed)} {
875  if (!validate(value))
876  throw std::invalid_argument("Supplied Value not in allowed set.");
877  m_value = m_default_value = *qof_entity_get_guid(value);
878  }
879 
880  const Account* get_value() const;
881  const Account* get_default_value() const;
882  bool validate (const Account* value) const;
883  void set_value (const Account* value) {
884  if (validate(value))
885  {
886  auto guid{qof_entity_get_guid(value)};
887  m_value = *guid;
888  }
889  //else throw
890  }
891  void set_default_value (const Account* value) {
892  if (validate(value))
893  {
894  auto guid{qof_entity_get_guid(value)};
895  m_value = m_default_value = *guid;
896  }
897  //else throw
898  }
899  GList* account_type_list() const noexcept;
900  void reset_default_value() { m_value = m_default_value; }
901  bool is_changed() const noexcept { return !guid_equal(&m_value, &m_default_value); }
902  GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
903  void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
904  bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
905  std::string serialize() const noexcept;
906  bool deserialize(const std::string& str) noexcept;
907 private:
908  GncOptionUIType m_ui_type;
909  GncGUID m_value;
910  GncGUID m_default_value;
911  GncOptionAccountTypeList m_allowed;
912 };
913 
914 template<> inline std::ostream&
915 operator<< <GncOptionAccountSelValue>(std::ostream& oss,
916  const GncOptionAccountSelValue& opt)
917 {
918  auto value{opt.get_value()};
919  oss << qof_instance_to_string(QOF_INSTANCE(value));
920  return oss;
921 }
922 
923 template<> inline std::istream&
924 operator>> <GncOptionAccountSelValue>(std::istream& iss,
926 {
927  Account* value{nullptr};
928  std::string str;
929  std::getline(iss, str, ' ');
930  if (!str.empty())
931  value = (Account*)qof_instance_from_string(str, opt.get_ui_type());
932  opt.set_value(value);
933  iss.clear();
934  return iss;
935 }
936 
941 /*
942 gnc-date-option-show-time? -- option_data[1]
943 gnc-date-option-get-subtype -- option_data[0]
944 gnc-date-option-value-type m_value
945 gnc-date-option-absolute-time m_type == RelativeDatePeriod::ABSOLUTE
946 gnc-date-option-relative-time m_type != RelativeDatePeriod::ABSOLUTE
947  */
948 
950 {
951 public:
952  GncOptionDateValue(const char* section, const char* name,
953  const char* key, const char* doc_string,
954  GncOptionUIType ui_type) :
955  OptionClassifier{section, name, key, doc_string},
956  m_ui_type{ui_type}, m_date{INT64_MAX}, m_default_date{INT64_MAX},
957  m_period{RelativeDatePeriod::TODAY},
958  m_default_period{RelativeDatePeriod::TODAY},
959  m_period_set{} {}
960  GncOptionDateValue(const char* section, const char* name,
961  const char* key, const char* doc_string,
962  GncOptionUIType ui_type, time64 time) :
963  OptionClassifier{section, name, key, doc_string},
964  m_ui_type{ui_type}, m_date{time}, m_default_date{time},
965  m_period{RelativeDatePeriod::ABSOLUTE},
966  m_default_period{RelativeDatePeriod::ABSOLUTE},
967  m_period_set{} {}
968  GncOptionDateValue(const char* section, const char* name,
969  const char* key, const char* doc_string,
970  GncOptionUIType ui_type,
971  RelativeDatePeriod period) :
972  OptionClassifier{section, name, key, doc_string},
973  m_ui_type{ui_type}, m_date{INT64_MAX}, m_default_date{INT64_MAX},
974  m_period{period}, m_default_period{period},
975  m_period_set{} {}
976  GncOptionDateValue(const char* section, const char* name,
977  const char* key, const char* doc_string,
978  GncOptionUIType ui_type,
979  const RelativeDatePeriodVec& period_set) :
980  OptionClassifier{section, name, key, doc_string},
981  m_ui_type{ui_type}, m_date{INT64_MAX}, m_default_date{INT64_MAX},
982  m_period{period_set.back()},
983  m_default_period{period_set.back()},
984  m_period_set{period_set} {}
985  GncOptionDateValue(const GncOptionDateValue&) = default;
987  GncOptionDateValue& operator=(const GncOptionDateValue&) = default;
988  GncOptionDateValue& operator=(GncOptionDateValue&&) = default;
989  time64 get_value() const noexcept;
990  time64 get_default_value() const noexcept;
991  RelativeDatePeriod get_period() const noexcept { return m_period; }
992  RelativeDatePeriod get_default_period() const noexcept { return m_default_period; }
993  uint16_t get_period_index() const noexcept;
994  uint16_t get_default_period_index() const noexcept;
995  std::ostream& out_stream(std::ostream& oss) const noexcept;
996  std::istream& in_stream(std::istream& iss);
997  bool validate(RelativeDatePeriod value);
998  bool validate(time64 time) {
999  if (time > MINTIME && time < MAXTIME)
1000  return true;
1001  return false;
1002  }
1003  void set_value(RelativeDatePeriod value) {
1004  if (validate(value))
1005  {
1006  m_period = value;
1007  m_date = INT64_MAX;
1008  }
1009  }
1010  void set_value(time64 time) {
1011  if (validate(time))
1012  {
1013  m_period = RelativeDatePeriod::ABSOLUTE;
1014  m_date = time;
1015  }
1016  }
1017  void set_value(uint16_t index) noexcept;
1018  void set_default_value(RelativeDatePeriod value) {
1019  if (validate(value))
1020  {
1021  m_period = m_default_period = value;
1022  m_date = m_default_date = INT64_MAX;
1023  }
1024  }
1025  void set_default_value(time64 time) {
1026  if (validate(time))
1027  {
1028  m_period = m_default_period = RelativeDatePeriod::ABSOLUTE;
1029  m_date = m_default_date = time;
1030  }
1031  }
1032  uint16_t num_permissible_values() const noexcept
1033  {
1034  return m_period_set.size();
1035  }
1036  uint16_t permissible_value_index(const char* key) const noexcept;
1037  const char* permissible_value(uint16_t index) const
1038  {
1039  return gnc_relative_date_storage_string(m_period_set.at(index));
1040  }
1041  const char* permissible_value_name(uint16_t index) const
1042  {
1043  return gnc_relative_date_display_string(m_period_set.at(index));
1044  }
1045  void reset_default_value() {
1046  m_period = m_default_period;
1047  m_date = m_default_date;
1048  }
1049  bool is_changed() const noexcept { return m_period != m_default_period &&
1050  m_date != m_default_date; }
1051  GncOptionUIType get_ui_type() const noexcept { return m_ui_type; }
1052  void make_internal() { m_ui_type = GncOptionUIType::INTERNAL; }
1053  bool is_internal() { return m_ui_type == GncOptionUIType::INTERNAL; }
1054  const RelativeDatePeriodVec& get_period_set() const { return m_period_set; }
1055  std::string serialize() const noexcept;
1056  bool deserialize(const std::string& str) noexcept;
1057 private:
1058  GncOptionUIType m_ui_type;
1059  time64 m_date;
1060  time64 m_default_date;
1061  RelativeDatePeriod m_period;
1062  RelativeDatePeriod m_default_period;
1063  RelativeDatePeriodVec m_period_set;
1064 };
1065 
1066 template<> inline std::ostream&
1067 operator<< <GncOptionDateValue>(std::ostream& oss,
1068  const GncOptionDateValue& opt)
1069 {
1070  return opt.out_stream(oss);
1071 }
1072 
1073 template<> inline std::istream&
1074 operator>> <GncOptionDateValue>(std::istream& iss,
1075  GncOptionDateValue& opt)
1076 {
1077  return opt.in_stream(iss);
1078 }
1079 
1080 
1081 #endif //GNC_OPTION_IMPL_HPP_
1082 
const char * gnc_relative_date_display_string(RelativeDatePeriod per)
Provide the string representation of a relative date for displaying value to a user.
The generic option-value class.
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
GList * account_type_list() const noexcept
Create a GList of account types to pass to gnc_account_sel_set_acct_filters.
GnuCash Budgets.
OptionUITypes.
A legal date value is a pair of either a RelativeDatePeriod, the absolute flag and a time64...
GList * account_type_list() const noexcept
Create a GList of account types to pass to gnc_account_sel_set_acct_filters.
const char * gnc_commodity_get_namespace(const gnc_commodity *cm)
Retrieve the namespace for the specified commodity.
Set one or more accounts on which to report, optionally restricted to certain account types...
This class is the parent of all option implmentations.
C++ Public interface for individual options.
Account handling public routines.
Multichoice options have a vector of valid options (GncMultichoiceOptionChoices) and validate the sel...
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:204
RelativeDatePeriod
Reporting periods relative to the current date.
class GncOptionCommodityValue Commodities are stored with their namespace and mnemonic instead of the...
Used for numeric ranges and plot sizes.
const GncGUID * qof_entity_get_guid(gconstpointer ent)
gchar * guid_to_string(const GncGUID *guid)
The guid_to_string() routine returns a null-terminated string encoding of the id. ...
Definition: guid.cpp:165
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:131
const char * gnc_relative_date_storage_string(RelativeDatePeriod per)
Provide the string representation of a relative date for persisting the value.
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
The type used to store guids in C.
Definition: guid.h:75
A Query.
Definition: qofquery.cpp:77
GncOptionUIType
Used by GncOptionClassifier to indicate to dialog-options what control should be displayed for the op...
Commodity handling public routines.