LibrePCB Developers Documentation
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_CORE_SERIALIZABLEKEYVALUEMAP_H
21 #define LIBREPCB_CORE_SERIALIZABLEKEYVALUEMAP_H
22 
23 /*******************************************************************************
24  * Includes
25  ******************************************************************************/
26 #include "../exceptions.h"
27 #include "../types/elementname.h"
28 #include "../utils/signalslot.h"
29 #include "sexpression.h"
30 
31 #include <QtCore>
32 
33 #include <optional.hpp>
34 
35 /*******************************************************************************
36  * Namespace / Forward Declarations
37  ******************************************************************************/
38 namespace librepcb {
39 
40 /*******************************************************************************
41  * Class SerializableKeyValueMap
42  ******************************************************************************/
43 
55 template <typename T>
57  Q_DECLARE_TR_FUNCTIONS(SerializableKeyValueMap)
58 
59 public:
60  // Signals
61  enum class Event {
65  };
68 
69  // Constructors / Destructor
70  SerializableKeyValueMap() = delete;
72  : onEdited(*this), mValues(other.mValues) {}
74  const typename T::ValueType& defaultValue) noexcept
75  : onEdited(*this) {
76  mValues.insert("", defaultValue);
77  }
78  explicit SerializableKeyValueMap(const SExpression& node) : onEdited(*this) {
79  foreach (const SExpression* child, node.getChildren(T::tagname)) {
80  QString key;
82  if (child->getChild("@0").isList()) {
83  key = child->getChild(QString(T::keyname) % "/@0").getValue();
84  value = child->getChild("@1");
85  } else {
86  key = QString("");
87  value = child->getChild("@0");
88  }
89  if (mValues.contains(key)) {
90  throw RuntimeError(__FILE__, __LINE__,
91  tr("Key \"%1\" defined multiple times.").arg(key));
92  }
93  mValues.insert(key,
94  deserialize<typename T::ValueType>(value)); // can throw
95  }
96  if (!mValues.contains(QString(""))) {
97  throw RuntimeError(__FILE__, __LINE__,
98  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);
152  onEdited.notify(key, Event::ElementValueChanged);
153  }
154  }
155 
161  void serialize(SExpression& root) const {
162  for (auto i = mValues.constBegin(); i != mValues.constEnd(); ++i) {
163  root.ensureLineBreak();
164  SExpression& child = root.appendList(T::tagname);
165  if (!i.key().isEmpty()) {
166  child.appendChild(T::keyname, i.key());
167  }
168  child.appendChild(i.value());
169  }
170  root.ensureLineBreak();
171  }
172 
173  // Operator Overloadings
175  const SerializableKeyValueMap<T>& rhs) noexcept {
176  foreach (const QString& key, mValues.keys()) {
177  mValues.remove(key);
178  onEdited.notify(key, Event::ElementRemoved);
179  }
180  mValues = rhs.mValues;
181  QMapIterator<QString, typename T::ValueType> i(rhs.mValues);
182  while (i.hasNext()) {
183  i.next();
184  insert(i.key(), i.value());
185  }
186  return *this;
187  }
188  bool operator==(const SerializableKeyValueMap<T>& rhs) const noexcept {
189  return mValues == rhs.mValues;
190  }
191  bool operator!=(const SerializableKeyValueMap<T>& rhs) const noexcept {
192  return mValues != rhs.mValues;
193  }
194 
195 private: // Data
196  QMap<QString, typename T::ValueType> mValues;
197 };
198 
199 /*******************************************************************************
200  * Class LocalizedNameMap
201  ******************************************************************************/
202 
205  static constexpr const char* tagname = "name";
206  static constexpr const char* keyname = "locale";
207 };
209 
210 /*******************************************************************************
211  * Class LocalizedDescriptionMap
212  ******************************************************************************/
213 
215  typedef QString ValueType;
216  static constexpr const char* tagname = "description";
217  static constexpr const char* keyname = "locale";
218 };
221 
222 /*******************************************************************************
223  * Class LocalizedKeywordsMap
224  ******************************************************************************/
225 
227  typedef QString ValueType;
228  static constexpr const char* tagname = "keywords";
229  static constexpr const char* keyname = "locale";
230 };
231 using LocalizedKeywordsMap =
233 
234 /*******************************************************************************
235  * End of File
236  ******************************************************************************/
237 
238 } // namespace librepcb
239 
240 #endif
SerializableKeyValueMap(const SExpression &node)
Definition: serializablekeyvaluemap.h:78
Slot< SerializableKeyValueMap< T >, const QString &, Event > OnEditedSlot
Definition: serializablekeyvaluemap.h:67
bool contains(const QString &key) const noexcept
Definition: serializablekeyvaluemap.h:111
const QList< SExpression > & getChildren() const noexcept
Get all children of this node.
Definition: sexpression.h:99
void ensureLineBreak()
Definition: sexpression.cpp:191
Definition: occmodel.cpp:76
QString ValueType
Definition: serializablekeyvaluemap.h:227
QStringList keys() const noexcept
Definition: serializablekeyvaluemap.h:104
SExpression & appendList(const QString &name)
Definition: sexpression.cpp:197
SExpression & getChild(const QString &path)
Get a child by path.
Definition: sexpression.cpp:120
bool isList() const noexcept
Definition: sexpression.h:86
QMap< QString, typename T::ValueType > mValues
Definition: serializablekeyvaluemap.h:196
QString ValueType
Definition: serializablekeyvaluemap.h:215
SerializableKeyValueMap< T > & operator=(const SerializableKeyValueMap< T > &rhs) noexcept
Definition: serializablekeyvaluemap.h:174
const T::ValueType & getDefaultValue() const noexcept
Definition: serializablekeyvaluemap.h:105
Definition: serializablekeyvaluemap.h:226
bool operator!=(const SerializableKeyValueMap< T > &rhs) const noexcept
Definition: serializablekeyvaluemap.h:191
~SerializableKeyValueMap() noexcept
Definition: serializablekeyvaluemap.h:101
The RuntimeError class.
Definition: exceptions.h:216
void notify(Args... args) noexcept
Notify all attached slots.
Definition: signalslot.h:123
ElementName ValueType
Definition: serializablekeyvaluemap.h:204
void insert(const QString &key, const typename T::ValueType &value) noexcept
Definition: serializablekeyvaluemap.h:145
Definition: serializablekeyvaluemap.h:203
tl::optional< typename T::ValueType > tryGet(const QString &key) const noexcept
Definition: serializablekeyvaluemap.h:114
SExpression & appendChild(const SExpression &child)
Definition: sexpression.cpp:201
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:188
Signal< SerializableKeyValueMap< T >, const QString &, Event > onEdited
Definition: serializablekeyvaluemap.h:66
const T::ValueType & value(const QStringList &keyOrder, QString *usedKey=nullptr) const noexcept
Definition: serializablekeyvaluemap.h:123
Definition: serializablekeyvaluemap.h:214
void setDefaultValue(const typename T::ValueType &value) noexcept
Definition: serializablekeyvaluemap.h:141
SerializableKeyValueMap(const SerializableKeyValueMap< T > &other) noexcept
Definition: serializablekeyvaluemap.h:71
const QString & getValue() const
Definition: sexpression.cpp:71
void serialize(SExpression &root) const
Serialize into librepcb::SExpression node.
Definition: serializablekeyvaluemap.h:161
The Slot class is used to receive signals from non-QObject derived classes.
Definition: signalslot.h:36
The SExpression class.
Definition: sexpression.h:66
SerializableKeyValueMap(const typename T::ValueType &defaultValue) noexcept
Definition: serializablekeyvaluemap.h:73
The SerializableKeyValueMap class provides an easy way to serialize and deserialize ordered key value...
Definition: serializablekeyvaluemap.h:56
type_safe::constrained_type< QString, ElementNameConstraint, ElementNameVerifier > ElementName
Definition: elementname.h:83