-
-
Save oKcerG/fe747a3990cc286098c6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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