refs #413 To signal when contained object doesn't support an operation, throw exception in CValueObjectMetaInfo and catch in CVariant.

This commit is contained in:
Mathew Sutcliffe
2015-05-05 00:10:48 +01:00
parent 38cfebc55c
commit 9cdacf8d86
2 changed files with 113 additions and 28 deletions

View File

@@ -19,6 +19,7 @@
#include <QDBusMetaType> #include <QDBusMetaType>
#include <QDBusArgument> #include <QDBusArgument>
#include <QJsonObject> #include <QJsonObject>
#include <stdexcept>
namespace BlackMisc namespace BlackMisc
{ {
@@ -57,17 +58,37 @@ namespace BlackMisc
virtual void toIcon(const void *object, CIcon &o_icon) const = 0; virtual void toIcon(const void *object, CIcon &o_icon) const = 0;
}; };
//! \private Exception to signal that an unsupported operation was requested.
class CVariantException : public std::invalid_argument
{
public:
template <class T>
CVariantException(const T &, const QString &operationName) : std::invalid_argument((blurb<T>(operationName)).toStdString()), m_operationName(operationName) {}
const QString &operationName() const { return m_operationName; }
~CVariantException() Q_DECL_NOEXCEPT {}
private:
QString m_operationName;
template <class T>
static QString blurb(const QString &operationName)
{
return QString("CVariant requested unsupported operation of contained ") + QMetaType::typeName(qMetaTypeId<T>()) + " object: " + operationName;
}
};
//! \private //! \private
namespace Fallback namespace Fallback
{ {
//! \private Fallback in case qHash is not defined for T. //! \private Fallback in case qHash is not defined for T.
template <typename T> template <typename T>
uint qHash(const T &object) { return 0; } uint qHash(const T &object) { throw CVariantException(object, "qHash"); }
//! \private Fallback in case compare is not defined for T. //! \private Fallback in case compare is not defined for T.
template <typename T> template <typename T>
int compare(const T &a, const T &) { return 0; } int compare(const T &a, const T &) { throw CVariantException(a, "compare"); }
} }
//! \private Implementation of IValueObjectMetaInfo representing the set of operations supported by T. //! \private Implementation of IValueObjectMetaInfo representing the set of operations supported by T.
@@ -80,20 +101,20 @@ namespace BlackMisc
template <typename U> struct Derived : public U, public Fallback {}; template <typename U> struct Derived : public U, public Fallback {};
# define DISABLE_IF_HAS(MEMBER) typename int_t<&Derived<U>::MEMBER>::type # define DISABLE_IF_HAS(MEMBER) typename int_t<&Derived<U>::MEMBER>::type
template <typename U> static QJsonObject toJsonHelper(const U &, DISABLE_IF_HAS(toJson)) { return {}; } template <typename U> static QJsonObject toJsonHelper(const U &object, DISABLE_IF_HAS(toJson)) { throw CVariantException(object, "toJson"); }
template <typename U> static QJsonObject toJsonHelper(const U &object, ...) { return object.toJson(); } template <typename U> static QJsonObject toJsonHelper(const U &object, ...) { return object.toJson(); }
template <typename U> static void convertFromJsonHelper(const QJsonObject &, U &, DISABLE_IF_HAS(convertFromJson)) {} template <typename U> static void convertFromJsonHelper(const QJsonObject &, U &object, DISABLE_IF_HAS(convertFromJson)) { throw CVariantException(object, "convertFromJson"); }
template <typename U> static void convertFromJsonHelper(const QJsonObject &json, U &object, ...) { object.convertFromJson(json); } template <typename U> static void convertFromJsonHelper(const QJsonObject &json, U &object, ...) { object.convertFromJson(json); }
template <typename U> static void setPropertyByIndexHelper(U &, const CVariant &, const CPropertyIndex &, DISABLE_IF_HAS(setPropertyByIndex)) {} template <typename U> static void setPropertyByIndexHelper(U &object, const CVariant &, const CPropertyIndex &, DISABLE_IF_HAS(setPropertyByIndex)) { throw CVariantException(object, "setPropertyByIndex"); }
template <typename U> static void setPropertyByIndexHelper(U &object, const CVariant &variant, const CPropertyIndex &index, ...) { object.setPropertyByIndex(variant, index); } template <typename U> static void setPropertyByIndexHelper(U &object, const CVariant &variant, const CPropertyIndex &index, ...) { object.setPropertyByIndex(variant, index); }
template <typename U> static void propertyByIndexHelper(CVariant &, const U &, const CPropertyIndex &, DISABLE_IF_HAS(propertyByIndex)) {} template <typename U> static void propertyByIndexHelper(CVariant &, const U &object, const CPropertyIndex &, DISABLE_IF_HAS(propertyByIndex)) { throw CVariantException(object, "propertyByIndex"); }
template <typename U> static void propertyByIndexHelper(CVariant &o_variant, const U &object, const CPropertyIndex &index, ...) { assign(o_variant, object.propertyByIndex(index)); } template <typename U> static void propertyByIndexHelper(CVariant &o_variant, const U &object, const CPropertyIndex &index, ...) { assign(o_variant, object.propertyByIndex(index)); }
template <typename U> static QString propertyByIndexAsStringHelper(const U &, const CPropertyIndex &, bool, DISABLE_IF_HAS(propertyByIndexAsString)) { return {}; } template <typename U> static QString propertyByIndexAsStringHelper(const U &object, const CPropertyIndex &, bool, DISABLE_IF_HAS(propertyByIndexAsString)) { throw CVariantException(object, "propertyByIndexAsString"); }
template <typename U> static QString propertyByIndexAsStringHelper(const U &object, const CPropertyIndex &index, bool i18n, ...) { return object.propertyByIndexAsString(index, i18n); } template <typename U> static QString propertyByIndexAsStringHelper(const U &object, const CPropertyIndex &index, bool i18n, ...) { return object.propertyByIndexAsString(index, i18n); }
template <typename U> static bool equalsPropertyByIndexHelper(const U &, const CVariant &, const CPropertyIndex &, DISABLE_IF_HAS(equalsPropertyByIndex)) { return false; } template <typename U> static bool equalsPropertyByIndexHelper(const U &object, const CVariant &, const CPropertyIndex &, DISABLE_IF_HAS(equalsPropertyByIndex)) { throw CVariantException(object, "equalsPropertyByIndex"); }
template <typename U> static bool equalsPropertyByIndexHelper(const U &object, const CVariant &variant, const CPropertyIndex &index, ...) { return object.equalsPropertyByIndex(variant, index); } template <typename U> static bool equalsPropertyByIndexHelper(const U &object, const CVariant &variant, const CPropertyIndex &index, ...) { return object.equalsPropertyByIndex(variant, index); }
template <typename U> static void toIconHelper(const U &, CIcon &, DISABLE_IF_HAS(toIcon)) {} template <typename U> static void toIconHelper(const U &object, CIcon &, DISABLE_IF_HAS(toIcon)) { throw CVariantException(object, "toIcon"); }
template <typename U> static void toIconHelper(const U &, CIcon &, typename std::enable_if<std::is_same<U, CVariant>::value, int>::type) {} // CIcon is incomplete when CValueObjectMetaInfo<CVariant> is instantiated template <typename U> static void toIconHelper(const U &object, CIcon &, typename std::enable_if<std::is_same<U, CVariant>::value, int>::type) { throw CVariantException(object, "toIcon"); } // CIcon is incomplete when CValueObjectMetaInfo<CVariant> is instantiated
template <typename U> static void toIconHelper(const U &object, CIcon &o_icon, ...) { assign(o_icon, object.toIcon()); } template <typename U> static void toIconHelper(const U &object, CIcon &o_icon, ...) { assign(o_icon, object.toIcon()); }
# undef DISABLE_IF_HAS # undef DISABLE_IF_HAS

