2015-04-22 19:22:01 +02:00
|
|
|
#ifndef FIELDBASEDTAG_H
|
|
|
|
#define FIELDBASEDTAG_H
|
|
|
|
|
2015-09-06 19:57:33 +02:00
|
|
|
#include "./tag.h"
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
#include <map>
|
|
|
|
#include <functional>
|
|
|
|
|
2015-09-06 15:42:18 +02:00
|
|
|
namespace Media {
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* \class Media::FieldMapBasedTag
|
|
|
|
* \brief The FieldMapBasedTag provides a generic implementation of Tag which stores
|
|
|
|
* the tag fields using std::multimap.
|
|
|
|
*
|
|
|
|
* The FieldMapBasedTag class only provides the interface and common functionality.
|
|
|
|
* It is meant to be subclassed.
|
|
|
|
*
|
|
|
|
* \tparam FieldType Specifies the class used to store the fields. Should be a subclass
|
|
|
|
* of TagField.
|
|
|
|
*
|
|
|
|
* \tparam Compare Specifies the key comparsion function. Default is std::less.
|
|
|
|
*/
|
|
|
|
template <class FieldType, class Compare = std::less<typename FieldType::identifierType> >
|
|
|
|
class FieldMapBasedTag : public Tag
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
FieldMapBasedTag();
|
|
|
|
|
2015-07-27 23:10:35 +02:00
|
|
|
virtual const TagValue &value(KnownField field) const;
|
2015-04-22 19:22:01 +02:00
|
|
|
virtual const TagValue &value(const typename FieldType::identifierType &id) const;
|
|
|
|
virtual std::list<const TagValue *> values(const typename FieldType::identifierType &id) const;
|
|
|
|
virtual bool setValue(KnownField field, const TagValue &value);
|
|
|
|
virtual bool setValue(const typename FieldType::identifierType &id, const TagValue &value);
|
|
|
|
virtual bool hasField(KnownField field) const;
|
|
|
|
virtual bool hasField(const typename FieldType::identifierType &id) const;
|
|
|
|
virtual void removeAllFields();
|
|
|
|
const std::multimap<typename FieldType::identifierType, FieldType, Compare> &fields() const;
|
|
|
|
std::multimap<typename FieldType::identifierType, FieldType, Compare> &fields();
|
2015-08-16 23:39:42 +02:00
|
|
|
virtual unsigned int fieldCount() const;
|
2015-04-22 19:22:01 +02:00
|
|
|
virtual typename FieldType::identifierType fieldId(KnownField value) const = 0;
|
|
|
|
virtual KnownField knownField(const typename FieldType::identifierType &id) const = 0;
|
|
|
|
virtual bool supportsField(KnownField field) const;
|
|
|
|
using Tag::proposedDataType;
|
|
|
|
virtual TagDataType proposedDataType(const typename FieldType::identifierType &id) const;
|
|
|
|
virtual int insertFields(const FieldMapBasedTag<FieldType, Compare> &from, bool overwrite);
|
2015-08-16 23:39:42 +02:00
|
|
|
virtual unsigned int insertValues(const Tag &from, bool overwrite);
|
2015-04-22 19:22:01 +02:00
|
|
|
typedef FieldType fieldType;
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::multimap<typename FieldType::identifierType, FieldType, Compare> m_fields;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \fn FieldMapBasedTag::fieldId()
|
|
|
|
* \brief Returns the ID for the specified \a field.
|
|
|
|
*
|
|
|
|
* Needs to be implemented when subclassing.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \fn FieldMapBasedTag::knownField()
|
|
|
|
* \brief Returns the field for the specified \a ID.
|
|
|
|
*
|
|
|
|
* Needs to be implemented when subclassing.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Constructs a new FieldMapBasedTag.
|
|
|
|
*/
|
|
|
|
template <class FieldType, class Compare>
|
|
|
|
FieldMapBasedTag<FieldType, Compare>::FieldMapBasedTag()
|
|
|
|
{}
|
|
|
|
|
|
|
|
template <class FieldType, class Compare>
|
2015-07-27 23:10:35 +02:00
|
|
|
inline const TagValue &FieldMapBasedTag<FieldType, Compare>::value(KnownField field) const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2015-07-27 23:10:35 +02:00
|
|
|
return value(fieldId(field));
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the value of the field with the specified \a id.
|
|
|
|
*/
|
|
|
|
template <class FieldType, class Compare>
|
|
|
|
inline const TagValue &FieldMapBasedTag<FieldType, Compare>::value(const typename FieldType::identifierType &id) const
|
|
|
|
{
|
|
|
|
auto i = m_fields.find(id);
|
|
|
|
return i != m_fields.end() ? i->second.value() : TagValue::empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the values of the field with the specified \a id.
|
|
|
|
*
|
|
|
|
* There might me more then one value assigned to a \a field. Whereas value()
|
|
|
|
* returns only the first value, this method returns all values.
|
|
|
|
*/
|
|
|
|
template <class FieldType, class Compare>
|
|
|
|
inline std::list<const TagValue *> FieldMapBasedTag<FieldType, Compare>::values(const typename FieldType::identifierType &id) const
|
|
|
|
{
|
|
|
|
auto range = m_fields.equal_range(id);
|
|
|
|
std::list<const TagValue *> values;
|
|
|
|
for(auto i = range.first; i != range.second; ++i) {
|
|
|
|
values.push_back(&i->second.value());
|
|
|
|
}
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class FieldType, class Compare>
|
|
|
|
inline bool FieldMapBasedTag<FieldType, Compare>::setValue(KnownField field, const TagValue &value)
|
|
|
|
{
|
|
|
|
return setValue(fieldId(field), value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Assigns the given \a value to the field with the specified \a id.
|
|
|
|
*/
|
|
|
|
template <class FieldType, class Compare>
|
|
|
|
bool FieldMapBasedTag<FieldType, Compare>::setValue(const typename FieldType::identifierType &id, const Media::TagValue &value)
|
|
|
|
{
|
|
|
|
auto i = m_fields.find(id);
|
|
|
|
if(i != m_fields.end()) { // field already exists -> set its value
|
|
|
|
i->second.setValue(value);
|
|
|
|
} else if(!value.isEmpty()) {// field doesn't exist -> create new one if value is not null
|
|
|
|
m_fields.insert(std::pair<typename FieldType::identifierType, FieldType>(id, FieldType(id, value)));
|
|
|
|
} else { // otherwise return false
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class FieldType, class Compare>
|
|
|
|
inline bool FieldMapBasedTag<FieldType, Compare>::hasField(KnownField field) const
|
|
|
|
{
|
|
|
|
return hasField(fieldId(field));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns an indication whether the field with the specified \a id is present.
|
|
|
|
*/
|
|
|
|
template <class FieldType, class Compare>
|
|
|
|
inline bool FieldMapBasedTag<FieldType, Compare>::hasField(const typename FieldType::identifierType &id) const
|
|
|
|
{
|
|
|
|
return m_fields.count(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class FieldType, class Compare>
|
|
|
|
inline void FieldMapBasedTag<FieldType, Compare>::removeAllFields()
|
|
|
|
{
|
|
|
|
m_fields.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the fields of the tag.
|
|
|
|
*
|
|
|
|
* This method provides direct access to the fields of the tag. It might
|
|
|
|
* be usefull when the convenience methods value(), setValue(), hasField(), ...
|
2015-07-27 23:10:35 +02:00
|
|
|
* do not offer the required functionality.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
|
|
|
template <class FieldType, class Compare>
|
|
|
|
inline const std::multimap<typename FieldType::identifierType, FieldType, Compare> &FieldMapBasedTag<FieldType, Compare>::fields() const
|
|
|
|
{
|
|
|
|
return m_fields;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the fields of the tag.
|
|
|
|
*
|
|
|
|
* This method provides direct access to the fields of the tag. It might
|
|
|
|
* be usefull when the convenience methods value(), setValue(), hasField(), ...
|
2015-07-27 23:10:35 +02:00
|
|
|
* do not offer the required functionality.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
|
|
|
template <class FieldType, class Compare>
|
|
|
|
inline std::multimap<typename FieldType::identifierType, FieldType, Compare> &FieldMapBasedTag<FieldType, Compare>::fields()
|
|
|
|
{
|
|
|
|
return m_fields;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class FieldType, class Compare>
|
2015-08-16 23:39:42 +02:00
|
|
|
unsigned int FieldMapBasedTag<FieldType, Compare>::fieldCount() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2015-08-16 23:39:42 +02:00
|
|
|
int count = 0;
|
|
|
|
for(const auto &field : m_fields) {
|
|
|
|
if(!field.second.value().isEmpty()) {
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class FieldType, class Compare>
|
|
|
|
inline bool FieldMapBasedTag<FieldType, Compare>::supportsField(KnownField field) const
|
|
|
|
{
|
|
|
|
static typename FieldType::identifierType def;
|
|
|
|
return fieldId(field) != def;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the proposed data type for the field with the specified \a id.
|
|
|
|
*/
|
|
|
|
template <class FieldType, class Compare>
|
|
|
|
inline TagDataType FieldMapBasedTag<FieldType, Compare>::proposedDataType(const typename FieldType::identifierType &id) const
|
|
|
|
{
|
|
|
|
return Tag::proposedDataType(knownField(id));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Inserts all fields \a from another tag of the same field type and compare function.
|
|
|
|
* \param from Specifies the tag the fields should be inserted from.
|
|
|
|
* \param overwrite Indicates whether existing fields should be overwritten.
|
|
|
|
* \return Returns the number of fields that have been inserted.
|
|
|
|
*/
|
|
|
|
template <class FieldType, class Compare>
|
|
|
|
int FieldMapBasedTag<FieldType, Compare>::insertFields(const FieldMapBasedTag<FieldType, Compare> &from, bool overwrite)
|
|
|
|
{
|
|
|
|
int fieldsInserted = 0;
|
|
|
|
for(const auto &pair : from.fields()) {
|
|
|
|
const FieldType &fromField = pair.second;
|
|
|
|
if(fromField.value().isEmpty())
|
|
|
|
continue;
|
|
|
|
bool fieldInserted = false;
|
|
|
|
auto range = fields().equal_range(fromField.id());
|
|
|
|
for(auto i = range.first; i != range.second; ++i) {
|
|
|
|
FieldType &ownField = i->second;
|
|
|
|
if((fromField.isTypeInfoAssigned() && ownField.isTypeInfoAssigned()
|
|
|
|
&& fromField.typeInfo() == ownField.typeInfo())
|
|
|
|
|| (!fromField.isTypeInfoAssigned() && ! ownField.isTypeInfoAssigned())) {
|
|
|
|
if(overwrite || ownField.value().isEmpty()) {
|
|
|
|
ownField = fromField;
|
|
|
|
++fieldsInserted;
|
|
|
|
}
|
|
|
|
fieldInserted = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!fieldInserted) {
|
|
|
|
fields().insert(std::pair<typename FieldType::identifierType, FieldType>(fromField.id(), fromField));
|
|
|
|
++fieldsInserted;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return fieldsInserted;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class FieldType, class Compare>
|
2015-08-16 23:39:42 +02:00
|
|
|
unsigned int FieldMapBasedTag<FieldType, Compare>::insertValues(const Tag &from, bool overwrite)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
if(type() == from.type()) {
|
|
|
|
// the tags are of the same type, we can insert the fields directly
|
|
|
|
return insertFields(static_cast<const FieldMapBasedTag<FieldType, Compare> &>(from), overwrite);
|
|
|
|
} else {
|
|
|
|
return Tag::insertValues(from, overwrite);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // FIELDBASEDTAG_H
|