LibrePCB Developers Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
serializablekeyvaluemap.h
Go to the documentation of this file.
1 /*
2  * LibrePCB - Professional EDA for everyone!
3  * Copyright (C) 2013 LibrePCB Developers, see AUTHORS.md for contributors.
4  * https://librepcb.org/
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef LIBREPCB_SERIALIZABLEKEYVALUEMAP_H
21 #define LIBREPCB_SERIALIZABLEKEYVALUEMAP_H
22 
23 /*******************************************************************************
24  * Includes
25  ******************************************************************************/
26 #include "../elementname.h"
27 #include "../signalslot.h"
28 #include "serializableobject.h"
29 
30 #include <optional/tl/optional.hpp>
31 
32 #include <QtCore>
33 
34 /*******************************************************************************
35  * Namespace / Forward Declarations
36  ******************************************************************************/
37 namespace librepcb {
38 
39 /*******************************************************************************
40  * Class SerializableKeyValueMap
41  ******************************************************************************/
42 
54 template <typename T>
56  Q_DECLARE_TR_FUNCTIONS(SerializableKeyValueMap)
57 
58 public:
59  // Signals
60  enum class Event {
64  };
67 
68  // Constructors / Destructor
69  SerializableKeyValueMap() = delete;
71  : onEdited(*this), mValues(other.mValues) {}
73  const typename T::ValueType& defaultValue) noexcept
74  : onEdited(*this) {
75  mValues.insert("", defaultValue);
76  }
77  explicit SerializableKeyValueMap(const SExpression& node) : onEdited(*this) {
78  foreach (const SExpression& child, node.getChildren(T::tagname)) {
79  QString key;
81  if (child.getChildren().count() > 1) {
82  key = child.getValueByPath<QString>(T::keyname);
83  value = child.getChildByIndex(1);
84  } else {
85  key = QString("");
86  value = child.getChildByIndex(0);
87  }
88  if (mValues.contains(key)) {
89  throw RuntimeError(
90  __FILE__, __LINE__,
91  QString(tr("Key \"%1\" defined multiple times.")).arg(key));
92  }
93  mValues.insert(key, deserializeFromSExpression<typename T::ValueType>(
94  value, false)); // can throw
95  }
96  if (!mValues.contains(QString(""))) {
97  throw RuntimeError(__FILE__, __LINE__,
98  QString(tr("No default %1 defined.")).arg(T::tagname));
99  }
100  }
102 
103  // Getters
104  QStringList keys() const noexcept { return mValues.keys(); }
105  const typename T::ValueType& getDefaultValue() const noexcept {
106  auto i = mValues.find(QString(""));
107  // there must always be a default value!!!
108  Q_ASSERT((i != mValues.end()) && (i.key() == QString("")));
109  return i.value();
110  }
111  bool contains(const QString& key) const noexcept {
112  return mValues.contains(key);
113  }
114  tl::optional<typename T::ValueType> tryGet(const QString& key) const
115  noexcept {
116  auto i = mValues.find(key);
117  if ((i != mValues.end()) && (i.key() == key)) {
118  return i.value();
119  } else {
120  return tl::nullopt;
121  }
122  }
123  const typename T::ValueType& value(const QStringList& keyOrder,
124  QString* usedKey = nullptr) const
125  noexcept {
126  // search in the specified key order
127  foreach (const QString& key, keyOrder) {
128  auto i = mValues.find(key);
129  if ((i != mValues.end()) && (i.key() == key)) {
130  if (usedKey) *usedKey = key;
131  return i.value();
132  }
133  }
134  // use default value (empty key) as fallback
135  if (usedKey) *usedKey = QString("");
136  return getDefaultValue();
137  }
138 
139  // General Methods
140 
141  void setDefaultValue(const typename T::ValueType& value) noexcept {
142  insert(QString(""), value);
143  }
144 
145  void insert(const QString& key, const typename T::ValueType& value) noexcept {
146  auto it = mValues.find(key);
147  if (it == mValues.end()) {
148  mValues.insert(key, value);
149  onEdited.notify(key, Event::ElementAdded);
150  } else if (it.value() != value) {
151  mValues.insert(key, value);
153  }
154  }
155 
157  void serialize(SExpression& root) const override {
158  for (auto i = mValues.constBegin(); i != mValues.constEnd(); ++i) {
159  SExpression& child = root.appendList(T::tagname, true);
160  if (!i.key().isEmpty()) {
161  child.appendChild(T::keyname, i.key(), false);
162  }
163  child.appendChild(i.value());
164  }
165  }
166 
167  // Operator Overloadings
169  const SerializableKeyValueMap<T>& rhs) noexcept {
170  foreach (const QString& key, mValues.keys()) {
171  mValues.remove(key);
172  onEdited.notify(key, Event::ElementRemoved);
173  }
174  mValues = rhs.mValues;
175  QMapIterator<QString, typename T::ValueType> i(rhs.mValues);
176  while (i.hasNext()) {
177  i.next();
178  insert(i.key(), i.value());
179  }
180  return *this;
181  }
182  bool operator==(const SerializableKeyValueMap<T>& rhs) const noexcept {
183  return mValues == rhs.mValues;
184  }
185  bool operator!=(const SerializableKeyValueMap<T>& rhs) const noexcept {
186  return mValues != rhs.mValues;
187  }
188 
189 private: // Data
190  QMap<QString, typename T::ValueType> mValues;
191 };
192 
193 /*******************************************************************************
194  * Class LocalizedNameMap
195  ******************************************************************************/
196 
199  static constexpr const char* tagname = "name";
200  static constexpr const char* keyname = "locale";
201 };
203 
204 /*******************************************************************************
205  * Class LocalizedDescriptionMap
206  ******************************************************************************/
207 
209  typedef QString ValueType;
210  static constexpr const char* tagname = "description";
211  static constexpr const char* keyname = "locale";
212 };
215 
216 /*******************************************************************************
217  * Class LocalizedKeywordsMap
218  ******************************************************************************/
219 
221  typedef QString ValueType;
222  static constexpr const char* tagname = "keywords";
223  static constexpr const char* keyname = "locale";
224 };
225 using LocalizedKeywordsMap =
227 
228 /*******************************************************************************
229  * End of File
230  ******************************************************************************/
231 
232 } // namespace librepcb
233 
234 #endif // LIBREPCB_SERIALIZABLEKEYVALUEMAP_H
SerializableKeyValueMap(const SExpression &node)
Definition: serializablekeyvaluemap.h:77
Slot< SerializableKeyValueMap< T >, const QString &, Event > OnEditedSlot
Definition: serializablekeyvaluemap.h:66
bool contains(const QString &key) const noexcept
Definition: serializablekeyvaluemap.h:111
const QList< SExpression > & getChildren() const
Definition: sexpression.h:84
const SExpression & getChildByIndex(int index) const
Definition: sexpression.cpp:124
SExpression & appendChild(const SExpression &child, bool linebreak)
Definition: sexpression.cpp:173
QString ValueType
Definition: serializablekeyvaluemap.h:221
static constexpr const char * keyname
Definition: serializablekeyvaluemap.h:200
QStringList keys() const noexcept
Definition: serializablekeyvaluemap.h:104
static constexpr const char * tagname
Definition: serializablekeyvaluemap.h:199
void serialize(SExpression &root) const override
Serialize the object into an existing S-Expression node.
Definition: serializablekeyvaluemap.h:157
QMap< QString, typename T::ValueType > mValues
Definition: serializablekeyvaluemap.h:190
QString ValueType
Definition: serializablekeyvaluemap.h:209
SerializableKeyValueMap< T > & operator=(const SerializableKeyValueMap< T > &rhs) noexcept
Definition: serializablekeyvaluemap.h:168
The SerializableObject class is the base class for all classes which need to be serializable/deserial...
Definition: serializableobject.h:43
static constexpr const char * tagname
Definition: serializablekeyvaluemap.h:222
const T::ValueType & getDefaultValue() const noexcept
Definition: serializablekeyvaluemap.h:105
SExpression & appendList(const QString &name, bool linebreak)
Definition: sexpression.cpp:169
Definition: serializablekeyvaluemap.h:220
static constexpr const char * tagname
Definition: serializablekeyvaluemap.h:210
bool operator!=(const SerializableKeyValueMap< T > &rhs) const noexcept
Definition: serializablekeyvaluemap.h:185
~SerializableKeyValueMap() noexcept
Definition: serializablekeyvaluemap.h:101
The RuntimeError class.
Definition: exceptions.h:219
ElementName ValueType
Definition: serializablekeyvaluemap.h:198
void insert(const QString &key, const typename T::ValueType &value) noexcept
Definition: serializablekeyvaluemap.h:145
T getValueByPath(const QString &path, bool throwIfEmpty=false) const
Definition: sexpression.h:101
Definition: serializablekeyvaluemap.h:197
tl::optional< typename T::ValueType > tryGet(const QString &key) const noexcept
Definition: serializablekeyvaluemap.h:114
The Signal class is used to emit signals on non-QObject derived classes.
Definition: signalslot.h:65
bool operator==(const SerializableKeyValueMap< T > &rhs) const noexcept
Definition: serializablekeyvaluemap.h:182
Signal< SerializableKeyValueMap< T >, const QString &, Event > onEdited
Definition: serializablekeyvaluemap.h:65
const T::ValueType & value(const QStringList &keyOrder, QString *usedKey=nullptr) const noexcept
Definition: serializablekeyvaluemap.h:123
static constexpr const char * keyname
Definition: serializablekeyvaluemap.h:211
Definition: serializablekeyvaluemap.h:208
void setDefaultValue(const typename T::ValueType &value) noexcept
Definition: serializablekeyvaluemap.h:141
static constexpr const char * keyname
Definition: serializablekeyvaluemap.h:223
SerializableKeyValueMap(const SerializableKeyValueMap< T > &other) noexcept
Definition: serializablekeyvaluemap.h:70
The Slot class is used to receive signals from non-QObject derived classes.
Definition: signalslot.h:36
The SExpression class.
Definition: sexpression.h:57
SerializableKeyValueMap(const typename T::ValueType &defaultValue) noexcept
Definition: serializablekeyvaluemap.h:72
The SerializableKeyValueMap class provides an easy way to serialize and deserialize ordered key value...
Definition: serializablekeyvaluemap.h:55
type_safe::constrained_type< QString, ElementNameConstraint, ElementNameVerifier > ElementName
Definition: elementname.h:92