Issue #77 Move mixin classes to separate files

By separating them from unrelated code, their dependents
can use them without depending on unrelated code, which
in turn helps to reduce cyclic dependencies.
This commit is contained in:
Mat Sutcliffe
2020-08-25 23:31:23 +01:00
parent 4a6d94b6d4
commit b80114213d
129 changed files with 1207 additions and 969 deletions

View File

@@ -12,13 +12,14 @@
#define BLACKMISC_PROPERTYINDEXVARIANTMAP_H
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/compare.h"
#include "blackmisc/dbus.h"
#include "blackmisc/mixin/mixincompare.h"
#include "blackmisc/mixin/mixindbus.h"
#include "blackmisc/inheritancetraits.h"
#include "blackmisc/predicates.h"
#include "blackmisc/propertyindex.h"
#include "blackmisc/propertyindexlist.h"
#include "blackmisc/stringutils.h"
#include "blackmisc/mixin/mixinstring.h"
#include "blackmisc/mixin/mixinmetatype.h"
#include "blackmisc/variant.h"
#include <QDBusArgument>
@@ -33,93 +34,6 @@
namespace BlackMisc
{
class CPropertyIndexVariantMap;
namespace Mixin
{
/*!
* CRTP class template from which a derived class can inherit property indexing functions.
*
* This is only a placeholder for future support of implementing property indexing through the tuple system.
* At the moment, it just implements the default properties: String, Icon, and Pixmap.
*/
template <class Derived>
class Index
{
public:
//! Base class enums
enum ColumnIndex
{
IndexPixmap = 10, // manually set to avoid circular dependencies
IndexIcon,
IndexString
};
//! Update by variant map
//! \return number of values changed, with skipEqualValues equal values will not be changed
CPropertyIndexList apply(const CPropertyIndexVariantMap &indexMap, bool skipEqualValues = false);
//! Set property by index
void setPropertyByIndex(const CPropertyIndex &index, const CVariant &variant);
//! Property by index
CVariant propertyByIndex(const CPropertyIndex &index) const;
//! Property by index as String
QString propertyByIndexAsString(const CPropertyIndex &index, bool i18n = false) const;
//! Compare for index
int comparePropertyByIndex(const CPropertyIndex &index, const Derived &compareValue) const;
//! Is given variant equal to value of property index?
bool equalsPropertyByIndex(const CVariant &compareValue, const CPropertyIndex &index) const;
private:
const Derived *derived() const { return static_cast<const Derived *>(this); }
Derived *derived() { return static_cast<Derived *>(this); }
template <typename T, std::enable_if_t<std::is_default_constructible<T>::value, int> = 0>
CVariant myself() const { return CVariant::from(*derived()); }
template <typename T, std::enable_if_t<std::is_default_constructible<T>::value, int> = 0>
void myself(const CVariant &variant) { *derived() = variant.to<T>(); }
template <typename T, std::enable_if_t<! std::is_default_constructible<T>::value, int> = 0>
CVariant myself() const { qFatal("isMyself should have been handled before reaching here"); return {}; }
template <typename T, std::enable_if_t<! std::is_default_constructible<T>::value, int> = 0>
void myself(const CVariant &) { qFatal("isMyself should have been handled before reaching here"); }
template <typename T>
CVariant basePropertyByIndex(const T *base, const CPropertyIndex &index) const { return base->propertyByIndex(index); }
template <typename T>
void baseSetPropertyByIndex(T *base, const CVariant &var, const CPropertyIndex &index) { base->setPropertyByIndex(index, var); }
CVariant basePropertyByIndex(const void *, const CPropertyIndex &index) const
{
qFatal("%s", qPrintable("Property by index not found, index: " + index.toQString())); return {};
}
void baseSetPropertyByIndex(void *, const CVariant &, const CPropertyIndex &index)
{
qFatal("%s", qPrintable("Property by index not found (setter), index: " + index.toQString()));
}
};
/*!
* When a derived class and a base class both inherit from Mixin::Index,
* the derived class uses this macro to disambiguate the inherited members.
*/
// *INDENT-OFF*
# define BLACKMISC_DECLARE_USING_MIXIN_INDEX(DERIVED) \
using ::BlackMisc::Mixin::Index<DERIVED>::apply; \
using ::BlackMisc::Mixin::Index<DERIVED>::setPropertyByIndex; \
using ::BlackMisc::Mixin::Index<DERIVED>::propertyByIndex; \
using ::BlackMisc::Mixin::Index<DERIVED>::propertyByIndexAsString; \
using ::BlackMisc::Mixin::Index<DERIVED>::comparePropertyByIndex; \
using ::BlackMisc::Mixin::Index<DERIVED>::equalsPropertyByIndex;
// *INDENT-ON*
} // Mixin
/*!
* Specialized value object compliant map for variants,
* based on indexes
@@ -225,93 +139,6 @@ namespace BlackMisc
//! \copydoc BlackMisc::Mixin::DataStreamByMetaClass::unmarshalFromDataStream
void unmarshalFromDataStream(QDataStream &stream);
};
namespace Mixin
{
template <class Derived>
CPropertyIndexList Index<Derived>::apply(const BlackMisc::CPropertyIndexVariantMap &indexMap, bool skipEqualValues)
{
if (indexMap.isEmpty()) return {};
CPropertyIndexList changed;
const auto &map = indexMap.map();
for (auto it = map.begin(); it != map.end(); ++it)
{
const CVariant value = it.value();
const CPropertyIndex index = it.key();
if (skipEqualValues)
{
const bool equal = derived()->equalsPropertyByIndex(value, index);
if (equal) { continue; }
}
derived()->setPropertyByIndex(index, value);
changed.push_back(index);
}
return changed;
}
template <class Derived>
void Index<Derived>::setPropertyByIndex(const CPropertyIndex &index, const CVariant &variant)
{
if (index.isMyself())
{
myself<Derived>(variant);
}
else
{
baseSetPropertyByIndex(static_cast<TIndexBaseOfT<Derived> *>(derived()), variant, index);
}
}
template <class Derived>
CVariant Index<Derived>::propertyByIndex(const CPropertyIndex &index) const
{
if (index.isMyself()) { return myself<Derived>(); }
const auto i = index.frontCasted<ColumnIndex>(); // keep that "auto", otherwise I won's compile
switch (i)
{
case IndexIcon: return CVariant::from(derived()->toIcon());
case IndexPixmap: return CVariant::from(derived()->toPixmap());
case IndexString: return CVariant(derived()->toQString());
default: return basePropertyByIndex(static_cast<const TIndexBaseOfT<Derived> *>(derived()), index);
}
}
template <class Derived>
QString Index<Derived>::propertyByIndexAsString(const CPropertyIndex &index, bool i18n) const
{
return derived()->propertyByIndex(index).toQString(i18n);
}
template <class Derived>
bool Index<Derived>::equalsPropertyByIndex(const CVariant &compareValue, const CPropertyIndex &index) const
{
return derived()->propertyByIndex(index) == compareValue;
}
template<class Derived>
int Index<Derived>::comparePropertyByIndex(const CPropertyIndex &index, const Derived &compareValue) const
{
if (this == &compareValue) { return 0; }
if (index.isMyself()) {
// slow, only last resort
return derived()->toQString().compare(compareValue.toQString());
}
const auto i = index.frontCasted<ColumnIndex>();
switch (i)
{
case IndexIcon:
case IndexPixmap:
case IndexString:
default:
break; // also covers
}
// slow, only last resort
return derived()->toQString().compare(compareValue.toQString());
}
} // Mixin
} // ns
Q_DECLARE_METATYPE(BlackMisc::CPropertyIndexVariantMap)