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 ******************************************************************************/
38namespace librepcb {
39
40/*******************************************************************************
41 * Class SerializableKeyValueMap
42 ******************************************************************************/
43
55template <typename T>
57 Q_DECLARE_TR_FUNCTIONS(SerializableKeyValueMap)
58
59public:
60 // Signals
61 enum class Event {
62 ElementAdded,
63 ElementRemoved,
64 ElementValueChanged,
65 };
68
69 // Constructors / Destructor
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(
115 const QString& key) const 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(
124 const QStringList& keyOrder, QString* usedKey = nullptr) const noexcept {
125 // search in the specified key order
126 foreach (const QString& key, keyOrder) {
127 auto i = mValues.find(key);
128 if ((i != mValues.end()) && (i.key() == key)) {
129 if (usedKey) *usedKey = key;
130 return i.value();
131 }
132 }
133 // use default value (empty key) as fallback
134 if (usedKey) *usedKey = QString("");
135 return getDefaultValue();
136 }
137
138 // General Methods
139
140 void setDefaultValue(const typename T::ValueType& value) noexcept {
141 insert(QString(""), value);
142 }
143
144 void insert(const QString& key, const typename T::ValueType& value) noexcept {
145 auto it = mValues.find(key);
146 if (it == mValues.end()) {
147 mValues.insert(key, value);
148 onEdited.notify(key, Event::ElementAdded);
149 } else if (it.value() != value) {
150 mValues.insert(key, value);
152 }
153 }
154
160 void serialize(SExpression& root) const {
161 for (auto i = mValues.constBegin(); i != mValues.constEnd(); ++i) {
162 root.ensureLineBreak();
163 SExpression& child = root.appendList(T::tagname);
164 if (!i.key().isEmpty()) {
165 child.appendChild(T::keyname, i.key());
166 }
167 child.appendChild(i.value());
168 }
169 root.ensureLineBreak();
170 }
171
172 // Operator Overloadings
174 const SerializableKeyValueMap<T>& rhs) noexcept {
175 foreach (const QString& key, mValues.keys()) {
176 mValues.remove(key);
177 onEdited.notify(key, Event::ElementRemoved);
178 }
179 mValues = rhs.mValues;
180 QMapIterator<QString, typename T::ValueType> i(rhs.mValues);
181 while (i.hasNext()) {
182 i.next();
183 insert(i.key(), i.value());
184 }
185 return *this;
186 }
187 bool operator==(const SerializableKeyValueMap<T>& rhs) const noexcept {
188 return mValues == rhs.mValues;
189 }
190 bool operator!=(const SerializableKeyValueMap<T>& rhs) const noexcept {
191 return mValues != rhs.mValues;
192 }
193
194private: // Data
195 QMap<QString, typename T::ValueType> mValues;
196};
197
198/*******************************************************************************
199 * Class LocalizedNameMap
200 ******************************************************************************/
201
204 static constexpr const char* tagname = "name";
205 static constexpr const char* keyname = "locale";
206};
208
209/*******************************************************************************
210 * Class LocalizedDescriptionMap
211 ******************************************************************************/
212
214 typedef QString ValueType;
215 static constexpr const char* tagname = "description";
216 static constexpr const char* keyname = "locale";
217};
220
221/*******************************************************************************
222 * Class LocalizedKeywordsMap
223 ******************************************************************************/
224
226 typedef QString ValueType;
227 static constexpr const char* tagname = "keywords";
228 static constexpr const char* keyname = "locale";
229};
232
233/*******************************************************************************
234 * End of File
235 ******************************************************************************/
236
237} // namespace librepcb
238
239#endif
The RuntimeError class.
Definition: exceptions.h:218
The SExpression class.
Definition: sexpression.h:69
SExpression & appendList(const QString &name)
Definition: sexpression.cpp:212
QList< SExpression * > getChildren(Type type) noexcept
Definition: sexpression.cpp:94
bool isList() const noexcept
Definition: sexpression.h:89
const QString & getValue() const
Definition: sexpression.cpp:71
void ensureLineBreak()
Definition: sexpression.cpp:206
SExpression & getChild(int index)
Definition: sexpression.cpp:86
void appendChild(std::unique_ptr< SExpression > child)
Definition: sexpression.cpp:217
The SerializableKeyValueMap class provides an easy way to serialize and deserialize ordered key value...
Definition: serializablekeyvaluemap.h:56
SerializableKeyValueMap(const SExpression &node)
Definition: serializablekeyvaluemap.h:78
void insert(const QString &key, const typename T::ValueType &value) noexcept
Definition: serializablekeyvaluemap.h:144
const T::ValueType & getDefaultValue() const noexcept
Definition: serializablekeyvaluemap.h:105
SerializableKeyValueMap(const typename T::ValueType &defaultValue) noexcept
Definition: serializablekeyvaluemap.h:73
SerializableKeyValueMap< T > & operator=(const SerializableKeyValueMap< T > &rhs) noexcept
Definition: serializablekeyvaluemap.h:173
Slot< SerializableKeyValueMap< T >, const QString &, Event > OnEditedSlot
Definition: serializablekeyvaluemap.h:67
QStringList keys() const noexcept
Definition: serializablekeyvaluemap.h:104
Event
Definition: serializablekeyvaluemap.h:61
Signal< SerializableKeyValueMap< T >, const QString &, Event > onEdited
Definition: serializablekeyvaluemap.h:66
QMap< QString, typename T::ValueType > mValues
Definition: serializablekeyvaluemap.h:195
SerializableKeyValueMap(const SerializableKeyValueMap< T > &other) noexcept
Definition: serializablekeyvaluemap.h:71
bool contains(const QString &key) const noexcept
Definition: serializablekeyvaluemap.h:111
void serialize(SExpression &root) const
Serialize into librepcb::SExpression node.
Definition: serializablekeyvaluemap.h:160
tl::optional< typename T::ValueType > tryGet(const QString &key) const noexcept
Definition: serializablekeyvaluemap.h:114
bool operator==(const SerializableKeyValueMap< T > &rhs) const noexcept
Definition: serializablekeyvaluemap.h:187
bool operator!=(const SerializableKeyValueMap< T > &rhs) const noexcept
Definition: serializablekeyvaluemap.h:190
~SerializableKeyValueMap() noexcept
Definition: serializablekeyvaluemap.h:101
const T::ValueType & value(const QStringList &keyOrder, QString *usedKey=nullptr) const noexcept
Definition: serializablekeyvaluemap.h:123
void setDefaultValue(const typename T::ValueType &value) noexcept
Definition: serializablekeyvaluemap.h:140
The Signal class is used to emit signals on non-QObject derived classes.
Definition: signalslot.h:65
The Slot class is used to receive signals from non-QObject derived classes.
Definition: signalslot.h:170
Definition: occmodel.cpp:77
type_safe::constrained_type< QString, ElementNameConstraint, ElementNameVerifier > ElementName
Definition: elementname.h:84
Definition: serializablekeyvaluemap.h:213
static constexpr const char * keyname
Definition: serializablekeyvaluemap.h:216
QString ValueType
Definition: serializablekeyvaluemap.h:214
static constexpr const char * tagname
Definition: serializablekeyvaluemap.h:215
Definition: serializablekeyvaluemap.h:225
static constexpr const char * keyname
Definition: serializablekeyvaluemap.h:228
QString ValueType
Definition: serializablekeyvaluemap.h:226
static constexpr const char * tagname
Definition: serializablekeyvaluemap.h:227
Definition: serializablekeyvaluemap.h:202
static constexpr const char * keyname
Definition: serializablekeyvaluemap.h:205
static constexpr const char * tagname
Definition: serializablekeyvaluemap.h:204
ElementName ValueType
Definition: serializablekeyvaluemap.h:203