File indexing completed on 2024-05-12 15:59:17

0001 /*
0002  *  SPDX-FileCopyrightText: 2009 Cyrille Berger <cberger@cberger.net>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.1-or-later
0005  */
0006 
0007 #include "kis_meta_data_type_info.h"
0008 
0009 #include <QVariant>
0010 
0011 #include "kis_meta_data_parser_p.h"
0012 #include "kis_meta_data_type_info_p.h"
0013 #include "kis_meta_data_value.h"
0014 #include "kis_meta_data_schema.h"
0015 
0016 using namespace KisMetaData;
0017 
0018 QHash< const TypeInfo*, const TypeInfo*> TypeInfo::Private::orderedArrays;
0019 QHash< const TypeInfo*, const TypeInfo*> TypeInfo::Private::unorderedArrays;
0020 QHash< const TypeInfo*, const TypeInfo*> TypeInfo::Private::alternativeArrays;
0021 
0022 const TypeInfo* TypeInfo::Private::Boolean = new TypeInfo(TypeInfo::BooleanType);
0023 const TypeInfo* TypeInfo::Private::Integer = new TypeInfo(TypeInfo::IntegerType);
0024 const TypeInfo* TypeInfo::Private::Date = new TypeInfo(TypeInfo::DateType);
0025 const TypeInfo* TypeInfo::Private::Text = new TypeInfo(TypeInfo::TextType);
0026 const TypeInfo* TypeInfo::Private::Rational = new TypeInfo(TypeInfo::RationalType);
0027 const TypeInfo* TypeInfo::Private::GPSCoordinate = new TypeInfo(TypeInfo::GPSCoordinateType);
0028 
0029 const TypeInfo* TypeInfo::Private::orderedArray(const TypeInfo* _typeInfo)
0030 {
0031     if (Private::orderedArrays.contains(_typeInfo)) {
0032         return Private::orderedArrays[ _typeInfo ];
0033     }
0034     const TypeInfo* info = new TypeInfo(TypeInfo::OrderedArrayType, _typeInfo);
0035     Private::orderedArrays[ _typeInfo ] = info;
0036     return info;
0037 }
0038 
0039 const TypeInfo* TypeInfo::Private::unorderedArray(const TypeInfo* _typeInfo)
0040 {
0041     if (Private::unorderedArrays.contains(_typeInfo)) {
0042         return Private::unorderedArrays[ _typeInfo ];
0043     }
0044     const TypeInfo* info = new TypeInfo(TypeInfo::UnorderedArrayType, _typeInfo);
0045     Private::unorderedArrays[ _typeInfo ] = info;
0046     return info;
0047 }
0048 
0049 const TypeInfo* TypeInfo::Private::alternativeArray(const TypeInfo* _typeInfo)
0050 {
0051     if (Private::alternativeArrays.contains(_typeInfo)) {
0052         return Private::alternativeArrays[ _typeInfo ];
0053     }
0054     const TypeInfo* info = new TypeInfo(TypeInfo::AlternativeArrayType, _typeInfo);
0055     Private::alternativeArrays[ _typeInfo ] = info;
0056     return info;
0057 }
0058 
0059 const TypeInfo* TypeInfo::Private::createChoice(PropertyType _propertiesType, const TypeInfo* _embedded, const QList< Choice >& _choices)
0060 {
0061     return new TypeInfo(_propertiesType, _embedded, _choices);
0062 }
0063 
0064 const TypeInfo* TypeInfo::Private::createStructure(Schema* _structureSchema, const QString& name)
0065 {
0066     return new TypeInfo(_structureSchema, name);
0067 }
0068 
0069 const TypeInfo* TypeInfo::Private::LangArray = new TypeInfo(TypeInfo::LangArrayType);
0070 
0071 TypeInfo::TypeInfo(TypeInfo::PropertyType _propertyType) : d(new Private)
0072 {
0073     d->propertyType = _propertyType;
0074     if (d->propertyType == TypeInfo::LangArrayType) {
0075         d->embeddedTypeInfo = TypeInfo::Private::Text;
0076     }
0077     switch (d->propertyType) {
0078     case IntegerType:
0079         d->parser = new IntegerParser;
0080         break;
0081     case TextType:
0082         d->parser = new TextParser;
0083         break;
0084     case DateType:
0085         d->parser = new DateParser;
0086         break;
0087     case RationalType:
0088         d->parser = new RationalParser;
0089         break;
0090     default:
0091         ;
0092     }
0093 }
0094 
0095 struct Q_DECL_HIDDEN TypeInfo::Choice::Private {
0096     Value value;
0097     QString hint;
0098 };
0099 
0100 TypeInfo::Choice::Choice(const Value& value, const QString& hint) : d(new Private)
0101 {
0102     d->value = value;
0103     d->hint = hint;
0104 }
0105 
0106 TypeInfo::Choice::Choice(const Choice& _rhs) : d(new Private(*_rhs.d))
0107 {
0108 }
0109 
0110 TypeInfo::Choice& TypeInfo::Choice::operator=(const Choice & _rhs)
0111 {
0112     *d = *_rhs.d;
0113     return *this;
0114 }
0115 
0116 TypeInfo::Choice::~Choice()
0117 {
0118     delete d;
0119 }
0120 const Value& TypeInfo::Choice::value() const
0121 {
0122     return d->value;
0123 }
0124 
0125 const QString& TypeInfo::Choice::hint() const
0126 {
0127     return d->hint;
0128 }
0129 
0130 TypeInfo::TypeInfo(PropertyType _propertyType, const TypeInfo* _embedded) : d(new Private)
0131 {
0132     Q_ASSERT(_propertyType == OrderedArrayType || _propertyType == UnorderedArrayType || _propertyType == AlternativeArrayType);
0133     d->propertyType = _propertyType;
0134     d->embeddedTypeInfo = _embedded;
0135 }
0136 
0137 TypeInfo::TypeInfo(PropertyType _propertyType, const TypeInfo* _embedded, const QList< Choice >& _choices) : d(new Private)
0138 {
0139     Q_ASSERT(_propertyType == ClosedChoice || _propertyType == OpenedChoice);
0140     d->propertyType = _propertyType;
0141     d->embeddedTypeInfo = _embedded;
0142     d->parser = _embedded->parser();
0143     d->choices = _choices;
0144 }
0145 
0146 TypeInfo::TypeInfo(Schema* _structureSchema, const QString& name) : d(new Private)
0147 {
0148     d->propertyType = TypeInfo::StructureType;
0149     d->structureSchema = _structureSchema;
0150     d->structureName = name;
0151 }
0152 
0153 TypeInfo::~TypeInfo()
0154 {
0155     delete d->parser;
0156     delete d;
0157 }
0158 
0159 TypeInfo::PropertyType TypeInfo::propertyType() const
0160 {
0161     return d->propertyType;
0162 }
0163 
0164 const TypeInfo* TypeInfo::embeddedPropertyType() const
0165 {
0166     return d->embeddedTypeInfo;
0167 }
0168 
0169 const QList< TypeInfo::Choice >& TypeInfo::choices() const
0170 {
0171     return d->choices;
0172 }
0173 
0174 Schema* TypeInfo::structureSchema() const
0175 {
0176     return d->structureSchema;
0177 }
0178 
0179 const QString& TypeInfo::structureName() const
0180 {
0181     return d->structureName;
0182 }
0183 
0184 const Parser* TypeInfo::parser() const
0185 {
0186     return d->parser;
0187 }
0188 
0189 bool checkArray(const Value& value, const TypeInfo* typeInfo)
0190 {
0191     QList< Value > values = value.asArray();
0192     Q_FOREACH (const Value& val, values) {
0193         if (!typeInfo->hasCorrectType(val)) {
0194             return false;
0195         }
0196     }
0197     return true;
0198 }
0199 
0200 bool TypeInfo::hasCorrectType(const Value& value) const
0201 {
0202     switch (d->propertyType) {
0203     case BooleanType:
0204         return value.type() == Value::Variant && value.asVariant().type() == QVariant::Bool;
0205     case IntegerType:
0206         return value.type() == Value::Variant && value.asVariant().type() == QVariant::Int;
0207     case DateType:
0208         return value.type() == Value::Variant && value.asVariant().type() == QVariant::DateTime;
0209     case GPSCoordinateType:
0210     case TextType:
0211         return value.type() == Value::Variant && value.asVariant().type() == QVariant::String;
0212     case OrderedArrayType:
0213         if (value.type() == Value::OrderedArray) {
0214             return checkArray(value, d->embeddedTypeInfo);
0215         } else {
0216             return false;
0217         }
0218     case UnorderedArrayType:
0219         if (value.type() == Value::UnorderedArray) {
0220             return checkArray(value, d->embeddedTypeInfo);
0221         } else {
0222             return false;
0223         }
0224     case AlternativeArrayType:
0225         if (value.type() == Value::AlternativeArray) {
0226             return checkArray(value, d->embeddedTypeInfo);
0227         } else {
0228             return false;
0229         }
0230     case LangArrayType:
0231         if (value.type() == Value::LangArray) {
0232             QList< Value > values = value.asArray();
0233             Q_FOREACH (const Value& vallang, values) {
0234                 if (!Private::Text->hasCorrectType(vallang) ||
0235                         !Private::Text->hasCorrectType(vallang.propertyQualifiers()["xml:lang"])) {
0236                     return false;
0237                 }
0238             }
0239             return true;
0240         } else {
0241             return false;
0242         }
0243     case StructureType:
0244         if (value.type() == Value::Structure) {
0245             QMap<QString, KisMetaData::Value> structure = value.asStructure();
0246             for (QMap<QString, KisMetaData::Value>::iterator it = structure.begin();
0247                     it != structure.end(); ++it) {
0248                 const TypeInfo* typeInfo = d->structureSchema->propertyType(it.key());
0249                 if (!typeInfo || !typeInfo->hasCorrectType(it.value())) {
0250                     return false;
0251                 }
0252             }
0253             return true;
0254         } else {
0255             return false;
0256         }
0257     case RationalType:
0258         return value.type() == Value::Rational;
0259     case OpenedChoice:
0260     case ClosedChoice:
0261         return d->embeddedTypeInfo->hasCorrectType(value);
0262     }
0263     return false;
0264 }
0265 
0266 bool TypeInfo::hasCorrectValue(const Value& value) const
0267 {
0268     if (d->propertyType == ClosedChoice) {
0269         Q_FOREACH (const Choice& choice, d->choices) {
0270             if (choice.value() == value) {
0271                 return true;
0272             }
0273         }
0274         return false;
0275     } else {
0276         return true;
0277     }
0278 }