Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_meta_data_value.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2007, 2010 Cyrille Berger <cberger@cberger.net>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6
8#include <QPoint>
9#include <QRegExp>
10#include <QTime>
11#include <QVariant>
12
13#include <klocalizedstring.h>
14
15#include <kis_debug.h>
16
17using namespace KisMetaData;
18
19struct Q_DECL_HIDDEN Value::Private {
20 Private() : type(Invalid) {}
21 union {
22 QVariant* variant;
24 QMap<QString, Value>* structure;
27 ValueType type;
28 QMap<QString, Value> propertyQualifiers;
29};
30
31Value::Value() : d(new Private)
32{
33 d->type = Invalid;
34}
35
36
37Value::Value(const QVariant& variant) : d(new Private)
38{
39 d->type = Value::Variant;
40 d->value.variant = new QVariant(variant);
41}
42
43Value::Value(const QList<Value>& array, ValueType type) : d(new Private)
44{
46 d->value.array = new QList<Value>(array);
47 d->type = type; // TODO: I am hesitating about LangArray to keep them as array or convert them to maps
48}
49
50Value::Value(const QMap<QString, Value>& structure) : d(new Private)
51{
52 d->type = Structure;
53 d->value.structure = new QMap<QString, Value>(structure);
54}
55
56Value::Value(const KisMetaData::Rational& signedRational) : d(new Private)
57{
58 d->type = Value::Rational;
59 d->value.rational = new KisMetaData::Rational(signedRational);
60}
61
62
63Value::Value(const Value& v) : d(new Private)
64{
65 d->type = Invalid;
66 *this = v;
67}
68
70{
71 d->type = v.d->type;
72 d->propertyQualifiers = v.d->propertyQualifiers;
73 switch (d->type) {
74 case Invalid:
75 break;
76 case Variant:
77 d->value.variant = new QVariant(*v.d->value.variant);
78 break;
79 case OrderedArray:
80 case UnorderedArray:
82 case LangArray:
83 d->value.array = new QList<Value>(*v.d->value.array);
84 break;
85 case Structure:
86 d->value.structure = new QMap<QString, Value>(*v.d->value.structure);
87 break;
88 case Rational:
89 d->value.rational = new KisMetaData::Rational(*v.d->value.rational);
90 }
91 return *this;
92}
93
94
96{
97 delete d;
98}
99
100void Value::addPropertyQualifier(const QString& _name, const Value& _value)
101{
102 d->propertyQualifiers[_name] = _value;
103}
104
105const QMap<QString, Value>& Value::propertyQualifiers() const
106{
107 return d->propertyQualifiers;
108}
109
111{
112 return d->type;
113}
114
115double Value::asDouble() const
116{
117 switch (type()) {
118 case Variant:
119 return d->value.variant->toDouble(0);
120 case Rational:
121 return d->value.rational->numerator / (double)d->value.rational->denominator;
122 default:
123 return 0.0;
124 }
125 return 0.0;
126}
127
129{
130 switch (type()) {
131 case Variant:
132 return d->value.variant->toInt(0);
133 case Rational:
134 return d->value.rational->numerator / d->value.rational->denominator;
135 default:
136 return 0;
137 }
138 return 0;
139}
140
141QVariant Value::asVariant() const
142{
143 switch (type()) {
144 case Variant:
145 return *d->value.variant;
146 case Rational:
147 return QVariant(QString("%1 / %2").arg(d->value.rational->numerator).arg(d->value.rational->denominator));
148 default: break;
149 }
150 return QVariant();
151}
152
153bool Value::setVariant(const QVariant& variant)
154{
155 switch (type()) {
157 *this = KisMetaData::Value(variant);
158 return true;
159 case Rational: {
160 QRegExp rx("([^\\/]*)\\/([^\\/]*)");
161 rx.indexIn(variant.toString());
162 // TODO: erm... did someone forgot to write actual code here?
163
164 // for now just safe assert and return a failure
165 KIS_SAFE_ASSERT_RECOVER_NOOP(0 && "Rational metadata values are not implemented!");
166 return false;
167 }
169 if (d->value.variant->type() == variant.type()) {
170 *d->value.variant = variant;
171 return true;
172 }
173 }
174 return true;
175 default:
176 break;
177 }
178 return false;
179}
180
181bool Value::setStructureVariant(const QString& fieldNAme, const QVariant& variant)
182{
183 if (type() == Structure) {
184 return (*d->value.structure)[fieldNAme].setVariant(variant);
185 }
186 return false;
187}
188
189bool Value::setArrayVariant(int index, const QVariant& variant)
190{
191 if (isArray()) {
192 for (int i = d->value.array->size(); i <= index; ++i) {
193 d->value.array->append(Value());
194 }
195 (*d->value.array)[index].setVariant(variant);
196 }
197 return false;
198}
199
201{
202 if (d->type == Rational) {
203 return *d->value.rational;
204 }
205 return KisMetaData::Rational();
206}
207
209{
210 if (isArray()) {
211 return *d->value.array;
212 }
213 return QList<Value>();
214}
215
216
217bool Value::isArray() const
218{
219 return type() == OrderedArray || type() == UnorderedArray || type() == AlternativeArray;
220}
221
222QMap<QString, KisMetaData::Value> Value::asStructure() const
223{
224 if (type() == Structure) {
225 return *d->value.structure;
226 }
227 return QMap<QString, KisMetaData::Value>();
228}
229
230QDebug operator<<(QDebug debug, const Value &v)
231{
232 switch (v.type()) {
233 case Value::Invalid:
234 debug.nospace() << "invalid value";
235 break;
236 case Value::Variant:
237 debug.nospace() << "Variant: " << v.asVariant();
238 break;
242 case Value::LangArray:
243 debug.nospace() << "Array: " << v.asArray();
244 break;
245 case Value::Structure:
246 debug.nospace() << "Structure: " << v.asStructure();
247 break;
248 case Value::Rational:
249 debug.nospace() << "Rational: " << v.asRational().numerator << " / " << v.asRational().denominator;
250 break;
251 }
252 return debug.space();
253}
254
255bool Value::operator==(const Value& rhs) const
256{
257 if (d->type != rhs.d->type) return false;
258 switch (d->type) {
259 case Value::Invalid:
260 return true;
261 case Value::Variant:
262 return asVariant() == rhs.asVariant();
266 case Value::LangArray:
267 return asArray() == rhs.asArray();
268 case Value::Structure:
269 return asStructure() == rhs.asStructure();
270 case Value::Rational:
271 return asRational() == rhs.asRational();
272 }
273 return false;
274}
275
277{
278 switch (d->type) {
279 case Value::Invalid:
280 Q_ASSERT(v.type() == Value::Invalid);
281 break;
282 case Value::Variant:
283 Q_ASSERT(v.type() == Value::Variant);
284 {
285 QVariant v1 = *d->value.variant;
286 QVariant v2 = *v.d->value.variant;
287 Q_ASSERT(v2.canConvert(v1.type()));
288 switch (v1.type()) {
289 default:
290 warnMetaData << "KisMetaData: Merging metadata of type" << v1.type() << "is unsupported!";
291 break;
292 case QVariant::Date:
293 *d->value.variant = qMax(v1.toDate(), v2.toDate());
294 break;
295 case QVariant::DateTime:
296 *d->value.variant = qMax(v1.toDate(), v2.toDate());
297 break;
298 case QVariant::Double:
299 *d->value.variant = v1.toDouble() + v2.toDouble();
300 break;
301 case QVariant::Int:
302 *d->value.variant = v1.toInt() + v2.toInt();
303 break;
304 case QVariant::List:
305 *d->value.variant = v1.toList() + v2.toList();
306 break;
307 case QVariant::LongLong:
308 *d->value.variant = v1.toLongLong() + v2.toLongLong();
309 break;
310 case QVariant::Point:
311 *d->value.variant = v1.toPoint() + v2.toPoint();
312 break;
313 case QVariant::PointF:
314 *d->value.variant = v1.toPointF() + v2.toPointF();
315 break;
316 case QVariant::String:
317 *d->value.variant = QVariant(v1.toString() + v2.toString());
318 break;
319 case QVariant::StringList:
320 *d->value.variant = v1.toStringList() + v2.toStringList();
321 break;
322 case QVariant::Time: {
323 QTime t1 = v1.toTime();
324 QTime t2 = v2.toTime();
325 int h = t1.hour() + t2.hour();
326 int m = t1.minute() + t2.minute();
327 int s = t1.second() + t2.second();
328 int ms = t1.msec() + t2.msec();
329 if (ms > 999) {
330 ms -= 999; s++;
331 }
332 if (s > 60) {
333 s -= 60; m++;
334 }
335 if (m > 60) {
336 m -= 60; h++;
337 }
338 if (h > 24) {
339 h -= 24;
340 }
341 *d->value.variant = QTime(h, m, s, ms);
342 }
343 break;
344 case QVariant::UInt:
345 *d->value.variant = v1.toUInt() + v2.toUInt();
346 break;
347 case QVariant::ULongLong:
348 *d->value.variant = v1.toULongLong() + v2.toULongLong();
349 break;
350 }
351
352 }
353 break;
357 if (v.isArray()) {
358 *(d->value.array) += *(v.d->value.array);
359 } else {
360 d->value.array->append(v);
361 }
362 }
363 break;
364 case Value::LangArray: {
365 Q_ASSERT(v.type() == Value::LangArray);
366 }
367 break;
368 case Value::Structure: {
369 Q_ASSERT(v.type() == Value::Structure);
370 break;
371 }
372 case Value::Rational: {
373 Q_ASSERT(v.type() == Value::Rational);
374 d->value.rational->numerator =
375 (d->value.rational->numerator
376 * v.d->value.rational->denominator)
377 + (v.d->value.rational->numerator
378 * d->value.rational->denominator);
379 d->value.rational->denominator *= v.d->value.rational->denominator;
380 break;
381 }
382 }
383 return *this;
384}
385
386QMap<QString, KisMetaData::Value> Value::asLangArray() const
387{
388 Q_ASSERT(d->type == LangArray);
389 QMap<QString, KisMetaData::Value> langArray;
390 Q_FOREACH (const KisMetaData::Value& val, *d->value.array) {
391 Q_ASSERT(val.d->propertyQualifiers.contains("xml:lang")); // TODO probably worth to have an assert for this in the constructor as well
392 KisMetaData::Value valKeyVal = val.d->propertyQualifiers.value("xml:lang");
393 Q_ASSERT(valKeyVal.type() == Variant);
394 QVariant valKeyVar = valKeyVal.asVariant();
395 Q_ASSERT(valKeyVar.type() == QVariant::String);
396 langArray[valKeyVar.toString()] = val;
397 }
398 return langArray;
399}
400
401QString Value::toString() const
402{
403 switch (type()) {
404 case Value::Invalid:
405 return i18n("Invalid value.");
406 case Value::Variant:
407 return d->value.variant->toString();
408 break;
412 case Value::LangArray: {
413 QString r = QString("[%1]{ ").arg(d->value.array->size());
414 for (int i = 0; i < d->value.array->size(); ++i) {
415 const Value& val = d->value.array->at(i);
416 r += val.toString();
417 if (i != d->value.array->size() - 1) {
418 r += ',';
419 }
420 r += ' ';
421 }
422 r += '}';
423 return r;
424 }
425 case Value::Structure: {
426 QString r = "{ ";
427 QList<QString> fields = d->value.structure->keys();
428 for (int i = 0; i < fields.count(); ++i) {
429 const QString& field = fields[i];
430 const Value& val = d->value.structure->value(field);
431 r += field + " => " + val.toString();
432 if (i != d->value.array->size() - 1) {
433 r += ',';
434 }
435 r += ' ';
436 }
437 r += '}';
438 return r;
439 }
440 break;
441 case Value::Rational:
442 return QString("%1 / %2").arg(d->value.rational->numerator).arg(d->value.rational->denominator);
443 }
444 return i18n("Invalid value.");
445}
float value(const T *src, size_t ch)
qreal v
QDebug KRITACOMMAND_EXPORT operator<<(QDebug dbg, const KisCumulativeUndoData &data)
const QMap< QString, Value > & propertyQualifiers() const
QList< KisMetaData::Value > asArray() const
bool setStructureVariant(const QString &fieldNAme, const QVariant &variant)
QMap< QString, KisMetaData::Value > asStructure() const
bool operator==(const Value &) const
QVariant asVariant() const
Value & operator=(const Value &v)
bool setVariant(const QVariant &variant)
Value & operator+=(const Value &)
ValueType
Define the possible value type.
void addPropertyQualifier(const QString &_name, const Value &)
KisMetaData::Rational asRational() const
ValueType type() const
bool setArrayVariant(int index, const QVariant &variant)
QMap< QString, KisMetaData::Value > asLangArray() const
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
#define warnMetaData
Definition kis_debug.h:103
KisMetaData::Rational * rational
QMap< QString, Value > propertyQualifiers
QVariant * variant
QList< Value > * array
ValueType type
QMap< QString, Value > * structure