Rose
Settings.h
Go to the documentation of this file.
1 
8 #pragma once
9 
10 #include <filesystem>
11 #include <iostream>
12 #include <soci/soci.h>
13 #include <sqlite3/soci-sqlite3.h>
14 #include "Color.h"
15 #include "Signals.h"
16 #include "Types.h"
17 
18 namespace rose {
19  using namespace std;
20 
21  struct SettingsUpdateProtocol : public Protocol<std::string> {};
22 
27  class Settings {
28  protected:
29  std::filesystem::path mDbPath;
30 
31  static constexpr std::string_view string_table = "settings_string";
32  static constexpr std::string_view int_table = "settings_int";
33  static constexpr std::string_view real_table = "settings_real";
34  static constexpr std::string_view int_pair_table = "settings_int_pair";
35  static constexpr std::string_view real_pair_table = "settings_real_pair";
36  static constexpr std::string_view color_table = "settings_color";
37 
42  void transmitDataUpdate(const std::string& dataName);
43 
44  Settings();
45 
46  public:
47 
48  static Settings& getSettings() {
49  static Settings instance{};
50  return instance;
51  }
52 
56  void initializeDatabase();
57 
60 
70  template<typename T, typename S>
71  std::optional<T> getDatabaseValue(soci::session &sql, S name) {
72  soci::indicator ind;
73  if constexpr (is_integral_v<T>) {
74  T value;
75  sql << "SELECT value FROM " << int_table << " WHERE name = \"" << name << '"', soci::into(value, ind);
76  if (sql.got_data() && ind == soci::i_ok) {
77  return value;
78  }
79  return nullopt;
80  } else if constexpr (is_floating_point_v<T>) {
81  T value;
82  sql << "SELECT value FROM " << real_table << " WHERE name = \"" << name << '"', soci::into(value, ind);
83  if (sql.got_data() && ind == soci::i_ok) {
84  return value;
85  }
86  return nullopt;
87  } else if constexpr (is_base_of_v<std::array<int,2>, T>) {
88  soci::row r;
89  sql << "SELECT a,b FROM " << int_pair_table << " WHERE name = \"" << name << '"', soci::into(r);
90  if (sql.got_data() && r.get_indicator(0) == soci::i_ok && r.get_indicator(1) == soci::i_ok) {
91  return T{r.get<int>(0), r.get<int>(1)};
92  }
93  return nullopt;
94  } else if constexpr (is_base_of_v<Size, T>) {
95  soci::row r;
96  sql << "SELECT a,b FROM " << int_pair_table << " WHERE name = \"" << name << '"', soci::into(r);
97  if (sql.got_data() && r.get_indicator(0) == soci::i_ok && r.get_indicator(1) == soci::i_ok) {
98  return T{r.get<int>(0), r.get<int>(1)};
99  }
100  return nullopt;
101  } else if constexpr (is_base_of_v<Position<int>, T>) {
102  soci::row r;
103  sql << "SELECT a,b FROM " << int_pair_table << " WHERE name = \"" << name << '"', soci::into(r);
104  if (sql.got_data() && r.get_indicator(0) == soci::i_ok && r.get_indicator(1) == soci::i_ok) {
105  return T{r.get<int>(0), r.get<int>(1)};
106  }
107  return nullopt;
108  } else if constexpr (is_base_of_v<std::array<double,2>, T>) {
109  soci::row r;
110  sql << "SELECT a,b FROM " << real_pair_table << " WHERE name = \"" << name << '"', soci::into(r);
111  if (sql.got_data() && r.get_indicator(0) == soci::i_ok && r.get_indicator(1) == soci::i_ok) {
112  return T{r.get<double>(0), r.get<double>(1)};
113  }
114  return nullopt;
115  } else if constexpr (is_same_v<T, string> || is_same_v<T, const string> ||
116  is_same_v<T, string_view> || is_same_v<T, const string_view> ||
117  is_same_v<T, char *> || is_same_v<T, const char *>) {
118  T value;
119  sql << "SELECT value FROM " << string_table << " WHERE name = \"" << name << '"', soci::into(value, ind);
120  if (sql.got_data() && ind == soci::i_ok) {
121  return value;
122  }
123  return nullopt;
124  } else if constexpr (is_same_v<T, color::RGBA>) {
125  soci::row r;
126  sql << "SELECT r,g,b,a FROM " << color_table << " WHERE name = \"" << name << '"', soci::into(r);
127  if (sql.got_data() && r.get_indicator(0) == soci::i_ok && r.get_indicator(1) == soci::i_ok
128  && r.get_indicator(2) == soci::i_ok && r.get_indicator(3) == soci::i_ok) {
129  color::RGBA value{};
130  value.r() = r.get<double>(0);
131  value.g() = r.get<double>(1);
132  value.b() = r.get<double>(2);
133  value.a() = r.get<double>(3);
134  return value;
135  }
136  return nullopt;
137  } else if constexpr (is_same_v<T, color::HSVA>) {
138  soci::row r;
139  sql << "SELECT r,g,b,a FROM " << color_table << " WHERE name = \"" << name << '"', soci::into(r);
140  if (sql.got_data() && r.get_indicator(0) == soci::i_ok && r.get_indicator(1) == soci::i_ok
141  && r.get_indicator(2) == soci::i_ok && r.get_indicator(3) == soci::i_ok) {
142  color::HSVA value{};
143  value.hue() = r.get<double>(0);
144  value.saturation() = r.get<double>(1);
145  value.value() = r.get<double>(2);
146  value.alpha() = r.get<double>(3);
147  return value;
148  }
149  return nullopt;
150  } else {
151  static_assert(is_integral_v<T>, "Value type not supported by Settings implementation." );
152  }
153  }
154 
164  template<typename T, typename S>
165  void setDatabaseValue(soci::session &sql, S name, T value) {
166  if constexpr (is_integral_v<T>) {
167  sql << "INSERT OR REPLACE INTO " << int_table << " (name,value) VALUES (\"" << name << "\"," << value << ')';
168  } else if constexpr (is_floating_point_v<T>) {
169  sql << "INSERT OR REPLACE INTO " << real_table << " (name,value) VALUES (\"" << name << "\"," << value << ')';
170  } else if constexpr (is_base_of_v<std::array<int,2>,T>) {
171  sql << "INSERT OR REPLACE INTO " << int_pair_table << " (name,a,b) VALUES (\"" << name << "\","
172  << value.at(0) << ',' << value.at(1) << ')';
173  } else if constexpr (is_base_of_v<Size,T>) {
174  sql << "INSERT OR REPLACE INTO " << int_pair_table << " (name,a,b) VALUES (\"" << name << "\","
175  << value.w << ',' << value.h << ')';
176  } else if constexpr (is_base_of_v<Position<int>,T>) {
177  sql << "INSERT OR REPLACE INTO " << int_pair_table << " (name,a,b) VALUES (\"" << name << "\","
178  << value.x << ',' << value.y << ')';
179  } else if constexpr (is_base_of_v<std::array<double,2>,T>) {
180  sql << "INSERT OR REPLACE INTO " << real_pair_table << " (name,a,b) VALUES (\"" << name << "\"," << value.at(0) << ',' << value.at(1) << ')';
181  } else if constexpr (is_same_v<T,string> || is_same_v<T,const string> ||
182  is_same_v<T,string_view> || is_same_v<T,const string_view> ||
183  is_same_v<T,char*> || is_same_v<T,const char *>) {
184  sql << "INSERT OR REPLACE INTO " << string_table << " (name,value) VALUES (\"" << name << "\",\"" << value << "\")";
185  } else if constexpr (is_same_v<T, color::RGBA>) {
186  sql << "INSERT OR REPLACE INTO " << color_table << " (name,r,g,b,a) VALUES (\"" << name << "\","
187  << value.r() << ',' << value.g() << ',' << value.lastPos() << ',' << value.firstPos() << ");";
188  } else if constexpr (is_same_v<T, color::HSVA>) {
189  sql << "INSERT OR REPLACE INTO " << color_table << " (name,r,g,b,a) VALUES (\"" << name << "\","
190  << (float)value.mHue << ',' << value.mSaturation << ',' << value.mLightness << ',' << value.mAlpha << ");";
191  } else {
192  static_assert(is_integral_v<T>, "Value type not supported by Settings implementation." );
193  return;
194  }
195  transmitDataUpdate(std::string{name});
196  }
197 
205  template<typename T, typename S>
206  void setValue(S name, T value) {
207  try {
208  soci::session sql(soci::sqlite3, mDbPath.string());
209  setDatabaseValue<T>(sql, name, value);
210  } catch (std::exception const &e) {
211  std::cerr << e.what() << '\n';
212  }
213  }
214 
222  template<typename T, typename S>
223  std::optional<T> getValue(S name) {
224  try {
225  soci::session sql(soci::sqlite3, mDbPath.string());
226  return getDatabaseValue<T,S>(sql, name);
227  } catch (std::exception const &e) {
228  std::cerr << e.what() << '\n';
229  return std::nullopt;
230  }
231  }
232 
241  template<typename T, typename S>
242  T getValue(S name, T defaultValue) {
243  auto value = getValue<T,S>(name);
244  if (value)
245  return value.value();
246  return defaultValue;
247  }
248  };
249 }
250 
void setDatabaseValue(soci::session &sql, S name, T value)
Set a value in the settings database.
Definition: Settings.h:165
A convenience structure that composes Signal and Slot types from a protocol signature, and provides a Slot factory.
Definition: Signals.h:122
std::filesystem::path mDbPath
The file path to the settings database.
Definition: Settings.h:29
Red Green Blue Alpha representation of a color.
Definition: Color.h:64
std::optional< T > getValue(S name)
Get a value in the settings database.
Definition: Settings.h:223
Hue Saturation Value (or Brightness) representation of a color.
Definition: Color.h:184
Definition: Settings.h:21
T getValue(S name, T defaultValue)
Get a value in the settings database, returning the default value if not found.
Definition: Settings.h:242
A settings database.
Definition: Settings.h:27
constexpr float & r() noexcept
Reference access to the Red value.
Definition: Color.h:107
ToDo: There is an issue that the initial scroll interaction is lost if the click/press lands on a Wid...
Definition: CelestialOverlay.cpp:13
The transmitter portion of a Signal-Slot transmitter receiver pair.
Definition: Signals.h:40
std::optional< T > getDatabaseValue(soci::session &sql, S name)
Get a value from settings the database.
Definition: Settings.h:71
Establish an intra-application signaling protocol.
void setValue(S name, T value)
Set a value in the settings database.
Definition: Settings.h:206