File indexing completed on 2024-05-12 15:56:57
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef __KIS_DOM_UTILS_H 0008 #define __KIS_DOM_UTILS_H 0009 0010 #include <float.h> 0011 0012 #include <QPointF> 0013 #include <QVector3D> 0014 #include <QVector> 0015 #include <QDomElement> 0016 #include <QLocale> 0017 #include <QColor> 0018 0019 #include <klocalizedstring.h> 0020 0021 #include "kritaglobal_export.h" 0022 #include "kis_debug.h" 0023 #include "krita_container_utils.h" 0024 0025 namespace KisDomUtils { 0026 0027 inline QString toString(const QString &value) { 0028 return value; 0029 } 0030 0031 template<typename T> 0032 inline QString toString(T value) { 0033 return QString::number(value); 0034 } 0035 0036 inline QString toString(float value) { 0037 QString str; 0038 QTextStream stream; 0039 stream.setCodec("UTF-8"); 0040 stream.setString(&str, QIODevice::WriteOnly); 0041 stream.setRealNumberPrecision(FLT_DIG); 0042 stream << value; 0043 return str; 0044 } 0045 0046 inline QString toString(double value) { 0047 QString str; 0048 QTextStream stream; 0049 stream.setCodec("UTF-8"); 0050 stream.setString(&str, QIODevice::WriteOnly); 0051 stream.setRealNumberPrecision(15); 0052 stream << value; 0053 return str; 0054 } 0055 0056 inline int toInt(const QString &str, bool *ok=nullptr) { 0057 bool ok_locale = false; 0058 int value = 0; 0059 0060 QLocale c(QLocale::German); 0061 0062 value = str.toInt(&ok_locale); 0063 if (!ok_locale) { 0064 value = c.toInt(str, &ok_locale); 0065 } 0066 0067 if (!ok_locale && ok == nullptr) { 0068 warnKrita << "WARNING: KisDomUtils::toInt failed:" << ppVar(str); 0069 value = 0; 0070 } 0071 0072 if (ok != nullptr) { 0073 *ok = ok_locale; 0074 } 0075 0076 return value; 0077 } 0078 0079 inline double toDouble(const QString &str, bool *ok=nullptr) { 0080 bool ok_locale = false; 0081 double value = 0; 0082 0083 QLocale c(QLocale::German); 0084 0085 /** 0086 * A special workaround to handle ','/'.' decimal point 0087 * in different locales. Added for backward compatibility, 0088 * because we used to save qreals directly using 0089 * 0090 * e.setAttribute("w", (qreal)value), 0091 * 0092 * which did local-aware conversion. 0093 */ 0094 0095 value = str.toDouble(&ok_locale); 0096 if (!ok_locale) { 0097 value = c.toDouble(str, &ok_locale); 0098 } 0099 0100 if (!ok_locale && ok == nullptr) { 0101 warnKrita << "WARNING: KisDomUtils::toDouble failed:" << ppVar(str); 0102 value = 0.0; 0103 } 0104 0105 if (ok != nullptr) { 0106 *ok = ok_locale; 0107 } 0108 0109 return value; 0110 } 0111 0112 0113 inline QString qColorToQString(QColor color) 0114 { 0115 // color channels will usually have 0-255 0116 QString customColor = QString::number(color.red()).append(",") 0117 .append(QString::number(color.green())).append(",") 0118 .append(QString::number(color.blue())).append(",") 0119 .append(QString::number(color.alpha())); 0120 0121 return customColor; 0122 } 0123 0124 inline QColor qStringToQColor(QString colorString) 0125 { 0126 QStringList colorComponents = colorString.split(','); 0127 return QColor(colorComponents[0].toInt(), colorComponents[1].toInt(), colorComponents[2].toInt(), colorComponents[3].toInt()); 0128 } 0129 0130 0131 0132 0133 /** 0134 * Save a value of type QRect into an XML tree. A child for \p parent 0135 * is created and assigned a tag \p tag. The corresponding value can 0136 * be fetched from the XML using loadValue() later. 0137 * 0138 * \see loadValue() 0139 */ 0140 void KRITAGLOBAL_EXPORT saveValue(QDomElement *parent, const QString &tag, const QRect &rc); 0141 void KRITAGLOBAL_EXPORT saveValue(QDomElement *parent, const QString &tag, const QRectF &rc); 0142 void KRITAGLOBAL_EXPORT saveValue(QDomElement *parent, const QString &tag, const QSize &size); 0143 void KRITAGLOBAL_EXPORT saveValue(QDomElement *parent, const QString &tag, const QPoint &pt); 0144 void KRITAGLOBAL_EXPORT saveValue(QDomElement *parent, const QString &tag, const QPointF &pt); 0145 void KRITAGLOBAL_EXPORT saveValue(QDomElement *parent, const QString &tag, const QVector3D &pt); 0146 void KRITAGLOBAL_EXPORT saveValue(QDomElement *parent, const QString &tag, const QTransform &t); 0147 void KRITAGLOBAL_EXPORT saveValue(QDomElement *parent, const QString &tag, const QColor &t); 0148 0149 /** 0150 * Save a value of a scalar type into an XML tree. A child for \p parent 0151 * is created and assigned a tag \p tag. The corresponding value can 0152 * be fetched from the XML using loadValue() later. 0153 * 0154 * \see loadValue() 0155 */ 0156 template <typename T> 0157 void saveValue(QDomElement *parent, const QString &tag, T value) 0158 { 0159 QDomDocument doc = parent->ownerDocument(); 0160 QDomElement e = doc.createElement(tag); 0161 parent->appendChild(e); 0162 0163 e.setAttribute("type", "value"); 0164 e.setAttribute("value", toString(value)); 0165 } 0166 0167 /** 0168 * Save a vector of values into an XML tree. A child for \p parent is 0169 * created and assigned a tag \p tag. The values in the array should 0170 * have a type supported by saveValue() overrides. The corresponding 0171 * vector can be fetched from the XML using loadValue() later. 0172 * 0173 * \see loadValue() 0174 */ 0175 template <template <class...> class Container, typename T, typename ...Args> 0176 typename std::enable_if<KritaUtils::is_container<Container<T, Args...>>::value, void>::type 0177 saveValue(QDomElement *parent, const QString &tag, const Container<T, Args...> &array) 0178 { 0179 QDomDocument doc = parent->ownerDocument(); 0180 QDomElement e = doc.createElement(tag); 0181 parent->appendChild(e); 0182 0183 e.setAttribute("type", "array"); 0184 0185 int i = 0; 0186 Q_FOREACH (const T &v, array) { 0187 saveValue(&e, QString("item_%1").arg(i++), v); 0188 } 0189 } 0190 0191 /** 0192 * Find an element with tag \p tag which is a child of \p parent. The element should 0193 * be the only element with the provided tag in this parent. 0194 * 0195 * \return true is the element with \p tag is found and it is unique 0196 */ 0197 bool KRITAGLOBAL_EXPORT findOnlyElement(const QDomElement &parent, const QString &tag, QDomElement *el, QStringList *errorMessages = 0); 0198 0199 0200 /** 0201 * Load an object from an XML element, which is a child of \p parent and has 0202 * a tag \p tag. 0203 * 0204 * \return true if the object is successfully loaded and is unique 0205 * 0206 * \see saveValue() 0207 */ 0208 bool KRITAGLOBAL_EXPORT loadValue(const QDomElement &e, float *v); 0209 bool KRITAGLOBAL_EXPORT loadValue(const QDomElement &e, double *v); 0210 bool KRITAGLOBAL_EXPORT loadValue(const QDomElement &e, QSize *size); 0211 bool KRITAGLOBAL_EXPORT loadValue(const QDomElement &e, QRect *rc); 0212 bool KRITAGLOBAL_EXPORT loadValue(const QDomElement &e, QRectF *rc); 0213 bool KRITAGLOBAL_EXPORT loadValue(const QDomElement &e, QPoint *pt); 0214 bool KRITAGLOBAL_EXPORT loadValue(const QDomElement &e, QPointF *pt); 0215 bool KRITAGLOBAL_EXPORT loadValue(const QDomElement &e, QVector3D *pt); 0216 bool KRITAGLOBAL_EXPORT loadValue(const QDomElement &e, QTransform *t); 0217 bool KRITAGLOBAL_EXPORT loadValue(const QDomElement &e, QString *value); 0218 bool KRITAGLOBAL_EXPORT loadValue(const QDomElement &e, QColor *value); 0219 0220 0221 namespace Private { 0222 bool KRITAGLOBAL_EXPORT checkType(const QDomElement &e, const QString &expectedType); 0223 } 0224 0225 0226 /** 0227 * Load a scalar value from an XML element, which is a child of \p parent 0228 * and has a tag \p tag. 0229 * 0230 * \return true if the object is successfully loaded and is unique 0231 * 0232 * \see saveValue() 0233 */ 0234 template <typename T> 0235 typename std::enable_if<std::is_arithmetic<T>::value, bool>::type 0236 loadValue(const QDomElement &e, T *value) 0237 { 0238 if (!Private::checkType(e, "value")) return false; 0239 0240 QVariant v(e.attribute("value", "no-value")); 0241 *value = v.value<T>(); 0242 return true; 0243 } 0244 0245 /** 0246 * A special adapter method that makes vector- and tag-based methods 0247 * work with environment parameter uniformly. 0248 */ 0249 template <typename T, typename E> 0250 typename std::enable_if<std::is_empty<E>::value, bool>::type 0251 loadValue(const QDomElement &parent, T *value, const E &/*env*/) { 0252 return loadValue(parent, value); 0253 } 0254 0255 /** 0256 * Load an array from an XML element, which is a child of \p parent 0257 * and has a tag \p tag. 0258 * 0259 * \return true if the object is successfully loaded and is unique 0260 * 0261 * \see saveValue() 0262 */ 0263 0264 template <template <class ...> class Container, typename T, typename E, typename ...Args> 0265 typename std::enable_if<KritaUtils::is_appendable_container<Container<T, Args...>>::value, bool>::type 0266 loadValue(const QDomElement &e, Container<T, Args...> *array, const E &env = std::tuple<>()) 0267 { 0268 if (!Private::checkType(e, "array")) return false; 0269 0270 QDomElement child = e.firstChildElement(); 0271 while (!child.isNull()) { 0272 T value; 0273 if (!loadValue(child, &value, env)) return false; 0274 array->push_back(value); 0275 child = child.nextSiblingElement(); 0276 } 0277 return true; 0278 } 0279 0280 template <template <class ...> class Container, typename T, typename E, typename F, typename ...Args> 0281 typename std::enable_if<KritaUtils::is_appendable_container<Container<T, Args...>>::value, bool>::type 0282 loadValue(const QDomElement &e, Container<T, Args...> *array, const E &env1, const F &env2) 0283 { 0284 if (!Private::checkType(e, "array")) return false; 0285 0286 QDomElement child = e.firstChildElement(); 0287 while (!child.isNull()) { 0288 T value; 0289 if (!loadValue(child, &value, env1, env2)) return false; 0290 array->push_back(value); 0291 child = child.nextSiblingElement(); 0292 } 0293 return true; 0294 } 0295 0296 template <typename T, typename E = std::tuple<>> 0297 bool loadValue(const QDomElement &parent, const QString &tag, T *value, const E &env = E()) 0298 { 0299 QDomElement e; 0300 if (!findOnlyElement(parent, tag, &e)) return false; 0301 0302 return loadValue(e, value, env); 0303 } 0304 0305 template <typename T, typename E, typename F> 0306 bool loadValue(const QDomElement &parent, const QString &tag, T *value, const E &env1, const F &env2) 0307 { 0308 QDomElement e; 0309 if (!findOnlyElement(parent, tag, &e)) return false; 0310 0311 return loadValue(e, value, env1, env2); 0312 } 0313 0314 0315 KRITAGLOBAL_EXPORT QDomElement findElementByAttibute(QDomNode parent, 0316 const QString &tag, 0317 const QString &attribute, 0318 const QString &key); 0319 0320 KRITAGLOBAL_EXPORT bool removeElements(QDomElement &parent, const QString &tag); 0321 0322 } 0323 0324 #endif /* __KIS_DOM_UTILS_H */