diff --git a/sources/properties/userproperties.cpp b/sources/properties/userproperties.cpp
new file mode 100644
index 000000000..549bda8e4
--- /dev/null
+++ b/sources/properties/userproperties.cpp
@@ -0,0 +1,210 @@
+/*
+ Copyright 2006-2021 The QElectroTech Team
+ This file is part of QElectroTech.
+
+ QElectroTech is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ QElectroTech is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QElectroTech. If not, see .
+*/
+#include "userproperties.h"
+#include "../qetxml.h"
+
+#include
+#include
+
+/**
+ * @brief UserProperties::UserProperties
+ * @param tag_name
+ */
+UserProperties::UserProperties(const QString tag_name) :
+ m_tag_name(tag_name)
+{}
+
+/**
+ * @brief UserProperties::toXml
+ * @param xml_document
+ * @return A QDomElement who contain one child for each user properties
+ * the tag name of the returned domElement is "userProperties" by default
+ * If you want to change the tag name, see setTagName and tagName function.
+ */
+QDomElement UserProperties::toXml(QDomDocument &xml_document) const
+{
+ QDomElement up = xml_document.createElement(m_tag_name);
+ if (m_properties.count() == 0)
+ return up;
+
+ for (auto i = m_properties.begin(); i != m_properties.end(); ++i)
+ {
+ auto type = i.value().type();
+ switch(type) {
+ case QVariant::Type::String:
+ up.appendChild(QETXML::createXmlProperty(i.key(), i.value().toString())); break;
+ case QVariant::Type::Int:
+ up.appendChild(QETXML::createXmlProperty(i.key(), i.value().toInt())); break;
+ case QVariant::Type::Double:
+ up.appendChild(QETXML::createXmlProperty(i.key(), i.value().toDouble())); break;
+ case QVariant::Type::Bool:
+ up.appendChild(QETXML::createXmlProperty(i.key(), i.value().toBool())); break;
+ case QVariant::Type::Color:
+ up.appendChild(QETXML::createXmlProperty(i.key(), QColor(i.value().value()))); break;
+ default:
+ break;
+ }
+ }
+
+ return up;
+}
+
+/**
+ * @brief UserProperties::fromXml
+ * @param xml_element
+ * @return load user properties from xml
+ * Take car befor use this function that the tagName of this class
+ * is the same as the tag of xml_element given in parameter.
+ */
+bool UserProperties::fromXml(const QDomElement &xml_element)
+{
+ QDomNodeList l = xml_element.childNodes();
+ for (int i=0; i < l.count(); i++)
+ {
+ QDomElement userProperties = l.at(i).toElement();
+ if (userProperties.tagName() != m_tag_name)
+ continue;
+
+ QDomElement userProperty;
+ for (int up_index = 0; up_index < userProperties.childNodes().length(); up_index++)
+ {
+ userProperty = userProperties.childNodes().at(up_index).toElement();
+
+ QString name = userProperty.attribute("name");
+ QString type = userProperty.attribute("type");
+ QString value = userProperty.attribute("value");
+
+ if (type == QETXML::integerS)
+ {
+ int i;
+ if (QETXML::propertyInteger(value, &i) == QETXML::PropertyFlags::Success)
+ m_properties[name] = QVariant(i);
+ else
+ return false;
+ }
+ else if (type == QETXML::doubleS)
+ {
+ double d;
+ if (QETXML::propertyDouble(value, &d) == QETXML::PropertyFlags::Success)
+ m_properties[name] = QVariant(d);
+ else
+ return false;
+ }
+ else if (type == QETXML::boolS)
+ {
+ bool b;
+ if (QETXML::propertyBool(value, &b) == QETXML::PropertyFlags::Success)
+ m_properties[name] = QVariant(b);
+ else
+ return false;
+ }
+ else if (type == QETXML::uuidS)
+ {
+ QUuid u;
+ if (QETXML::propertyUuid(value, &u) == QETXML::PropertyFlags::Success)
+ m_properties[name] = QVariant(u);
+ else
+ return false;
+ }
+ else if (type == QETXML::colorS)
+ {
+ QColor c;
+ if (QETXML::propertyColor(value, &c) == QETXML::PropertyFlags::Success)
+ m_properties[name] = QVariant(c);
+ else
+ return false;
+ }
+ else if (type == QETXML::stringS)
+ {
+ m_properties[name] = QVariant(value);
+ }
+ else
+ {
+ qDebug() << "Not a valid property type!";
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ * @brief UserProperties::deleteUserProperties
+ * Delete all userproperties
+ */
+void UserProperties::deleteUserProperties() {
+ m_properties.clear();
+}
+
+/**
+ * @brief UserProperties::userPropertiesCount
+ * @return Returns the number of user properties
+ */
+int UserProperties::userPropertiesCount() const {
+ return m_properties.count();
+}
+
+/**
+ * @brief UserProperties::setUserProperty
+ * Adds a new property if \p key does not exist in the \p properties member,
+ * otherwise overwrite the value
+ * @param key
+ * @param value
+ */
+void UserProperties::setUserProperty(const QString &key, const QVariant &value) {
+ m_properties[key] = value;
+}
+
+/**
+ * @brief UserProperties::existUserProperty
+ * Checks if a user property with key \p key is available or not
+ * @param key
+ * @return true if property exist
+ */
+bool UserProperties::existUserProperty(const QString &key) const {
+ return m_properties.contains(key);
+}
+
+/**
+ * @brief UserProperties::userPropertyValue
+ * Returns the value of a user property with key \p key
+ * If \p key is not found, an invalid QVariant is returned.
+ * Use QVariant::type() to get the type of the value
+ * @param key
+ * @return
+ */
+QVariant UserProperties::userPropertyValue(const QString &key)
+{
+ if (!existUserProperty(key))
+ return QVariant();
+
+ return m_properties[key];
+}
+
+/**
+ * @brief UserProperties::setTagName
+ * Set the tag name use to store in xml
+ * @param tag_name
+ */
+void UserProperties::setTagName(const QString &tag_name) {
+ m_tag_name = tag_name;
+}
+
+QString UserProperties::tagName() const {
+ return m_tag_name;
+}
diff --git a/sources/properties/userproperties.h b/sources/properties/userproperties.h
new file mode 100644
index 000000000..0ac6617e1
--- /dev/null
+++ b/sources/properties/userproperties.h
@@ -0,0 +1,59 @@
+/*
+ Copyright 2006-2021 The QElectroTech Team
+ This file is part of QElectroTech.
+
+ QElectroTech is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ QElectroTech is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QElectroTech. If not, see .
+*/
+#ifndef USERPROPERTIES_H
+#define USERPROPERTIES_H
+
+#include "propertiesinterface.h"
+
+/**
+ * @brief The UserProperties class
+ * This class store user properties.
+ * User properties are properties set by user
+ * who are don't know by QElectroTech.
+ * An user property is defined by a name and a value
+ * of arbitrarie type (QString, char*, int, double, bool, QUuid, QColor)
+ */
+class UserProperties : public PropertiesInterface
+{
+ public:
+ UserProperties(const QString tag_name = "userProperties");
+
+ virtual void toSettings (QSettings &,
+ const QString = QString()) const override {}
+
+ virtual void fromSettings (const QSettings &,
+ const QString = QString()) override {}
+
+ virtual QDomElement toXml (QDomDocument &xml_document) const override;
+ virtual bool fromXml (const QDomElement &xml_element) override;
+
+ void deleteUserProperties();
+ int userPropertiesCount() const;
+ void setUserProperty(const QString& key, const QVariant& value);
+ bool existUserProperty(const QString& key) const;
+ QVariant userPropertyValue(const QString& key);
+
+ void setTagName(const QString& tag_name);
+ QString tagName() const;
+
+ private:
+ QHash m_properties;
+ QString m_tag_name;
+};
+
+#endif // USERPROPERTIES_H