View File

@@ -10,6 +10,7 @@
#include "variant.h" #include "variant.h"
#include "blackmiscfreefunctions.h" #include "blackmiscfreefunctions.h"
#include "icon.h" #include "icon.h"
#include "logmessage.h"
#include <QDBusArgument> #include <QDBusArgument>
#include <QDBusMetaType> #include <QDBusMetaType>
#include <QDBusVariant> #include <QDBusVariant>
@@ -44,18 +45,26 @@ namespace BlackMisc
auto *bMeta = b.getValueObjectMetaInfo(); auto *bMeta = b.getValueObjectMetaInfo();
if (aMeta && bMeta) if (aMeta && bMeta)
{ {
const void *casted = nullptr; try
if ((casted = aMeta->upCastTo(a.data(), bMeta->getMetaTypeId())))
{ {
return bMeta->compareImpl(casted, b.data()); const void *casted = nullptr;
if ((casted = aMeta->upCastTo(a.data(), bMeta->getMetaTypeId())))
{
return bMeta->compareImpl(casted, b.data());
}
else if ((casted = bMeta->upCastTo(b.data(), aMeta->getMetaTypeId())))
{
return aMeta->compareImpl(a.data(), casted);
}
else
{
qWarning() << "Comparing two CVariants containing unrelated value objects";
return 0;
}
} }
else if ((casted = bMeta->upCastTo(b.data(), aMeta->getMetaTypeId()))) catch (const Private::CVariantException &ex)
{ {
return aMeta->compareImpl(a.data(), casted); CLogMessage().debug() << ex.what();
}
else
{
qWarning() << "Comparing two CVariants containing unrelated value objects";
return 0; return 0;
} }
} }
@@ -81,6 +90,7 @@ namespace BlackMisc
case QVariant::Char: json.insert("value", m_v.toString()); case QVariant::Char: json.insert("value", m_v.toString());
case QVariant::ByteArray: json.insert("value", m_v.toString()); case QVariant::ByteArray: json.insert("value", m_v.toString());
default: default:
try
{ {
auto *meta = getValueObjectMetaInfo(); auto *meta = getValueObjectMetaInfo();
if (meta) if (meta)
@@ -96,6 +106,10 @@ namespace BlackMisc
qWarning() << "Unsupported CVariant type for toJson"; qWarning() << "Unsupported CVariant type for toJson";
} }
} }
catch (const Private::CVariantException &ex)
{
CLogMessage().debug() << ex.what();
}
} }
return json; return json;
} }
@@ -117,6 +131,7 @@ namespace BlackMisc
case QVariant::Char: m_v.setValue(json.value("value").toString().size() > 0 ? json.value("value").toString().at(0) : '\0'); case QVariant::Char: m_v.setValue(json.value("value").toString().size() > 0 ? json.value("value").toString().at(0) : '\0');
case QVariant::ByteArray: m_v.setValue(json.value("value").toString().toLatin1()); case QVariant::ByteArray: m_v.setValue(json.value("value").toString().toLatin1());
default: default:
try
{ {
auto *meta = Private::getValueObjectMetaInfo(typeId); auto *meta = Private::getValueObjectMetaInfo(typeId);
if (meta) if (meta)
@@ -137,6 +152,10 @@ namespace BlackMisc
qWarning() << "Unsupported CVariant type for fromJson"; qWarning() << "Unsupported CVariant type for fromJson";
} }
} }
catch (const Private::CVariantException &ex)
{
CLogMessage().debug() << ex.what();
}
} }
} }
@@ -154,6 +173,7 @@ namespace BlackMisc
case QVariant::Char: return qHash(m_v.toChar()); case QVariant::Char: return qHash(m_v.toChar());
case QVariant::ByteArray: return qHash(m_v.toByteArray()); case QVariant::ByteArray: return qHash(m_v.toByteArray());
default: default:
try
{ {
auto *meta = getValueObjectMetaInfo(); auto *meta = getValueObjectMetaInfo();
if (meta) if (meta)
@@ -170,6 +190,11 @@ namespace BlackMisc
return 0; return 0;
} }
} }
catch (const Private::CVariantException &ex)
{
CLogMessage().debug() << ex.what();
return 0;
}
} }
} }
@@ -191,39 +216,78 @@ namespace BlackMisc
{ {
auto *meta = getValueObjectMetaInfo(); auto *meta = getValueObjectMetaInfo();
Q_ASSERT(meta); Q_ASSERT(meta);
meta->setPropertyByIndex(data(), variant, index); try
{
meta->setPropertyByIndex(data(), variant, index);
}
catch (const Private::CVariantException &ex)
{
CLogMessage().debug() << ex.what();
}
} }
CVariant CVariant::propertyByIndex(const BlackMisc::CPropertyIndex &index) const CVariant CVariant::propertyByIndex(const BlackMisc::CPropertyIndex &index) const
{ {
auto *meta = getValueObjectMetaInfo(); auto *meta = getValueObjectMetaInfo();
Q_ASSERT(meta); Q_ASSERT(meta);
CVariant result; try
meta->propertyByIndex(data(), result, index); {
return result; CVariant result;
meta->propertyByIndex(data(), result, index);
return result;
}
catch (const Private::CVariantException &ex)
{
CLogMessage().debug() << ex.what();
return {};
}
} }
QString CVariant::propertyByIndexAsString(const CPropertyIndex &index, bool i18n) const QString CVariant::propertyByIndexAsString(const CPropertyIndex &index, bool i18n) const
{ {
auto *meta = getValueObjectMetaInfo(); auto *meta = getValueObjectMetaInfo();
Q_ASSERT(meta); Q_ASSERT(meta);
return meta->propertyByIndexAsString(data(), index, i18n); try
{
return meta->propertyByIndexAsString(data(), index, i18n);
}
catch (const Private::CVariantException &ex)
{
CLogMessage().debug() << ex.what();
return {};
}
} }
bool CVariant::equalsPropertyByIndex(const CVariant &compareValue, const CPropertyIndex &index) const bool CVariant::equalsPropertyByIndex(const CVariant &compareValue, const CPropertyIndex &index) const
{ {
auto *meta = getValueObjectMetaInfo(); auto *meta = getValueObjectMetaInfo();
Q_ASSERT(meta); Q_ASSERT(meta);
return meta->equalsPropertyByIndex(data(), compareValue, index); try
{
return meta->equalsPropertyByIndex(data(), compareValue, index);
}
catch (const Private::CVariantException &ex)
{
CLogMessage().debug() << ex.what();
return false;
}
} }
CIcon CVariant::toIcon() const CIcon CVariant::toIcon() const
{ {
auto *meta = getValueObjectMetaInfo(); auto *meta = getValueObjectMetaInfo();
if (! meta) { return {}; } if (! meta) { return {}; }
CIcon result; try
meta->toIcon(data(), result); {
return result; CIcon result;
meta->toIcon(data(), result);
return result;
}
catch (const Private::CVariantException &ex)
{
CLogMessage().debug() << ex.what();
return {};
}
} }
QPixmap CVariant::toPixmap() const QPixmap CVariant::toPixmap() const