Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_properties_configuration.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006 Boudewijn Rempt <boud@valdyas.org>
3 * SPDX-FileCopyrightText: 2007, 2010 Cyrille Berger <cberger@cberger.net>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
9
10
11#include <kis_debug.h>
12#include <QDomDocument>
13#include <QString>
14
15#include "kis_image.h"
16#include "kis_transaction.h"
17#include "kis_undo_adapter.h"
18#include "kis_painter.h"
19#include "kis_selection.h"
20#include "KoID.h"
21#include "kis_types.h"
22#include <KoColor.h>
25
26struct Q_DECL_HIDDEN KisPropertiesConfiguration::Private {
27 QMap<QString, QVariant> properties;
28 QSet<QString> notSavedProperties;
29};
30
34
39
45
47{
48 if (&rhs != this) {
49 *d = *rhs.d;
50 }
51
52 return *this;
53}
54
55bool KisPropertiesConfiguration::fromXML(const QString & xml, bool clear)
56{
57 if (clear) {
59 }
60
61 QDomDocument doc;
62 bool retval = bool(doc.setContent(xml));
63 if (retval) {
64 QDomElement e = doc.documentElement();
65 fromXML(e);
66 }
67 return retval;
68}
69
70void KisPropertiesConfiguration::fromXML(const QDomElement &root)
71{
72 QDomElement e;
73 for (e = root.firstChildElement("param"); !e.isNull(); e = e.nextSiblingElement("param")) {
74 QString name = e.attribute("name");
75 QString value = e.text();
77 // Older versions didn't have a "type" parameter,
78 // so fall back to the old behavior if it's missing.
79 if (!e.hasAttribute("type")) {
80 d->properties[name] = QVariant(value);
81 } else if (e.attribute("type") == "bytearray") {
82 d->properties[name] = QVariant(QByteArray::fromBase64(value.toLatin1()));
83 } else {
84 d->properties[name] = value;
85 }
86 }
87}
88
89void KisPropertiesConfiguration::toXML(QDomDocument& doc, QDomElement& root) const
90{
91 QMap<QString, QVariant>::ConstIterator it;
92 for (it = d->properties.constBegin(); it != d->properties.constEnd(); ++it) {
93 if (d->notSavedProperties.contains(it.key())) {
94 continue;
95 }
96
97 QDomElement e = doc.createElement("param");
98 e.setAttribute("name", QString(it.key().toLatin1()));
99 QString type = "string";
100 QVariant v = it.value();
101 QDomText text;
102 if (v.type() == QVariant::UserType && v.userType() == qMetaTypeId<KisCubicCurve>()) {
103 text = doc.createCDATASection(v.value<KisCubicCurve>().toString());
104 } else if (v.type() == QVariant::UserType && v.userType() == qMetaTypeId<KoColor>()) {
105 QDomDocument cdataDoc = QDomDocument("color");
106 QDomElement cdataRoot = cdataDoc.createElement("color");
107 cdataDoc.appendChild(cdataRoot);
108 v.value<KoColor>().toXML(cdataDoc, cdataRoot);
109 text = cdataDoc.createCDATASection(cdataDoc.toString());
110 type = "color";
111 } else if(v.type() == QVariant::String ) {
112 text = doc.createCDATASection(v.toString()); // XXX: Unittest this!
113 type = "string";
114 } else if(v.type() == QVariant::ByteArray ) {
115 text = doc.createTextNode(QString::fromLatin1(v.toByteArray().toBase64())); // Arbitrary Data
116 type = "bytearray";
117 } else {
118 text = doc.createTextNode(v.toString());
119 type = "internal";
120 }
121 e.setAttribute("type", type);
122 e.appendChild(text);
123 root.appendChild(e);
124 }
125}
126
128{
129 QDomDocument doc = QDomDocument("params");
130 QDomElement root = doc.createElement("params");
131 doc.appendChild(root);
132 toXML(doc, root);
133 return doc.toString();
134}
135
136
137bool KisPropertiesConfiguration::hasProperty(const QString& name) const
138{
139 return d->properties.contains(name);
140}
141
142void KisPropertiesConfiguration::setProperty(const QString & name, const QVariant & value)
143{
144 if (d->properties.find(name) == d->properties.end()) {
145 d->properties.insert(name, value);
146 } else {
147 d->properties[name] = value;
148 }
149}
150
151bool KisPropertiesConfiguration::getProperty(const QString & name, QVariant & value) const
152{
153 if (d->properties.constFind(name) == d->properties.constEnd()) {
154 return false;
155 } else {
156 value = d->properties.value(name);
157 return true;
158 }
159}
160
161QVariant KisPropertiesConfiguration::getProperty(const QString & name) const
162{
163 return d->properties.value(name, QVariant());
164}
165
166
167int KisPropertiesConfiguration::getInt(const QString & name, int def) const
168{
169 QVariant v = getProperty(name);
170 if (v.isValid())
171 return v.toInt();
172 else
173 return def;
174
175}
176
177double KisPropertiesConfiguration::getDouble(const QString & name, double def) const
178{
179 QVariant v = getProperty(name);
180 if (v.isValid())
181 return v.toDouble();
182 else
183 return def;
184}
185
186float KisPropertiesConfiguration::getFloat(const QString & name, float def) const
187{
188 QVariant v = getProperty(name);
189 if (v.isValid())
190 return (float)v.toDouble();
191 else
192 return def;
194
195
196bool KisPropertiesConfiguration::getBool(const QString & name, bool def) const
197{
198 QVariant v = getProperty(name);
199 if (v.isValid())
200 return v.toBool();
201 else
202 return def;
203}
204
205QString KisPropertiesConfiguration::getString(const QString & name, const QString & def) const
206{
207 QVariant v = getProperty(name);
208 if (v.isValid())
209 return v.toString();
210 else
211 return def;
212}
213
215{
216 QVariant v = getProperty(name);
217 if (v.isValid()) {
218 if (v.type() == QVariant::UserType && v.userType() == qMetaTypeId<KisCubicCurve>()) {
219 return v.value<KisCubicCurve>();
220 } else {
221 return KisCubicCurve(v.toString());
222 }
223 } else
224 return curve;
225}
226
227KoColor KisPropertiesConfiguration::getColor(const QString& name, const KoColor& color) const
228{
229 QVariant v = getProperty(name);
230
231 if (v.isValid()) {
232 switch(v.type()) {
233 case QVariant::UserType:
234 {
235 if (v.userType() == qMetaTypeId<KoColor>()) {
236 return v.value<KoColor>();
237 }
238 break;
239 }
240 case QVariant::String:
241 {
242 QDomDocument doc;
243 if (doc.setContent(v.toString())) {
244 QDomElement e = doc.documentElement().firstChild().toElement();
245 bool ok;
247 if (ok) {
248 return c;
249 }
250 }
251 else {
252 QColor c(v.toString());
253 if (c.isValid()) {
255 return kc;
256 }
257 }
258 break;
259 }
260 case QVariant::Color:
261 {
262 QColor c = v.value<QColor>();
264 return kc;
265 }
266 case QVariant::Int:
267 {
268 QColor c(v.toInt());
269 if (c.isValid()) {
271 return kc;
272 }
273 break;
274 }
275 default:
276 ;
277 }
278 }
279 return color;
280}
281
283{
284 QMap<QString, QVariant>::ConstIterator it;
285 for (it = d->properties.constBegin(); it != d->properties.constEnd(); ++it) {
286 if (it->type() == QVariant::ByteArray) {
287 QByteArray ba = it->toByteArray();
288
289 if (ba.size() > 32) {
290 qDebug() << it.key() << " = " << QString("...skipped total %1 bytes...").arg(ba.size()) << it.value().typeName();
291 } else {
292 qDebug() << it.key() << " = " << it.value() << it.value().typeName();
293 }
294 } else {
295 qDebug() << it.key() << " = " << it.value() << it.value().typeName();
296 }
297 }
298
299}
300
302{
303 d->properties.clear();
304}
305
307{
308 d->notSavedProperties.insert(name);
309}
310
311QMap<QString, QVariant> KisPropertiesConfiguration::getProperties() const
312{
313 return d->properties;
314}
315
317{
318 d->properties.remove(name);
319}
320
322{
323 return d->properties.keys();
324}
325
327{
328 const int prefixSize = prefix.size();
329
330 const QList<QString> keys = getPropertiesKeys();
331 Q_FOREACH (const QString &key, keys) {
332 if (key.startsWith(prefix)) {
333 config->setProperty(key.mid(prefixSize), getProperty(key));
334 }
335 }
336
337 QString fullPrefix;
338 const QString parentPrefix = getString(extractedPrefixKey());
339 if (!parentPrefix.isEmpty()) {
340 fullPrefix = parentPrefix + "/" + prefix;
341 } else {
342 fullPrefix = prefix;
343 }
344
345 config->setProperty(extractedPrefixKey(), fullPrefix);
347}
348
350{
351 getPrefixedProperties(prefix, config.data());
352}
353
355{
356 const QList<QString> keys = config->getPropertiesKeys();
357 Q_FOREACH (const QString &key, keys) {
358 this->setProperty(prefix + key, config->getProperty(key));
359 }
360}
361
363{
364 setPrefixedProperties(prefix, config.data());
365}
366
368{
369 static const QString key = "__extractedFromPrefix";
370 return key;
371}
372
373QString KisPropertiesConfiguration::escapeString(const QString &string)
374{
375 QString result = string;
376 result.replace(";", "\\;");
377 result.replace("]", "\\]");
378 result.replace(">", "\\>");
379 return result;
380}
381
382QString KisPropertiesConfiguration::unescapeString(const QString &string)
383{
384 QString result = string;
385 result.replace("\\;", ";");
386 result.replace("\\]", "]");
387 result.replace("\\>", ">");
388 return result;
389}
390
392{
393 QStringList escapedList;
394 escapedList.reserve(value.size());
395
396 Q_FOREACH (const QString &str, value) {
397 escapedList << escapeString(str);
398 }
399
400 setProperty(name, escapedList.join(';'));
401}
402
403QStringList KisPropertiesConfiguration::getStringList(const QString &name, const QStringList &defaultValue) const
404{
405 if (!hasProperty(name)) return defaultValue;
406
407 const QString joined = getString(name);
408
409 QStringList result;
410
411 int afterLastMatch = -1;
412 for (int i = 0; i < joined.size(); i++) {
413 const bool lastChunk = i == joined.size() - 1;
414 const bool matchedSplitter = joined[i] == ';' && (i == 0 || joined[i - 1] != '\\');
415
416 if (lastChunk || matchedSplitter) {
417 result << unescapeString(joined.mid(afterLastMatch, i - afterLastMatch + int(lastChunk && !matchedSplitter)));
418 afterLastMatch = i + 1;
419 }
420
421 if (lastChunk && matchedSplitter) {
422 result << QString();
423 }
424 }
425
426 return result;
427}
428
429QStringList KisPropertiesConfiguration::getPropertyLazy(const QString &name, const QStringList &defaultValue) const
430{
431 return getStringList(name, defaultValue);
432}
433
435{
436 if (rhs == nullptr)
437 return false;
438
439 for(const auto& propertyName: getPropertiesKeys()) {
440 if (getProperty(propertyName) != rhs->getProperty(propertyName))
441 return false;
442 }
443
444 return true;
445}
446
447// --- factory ---
448
450};
451
455
460
465
467{
469 pc->fromXML(e);
470 return pc;
471}
472
float value(const T *src, size_t ch)
qreal v
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
static KoColor fromXML(const QDomElement &elt, const QString &channelDepthId)
Definition KoColor.cpp:350
QString id() const
Definition KoID.cpp:63
QString toString() const
KisSerializableConfigurationSP create(const QDomElement &e) override
KisSerializableConfigurationSP createDefault() override
void setPropertyNotSaved(const QString &name)
Marks a property that should not be saved by toXML.
static QString unescapeString(const QString &string)
void setPrefixedProperties(const QString &prefix, const KisPropertiesConfiguration *config)
QString getString(const QString &name, const QString &def=QString()) const
bool fromXML(const QString &xml, bool clear=true) override
void clearProperties()
Clear the map of properties.
virtual bool hasProperty(const QString &name) const
static QString escapeString(const QString &string)
virtual void setProperty(const QString &name, const QVariant &value)
bool getBool(const QString &name, bool def=false) const
KoColor getColor(const QString &name, const KoColor &color=KoColor()) const
getColor fetch the given property as a KoColor.
QStringList getStringList(const QString &name, const QStringList &defaultValue=QStringList()) const
KisCubicCurve getCubicCurve(const QString &name, const KisCubicCurve &curve=KisCubicCurve()) const
int getInt(const QString &name, int def=0) const
double getDouble(const QString &name, double def=0.0) const
virtual bool compareTo(const KisPropertiesConfiguration *rhs) const
float getFloat(const QString &name, float def=0.0) const
void getPrefixedProperties(const QString &prefix, KisPropertiesConfiguration *config) const
virtual bool getProperty(const QString &name, QVariant &value) const
virtual QList< QString > getPropertiesKeys() const
KisPropertiesConfiguration & operator=(const KisPropertiesConfiguration &rhs)
virtual QMap< QString, QVariant > getProperties() const
T getPropertyLazy(const QString &name, const T &defaultValue) const
static KoColorSpaceRegistry * instance()