Skip to content

Instantly share code, notes, and snippets.

@oKcerG
Forked from anonymous/qqmlobjectlistmodel.h
Last active August 29, 2015 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oKcerG/fe747a3990cc286098c6 to your computer and use it in GitHub Desktop.
Save oKcerG/fe747a3990cc286098c6 to your computer and use it in GitHub Desktop.
#ifndef QQMLOBJECTLISTMODEL_H
#define QQMLOBJECTLISTMODEL_H
#include "qqmlmodels.h"
#include <QByteArray>
#include <QChar>
#include <QDebug>
#include <QHash>
#include <QList>
#include <QMetaMethod>
#include <QMetaObject>
#include <QMetaProperty>
#include <QString>
#include <QVariant>
#include <QVector>
#include <qqmlobjectlistmodel_p.h>
template <class T>
class QQmlObjectListModel : public QAbstractListModel {
public:
explicit QQmlObjectListModel (QObject * parent = nullptr) :
QAbstractListModel(parent),
m_privateImpl(new QQmlObjectListModelPrivate(this, [=](QObject* o){return this->indexOf(qobject_cast<T*>(o));}))
{
QMetaObject metaObject = T::staticMetaObject;
qDebug() << m_privateImpl;
m_privateImpl->m_roles.insert (BASE_ROLE-1, QString(metaObject.className()).toLower().toUtf8());
m_privateImpl->m_roles.insert (BASE_ROLE, QByteArrayLiteral ("qtObject"));
for (int propertyIdx = 0; propertyIdx < metaObject.propertyCount (); propertyIdx++) {
int role = m_privateImpl->m_roles.count ();
QMetaProperty metaProp = metaObject.property (propertyIdx);
m_privateImpl->m_roles.insert (role, metaProp.name ());
if (metaProp.hasNotifySignal ()) {
m_privateImpl->m_signalIdxToRole.insert (metaProp.notifySignalIndex (), role);
}
}
}
~QQmlObjectListModel ()
{
clear ();
}
// QAbstractItemModel interface reimplemented
virtual int rowCount (const QModelIndex & parent = QModelIndex ()) const
{
Q_UNUSED (parent);
return m_items.count ();
}
virtual bool setData (const QModelIndex & index, const QVariant & value, int role)
{
bool ret = false;
T* item = get(index.row ());
QByteArray rolename = m_privateImpl->m_roles.value(role, EMPTY_BA);
if (item != NULL && role > BASE_ROLE && !rolename.isEmpty()) {
ret = item->setProperty(rolename, value);
}
return ret;
}
virtual QVariant data (const QModelIndex & index, int role) const
{
QVariant ret;
T* item = get (index.row());
QByteArray rolename = m_privateImpl->m_roles.value(role, EMPTY_BA);
if (item != NULL && !rolename.isEmpty()) {
ret.setValue(role > BASE_ROLE ? item->property(rolename) : QVariant::fromValue(item));
}
return ret;
}
virtual QHash<int, QByteArray> roleNames () const
{
return m_privateImpl->m_roles;
}
void clear ()
{
if (!isEmpty())
{
beginRemoveRows (NO_PARENT, 0, count () -1);
for (T* item : m_items) {
dereferenceItem (item);
}
m_items.clear ();
endRemoveRows ();
}
}
int count () const
{
return m_items.count();
}
bool isEmpty () const
{
return m_items.isEmpty();
}
bool contains (T * item) const
{
return m_items.contains(item);
}
int indexOf (T * item) const
{
return m_items.indexOf(item);
}
int roleForName (QByteArray name) const
{
return m_privateImpl->m_roles.key (name, -1);
}
void append(T* item)
{
if (item != NULL) {
int pos = m_items.count ();
beginInsertRows (NO_PARENT, pos, pos);
m_items.append (item);
referenceItem (item);
endInsertRows ();
}
}
void append(QList<T*> itemList)
{
itemList.removeAll (NULL);
if (!itemList.isEmpty ()) {
int pos = m_items.count ();
beginInsertRows (NO_PARENT, pos, pos + itemList.count () -1);
m_items.append (itemList);
foreach (T* item, itemList) {
referenceItem (item);
}
endInsertRows ();
}
}
void prepend(QList<T*> itemList)
{
itemList.removeAll (NULL);
if (!itemList.isEmpty ()) {
beginInsertRows (NO_PARENT, 0, itemList.count () -1);
int offset = 0;
foreach (T* item, itemList) {
m_items.insert (offset, item);
referenceItem (item);
}
endInsertRows ();
}
}
void insert(int idx, QList<T*> itemList)
{
itemList.removeAll (NULL);
if (!itemList.isEmpty ()) {
beginInsertRows (NO_PARENT, idx, idx + itemList.count () -1);
int offset = 0;
foreach (T* item, itemList) {
m_items.insert (idx + offset, item);
referenceItem (item);
offset++;
}
endInsertRows ();
}
}
void move(int idx, int pos)
{
beginMoveRows (NO_PARENT, idx, idx, NO_PARENT, pos);
m_items.move (idx, pos);
endMoveRows ();
}
void remove(T* item)
{
if (item != NULL) {
int idx = m_items.indexOf (item);
remove (idx);
}
}
void remove(int idx)
{
if (idx >= 0 && idx < m_items.size ()) {
beginRemoveRows (NO_PARENT, idx, idx);
T* item = m_items.takeAt (idx);
dereferenceItem (item);
endRemoveRows ();
}
}
T* get(int idx) const
{
T* ret = NULL;
if (idx >= 0 && idx < m_items.size ()) {
ret = m_items.value (idx);
}
return ret;
}
T* first() const
{
return m_items.first ();
}
T* last() const
{
return m_items.last ();
}
QList<T*> list() const
{
return m_items;
}
typename QList<T>::const_iterator begin() const
{
return m_items.begin();
}
typename QList<T>::const_iterator end() const
{
return m_items.end();
}
typename QList<T>::iterator begin()
{
return m_items.begin();
}
typename QList<T>::iterator end()
{
return m_items.end();
}
private:
void referenceItem (T* item)
{
m_privateImpl->referenceItem(item);
}
void dereferenceItem (T* item)
{
m_privateImpl->dereferenceItem(item);
}
QList<T*> m_items;
QQmlObjectListModelPrivate* m_privateImpl;
};
#endif // QQMLOBJECTLISTMODEL_H
#ifndef QQMLOBJECTLISTMODEL_P_H
#define QQMLOBJECTLISTMODEL_P_H
#include <QAbstractListModel>
#include <QMetaMethod>
#include <functional>
#include <QDebug>
#include "qqmlmodels.h"
class QQmlObjectListModelPrivate : public QObject {
Q_OBJECT
public:
explicit QQmlObjectListModelPrivate (QAbstractListModel* parent, std::function<int(QObject*)> indexFunction) : QObject(parent), m_publicObject(parent), m_indexFunction(indexFunction)
{
m_handler = metaObject()->method(metaObject()->indexOfMethod ("onItemPropertyChanged()"));
}
Q_SLOT void onItemPropertyChanged ()
{
QObject * item = sender();
int row = m_indexFunction(item);
int sig = senderSignalIndex ();
int role = m_signalIdxToRole.value (sig, -1);
if (row >= 0 && role >= 0) {
QModelIndex index = m_publicObject->index (row, 0, NO_PARENT);
emit m_publicObject->dataChanged (index, index, QVector<int> (1, role));
emit m_publicObject->dataChanged (index, index);
}
}
void referenceItem (QObject * item)
{
if (item != nullptr) {
if (item->parent() == nullptr)
item->setParent(m_publicObject);
for (int signalIdx : m_signalIdxToRole.keys())
{
QMetaMethod notifier = item->metaObject()->method(signalIdx);
QObject::connect (item, notifier, this, m_handler);
}
}
}
void dereferenceItem (QObject * item) {
if (item != nullptr) {
item->disconnect ();
if (item->parent () == m_publicObject) // FIXME : maybe that's not the best way to test ownership ?
item->deleteLater ();
}
}
QAbstractListModel* m_publicObject;
std::function<int(QObject*)> m_indexFunction;
QMetaMethod m_handler;
QHash<int, QByteArray> m_roles;
QHash<int, int> m_signalIdxToRole;
};
#endif // QQMLOBJECTLISTMODEL_P_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment