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 }