Commit 5113fd5b authored by Cyrille Berger's avatar Cyrille Berger

metadata:

* merge Signed and Unsigned Rational
* add a class for validating a metadata store
* add functions to check the type and value of an entry to TypeInfo

kisexiv2:
* add initial work on a test for the exif loader

svn path=/trunk/koffice/; revision=923521
parent 25f01f48
......@@ -162,6 +162,7 @@ set(kritaimage_LIB_SRCS
metadata/kis_meta_data_schema_registry.cc
metadata/kis_meta_data_store.cc
metadata/kis_meta_data_type_info.cc
metadata/kis_meta_data_validator.cc
metadata/kis_meta_data_value.cc
recorder/kis_action_recorder.cc
recorder/kis_macro.cc
......@@ -195,6 +196,7 @@ install( FILES
metadata/schemas/exif.schema
metadata/schemas/tiff.schema
metadata/schemas/xmp.schema
metadata/schemas/xmprights.schema
DESTINATION ${DATA_INSTALL_DIR}/krita/metadata/schemas)
......
......@@ -71,6 +71,6 @@ Value RationalParser::parse(const QString& _v) const
QRegExp regexp("(\\-?\\d+)/(\\d+)");
regexp.indexIn(_v);
if( regexp.capturedTexts().size() > 2 )
return Value( SignedRational( regexp.capturedTexts()[1].toInt(), regexp.capturedTexts()[2].toInt() ) );
return Value( Rational( regexp.capturedTexts()[1].toInt(), regexp.capturedTexts()[2].toInt() ) );
return Value();
}
......@@ -247,7 +247,7 @@ bool Schema::Private::parseEltType(QDomElement& elt, EntryInfo& entryInfo, QStri
entryInfo.propertyType = TypeInfo::Private::LangArray;
return true;
} else if( tagName == "rational" ) {
entryInfo.propertyType = TypeInfo::Private::SignedRational;
entryInfo.propertyType = TypeInfo::Private::Rational;
return true;
} else if( tagName == "gpscoordinate" ) {
entryInfo.propertyType = TypeInfo::Private::GPSCoordinate;
......@@ -280,7 +280,7 @@ const TypeInfo* Schema::Private::parseAttType( QDomElement& elt, bool ignoreStru
} else if( type == "text" ) {
return TypeInfo::Private::Text;
} else if( type == "rational" ) {
return TypeInfo::Private::SignedRational;
return TypeInfo::Private::Rational;
}
errImage << "Unsupported type: " << type << " in an attribute";
return 0;
......
......@@ -207,3 +207,8 @@ QList<QString> Store::keys() const
{
return d->entries.keys();
}
QList<Entry> Store::entries() const
{
return d->entries.values();
}
......@@ -164,6 +164,10 @@ public:
*/
QList<QString> keys() const;
/**
* @return the list of entries
*/
QList<Entry> entries() const;
private:
Private* const d;
};
......
......@@ -18,9 +18,12 @@
#include "kis_meta_data_type_info.h"
#include <QVariant>
#include "kis_meta_data_parser_p.h"
#include "kis_meta_data_type_info_p.h"
#include "kis_meta_data_value.h"
#include "kis_meta_data_schema.h"
using namespace KisMetaData;
......@@ -32,8 +35,7 @@ const TypeInfo* TypeInfo::Private::Boolean = new TypeInfo( TypeInfo::BooleanType
const TypeInfo* TypeInfo::Private::Integer = new TypeInfo( TypeInfo::IntegerType );
const TypeInfo* TypeInfo::Private::Date = new TypeInfo( TypeInfo::DateType );
const TypeInfo* TypeInfo::Private::Text = new TypeInfo( TypeInfo::TextType );
const TypeInfo* TypeInfo::Private::SignedRational = new TypeInfo( TypeInfo::SignedRationalType );
const TypeInfo* TypeInfo::Private::UnsignedRational = new TypeInfo( TypeInfo::UnsignedRationalType );
const TypeInfo* TypeInfo::Private::Rational = new TypeInfo( TypeInfo::RationalType );
const TypeInfo* TypeInfo::Private::GPSCoordinate = new TypeInfo( TypeInfo::GPSCoordinateType );
const TypeInfo* TypeInfo::Private::orderedArray( const TypeInfo* _typeInfo)
......@@ -99,7 +101,7 @@ TypeInfo::TypeInfo( TypeInfo::PropertyType _propertyType ) : d(new Private )
case DateType:
d->parser = new DateParser;
break;
case SignedRationalType:
case RationalType:
d->parser = new RationalParser;
break;
}
......@@ -197,3 +199,108 @@ const Parser* TypeInfo::parser() const
{
return d->parser;
}
bool checkArray( const Value& value, const TypeInfo* typeInfo )
{
QList< Value > values = value.asArray();
foreach( const Value& val, values )
{
if( !typeInfo->hasCorrectType(val))
{
return false;
}
}
return true;
}
bool TypeInfo::hasCorrectType( const Value& value ) const
{
switch( d->propertyType )
{
case BooleanType:
return value.type() == Value::Variant && value.asVariant().type() == QVariant::Bool;
case IntegerType:
return value.type() == Value::Variant && value.asVariant().type() == QVariant::Int;
case DateType:
return value.type() == Value::Variant && value.asVariant().type() == QVariant::DateTime;
case GPSCoordinateType:
case TextType:
return value.type() == Value::Variant && value.asVariant().type() == QVariant::String;
case OrderedArrayType:
if( value.type() == Value::OrderedArray )
{
return checkArray( value, d->embeddedTypeInfo );
} else {
return false;
}
case UnorderedArrayType:
if( value.type() == Value::UnorderedArray )
{
return checkArray( value, d->embeddedTypeInfo );
} else {
return false;
}
case AlternativeArrayType:
if( value.type() == Value::AlternativeArray )
{
return checkArray( value, d->embeddedTypeInfo );
} else {
return false;
}
case LangArrayType:
if( value.type() == Value::LangArray )
{
QList< Value > values = value.asArray();
foreach( const Value& vallang, values )
{
if( !Private::Text->hasCorrectType(vallang) ||
!Private::Text->hasCorrectType(vallang.propertyQualifiers()["xml:lang"]) )
{
return false;
}
}
} else {
return false;
}
case StructureType:
if( value.type() == Value::Structure )
{
QMap<QString, KisMetaData::Value> structure = value.asStructure();
for( QMap<QString, KisMetaData::Value>::iterator it = structure.begin();
it != structure.end(); ++it)
{
const TypeInfo* typeInfo = d->structureSchema->propertyType(it.key());
if( !typeInfo || typeInfo->hasCorrectType(it.value()))
{
return false;
}
}
return true;
} else {
return false;
}
case RationalType:
return value.type() == Value::Rational;
case OpenedChoice:
case ClosedChoice:
return d->embeddedTypeInfo->hasCorrectType(value);
}
return false;
}
bool TypeInfo::hasCorrectValue( const Value& value ) const
{
if( d->propertyType == ClosedChoice )
{
foreach( Choice choice, d->choices )
{
if( choice.value() == value )
{
return true;
}
}
return false;
} else {
return true;
}
}
......@@ -39,8 +39,7 @@ namespace KisMetaData {
AlternativeArrayType,
LangArrayType,
StructureType,
SignedRationalType,
UnsignedRationalType,
RationalType,
GPSCoordinateType,
OpenedChoice,
ClosedChoice
......@@ -81,6 +80,14 @@ namespace KisMetaData {
Schema* structureSchema() const;
const QString& structureName() const;
const Parser* parser() const;
/**
* @return true if @p value has a type that is correct for this \ref TypeInfo
*/
bool hasCorrectType( const Value& value ) const;
/**
* @return true if @p value has a value acceptable for this \ref TypeInfo
*/
bool hasCorrectValue( const Value& value ) const;
public:
struct Private;
private:
......
......@@ -37,8 +37,7 @@ struct KRITAIMAGE_TEST_EXPORT KisMetaData::TypeInfo::Private {
static const TypeInfo* Integer;
static const TypeInfo* Date;
static const TypeInfo* Text;
static const TypeInfo* SignedRational;
static const TypeInfo* UnsignedRational;
static const TypeInfo* Rational;
static const TypeInfo* GPSCoordinate;
static const TypeInfo* orderedArray( const TypeInfo* );
static const TypeInfo* unorderedArray( const TypeInfo* );
......
/*
* Copyright (c) 2009 Cyrille Berger <cberger@cberger.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_meta_data_validator.h"
#include "kis_meta_data_store.h"
#include "kis_meta_data_value.h"
#include "kis_meta_data_entry.h"
#include "kis_meta_data_schema.h"
#include "kis_meta_data_type_info.h"
using namespace KisMetaData;
//------------------- Validator::Reason -------------------//
struct Validator::Reason::Private {
Type type;
};
Validator::Reason::Reason( Type _type ) : d(new Private)
{
d->type = _type;
}
Validator::Reason::Reason(const Validator::Reason& _rhs ) : d(new Private(*_rhs.d))
{
}
Validator::Reason& Validator::Reason::operator=(const Validator::Reason& _rhs)
{
*d = *_rhs.d;
}
Validator::Reason::~Reason()
{
delete d;
}
Validator::Reason::Type Validator::Reason::type() const
{
return d->type;
}
//------------------- Validator -------------------//
struct Validator::Private {
Private() : countValidEntries(0)
{
}
int countValidEntries;
QMap<QString, Reason> invalidEntries;
const Store* store;
};
Validator::Validator( const Store* store ) : d(new Private)
{
d->store = store;
revalidate();
}
Validator::~Validator()
{
delete d;
}
void Validator::revalidate()
{
QList<Entry> entries = d->store->entries();
d->countValidEntries = 0;
d->invalidEntries.clear();
foreach( const Entry& entry, entries)
{
const TypeInfo* typeInfo = entry.schema()->propertyType( entry.name() );
if( typeInfo )
{
if( typeInfo->hasCorrectType(entry.value()) )
{
if( typeInfo->hasCorrectValue(entry.value()) )
{
++d->countValidEntries;
} else {
d->invalidEntries[entry.qualifiedName()] = Reason( Reason::INVALID_VALUE );
}
} else {
d->invalidEntries[entry.qualifiedName()] = Reason( Reason::INVALID_TYPE );
}
} else {
d->invalidEntries[entry.qualifiedName()] = Reason( Reason::UNKNOWN_ENTRY );
}
}
}
int Validator::countInvalidEntries() const
{
return d->invalidEntries.size();
}
int Validator::countValidEntries() const
{
return d->countValidEntries;
}
QMap<QString, Validator::Reason> Validator::invalidEntries() const
{
return d->invalidEntries;
}
/*
* Copyright (c) 2009 Cyrille Berger <cberger@cberger.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _KIS_META_DATA_VALIDATION_RESULT_H_
#define _KIS_META_DATA_VALIDATION_RESULT_H_
#include <QMap>
#include <QString>
#include <krita_export.h>
namespace KisMetaData {
class Store;
/**
* This class contains information on the validation results of a \ref KisMetaData::Store .
*/
class KRITAIMAGE_EXPORT Validator {
public:
class Reason {
friend class Validator;
friend class QMap<QString, Reason>;
public:
enum Type {
UNKNOWN_REASON,
UNKNOWN_ENTRY,
INVALID_TYPE,
INVALID_VALUE
};
private:
Reason(Type type = UNKNOWN_REASON);
Reason(const Reason& );
Reason& operator=(const Reason& );
public:
~Reason();
Type type() const;
private:
struct Private;
Private* const d;
};
public:
/**
* Validate a store. This constructore will call the \ref revalidate function.
*/
Validator( const Store* );
~Validator();
int countInvalidEntries() const;
int countValidEntries() const;
QMap<QString, Reason> invalidEntries() const;
/**
* Call this function to revalidate the store.
*/
void revalidate();
private:
struct Private;
Private* const d;
};
}
#endif
......@@ -34,8 +34,7 @@ struct Value::Private {
QVariant* variant;
QList<Value>* array;
QMap<QString, Value>* structure;
KisMetaData::SignedRational* signedRational;
KisMetaData::UnsignedRational* unsignedRational;
KisMetaData::Rational* rational;
} value;
ValueType type;
QMap<QString, Value> propertyQualifiers;
......@@ -66,15 +65,10 @@ Value::Value(const QMap<QString, Value>& structure) : d(new Private)
d->value.structure = new QMap<QString, Value>(structure);
}
Value::Value(const KisMetaData::SignedRational& signedRational) : d(new Private)
Value::Value(const KisMetaData::Rational& signedRational) : d(new Private)
{
d->type = Value::SignedRational;
d->value.signedRational = new KisMetaData::SignedRational(signedRational);
}
Value::Value(const KisMetaData::UnsignedRational& unsignedRational) : d(new Private)
{
d->type = Value::UnsignedRational;
d->value.unsignedRational = new KisMetaData::UnsignedRational(unsignedRational);
d->type = Value::Rational;
d->value.rational = new KisMetaData::Rational(signedRational);
}
......@@ -104,10 +98,8 @@ Value& Value::operator=(const Value & v)
case Structure:
d->value.structure = new QMap<QString, Value>(*v.d->value.structure);
break;
case SignedRational:
d->value.signedRational = new KisMetaData::SignedRational(*v.d->value.signedRational);
case UnsignedRational:
d->value.unsignedRational = new KisMetaData::UnsignedRational(*v.d->value.unsignedRational);
case Rational:
d->value.rational = new KisMetaData::Rational(*v.d->value.rational);
}
return *this;
}
......@@ -123,6 +115,11 @@ void Value::addPropertyQualifier(const QString& _name, const Value& _value)
d->propertyQualifiers[_name] = _value;
}
const QMap<QString, Value>& Value::propertyQualifiers() const
{
return d->propertyQualifiers;
}
Value::ValueType Value::type() const
{
return d->type;
......@@ -133,10 +130,8 @@ double Value::asDouble() const
switch (type()) {
case Variant:
return d->value.variant->toDouble(0);
case UnsignedRational:
return d->value.unsignedRational->numerator / (double)d->value.unsignedRational->denominator;
case SignedRational:
return d->value.signedRational->numerator / (double)d->value.signedRational->denominator;
case Rational:
return d->value.rational->numerator / (double)d->value.rational->denominator;
default:
return 0.0;
}
......@@ -148,10 +143,8 @@ int Value::asInteger() const
switch (type()) {
case Variant:
return d->value.variant->toInt(0);
case UnsignedRational:
return d->value.unsignedRational->numerator / d->value.unsignedRational->denominator;
case SignedRational:
return d->value.signedRational->numerator / d->value.signedRational->denominator;
case Rational:
return d->value.rational->numerator / d->value.rational->denominator;
default:
return 0;
}
......@@ -163,10 +156,8 @@ QVariant Value::asVariant() const
switch (type()) {
case Variant:
return *d->value.variant;
case UnsignedRational:
return QVariant(QString("%1 / %2").arg(d->value.unsignedRational->numerator).arg(d->value.unsignedRational->denominator));
case SignedRational:
return QVariant(QString("%1 / %2").arg(d->value.signedRational->numerator).arg(d->value.signedRational->denominator));
case Rational:
return QVariant(QString("%1 / %2").arg(d->value.rational->numerator).arg(d->value.rational->denominator));
default: break;
}
return QVariant();
......@@ -178,8 +169,7 @@ bool Value::setVariant(const QVariant& variant)
case KisMetaData::Value::Invalid:
*this = KisMetaData::Value(variant);
return true;
case UnsignedRational:
case SignedRational: {
case Rational: {
QRegExp rx("([^\\/]*)\\/([^\\/]*)");
rx.indexIn(variant.toString());
}
......@@ -196,20 +186,12 @@ bool Value::setVariant(const QVariant& variant)
return false;
}
KisMetaData::UnsignedRational Value::asUnsignedRational() const
KisMetaData::Rational Value::asRational() const
{
if (d->type == UnsignedRational) {
return *d->value.unsignedRational;
if (d->type == Rational) {
return *d->value.rational;
}
return KisMetaData::UnsignedRational();
}
KisMetaData::SignedRational Value::asSignedRational() const
{
if (d->type == SignedRational) {
return *d->value.signedRational;
}
return KisMetaData::SignedRational();
return KisMetaData::Rational();
}
QList<Value> Value::asArray() const
......@@ -260,11 +242,8 @@ QDebug operator<<(QDebug debug, const Value &v)
case Value::Structure:
debug.nospace() << "Structure: " << v.asStructure();
break;
case Value::SignedRational:
debug.nospace() << "Signed rational: " << v.asSignedRational().numerator << " / " << v.asSignedRational().denominator;
break;
case Value::UnsignedRational:
debug.nospace() << "Unsigend rational: " << v.asUnsignedRational().numerator << " / " << v.asUnsignedRational().denominator;
case Value::Rational:
debug.nospace() << "Rational: " << v.asRational().numerator << " / " << v.asRational().denominator;
break;
}
return debug.space();
......@@ -285,10 +264,8 @@ bool Value::operator==(const Value& rhs) const
return asArray() == rhs.asArray();
case Value::Structure:
return asStructure() == rhs.asStructure();
case Value::SignedRational:
return asSignedRational() == rhs.asSignedRational();
case Value::UnsignedRational:
return asUnsignedRational() == rhs.asUnsignedRational();
case Value::Rational:
return asRational() == rhs.asRational();
}
return false;
}
......@@ -397,28 +374,16 @@ Value& Value::operator+=(const Value & v)
Q_ASSERT(v.type() == Value::Structure);
break;
}
case Value::SignedRational: {
Q_ASSERT(v.type() == Value::SignedRational);
d->value.signedRational->numerator =
(d->value.signedRational->numerator
* v.d->value.signedRational->denominator)
+ (v.d->value.signedRational->numerator
* d->value.signedRational->denominator);
d->value.signedRational->denominator *= v.d->value.signedRational->denominator;
case Value::Rational: {
Q_ASSERT(v.type() == Value::Rational);
d->value.rational->numerator =
(d->value.rational->numerator
* v.d->value.rational->denominator)
+ (v.d->value.rational->numerator
* d->value.rational->denominator);
d->value.rational->denominator *= v.d->value.rational->denominator;
break;
}
case Value::UnsignedRational: {
Q_ASSERT(v.type() == Value::UnsignedRational);
d->value.unsignedRational->numerator =
(d->value.unsignedRational->numerator
* v.d->value.unsignedRational->denominator)
+ (v.d->value.unsignedRational->numerator
* d->value.unsignedRational->denominator);
d->value.unsignedRational->denominator *=
v.d->value.unsignedRational->denominator;
break;
}
break;
}
return *this;
}
......
......@@ -30,20 +30,11 @@ class QVariant;
namespace KisMetaData
{
class Schema;
struct UnsignedRational {
explicit UnsignedRational(quint32 n = 0, quint32 d = 1) : numerator(n), denominator(d) {}
quint32 numerator;
quint32 denominator;
bool operator==(const UnsignedRational& ur) const {
return numerator == ur.numerator && denominator == ur.denominator;
}
};
struct SignedRational {
explicit SignedRational(qint32 n = 0, qint32 d = 1) : numerator(n), denominator(d) {}
struct Rational {
explicit Rational(qint32 n = 0, qint32 d = 1) : numerator(n), denominator(d) {}
qint32 numerator;
qint32 denominator;
bool operator==(const SignedRational& ur) const {
bool operator==(const Rational& ur) const {
return numerator == ur.numerator && denominator == ur.denominator;
}
};
......@@ -64,8 +55,7 @@ public:
AlternativeArray,
LangArray,
Structure,
SignedRational,
UnsignedRational
Rational
};
public:
Value();
......@@ -76,13 +66,13 @@ public:
*/