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