1 #include "ModelDataExtractor.hxx"
2 
3 #include <QAbstractItemModel>
4 #include <QDebug>
5 
ModelDataExtractor(QObject * parent)6 ModelDataExtractor::ModelDataExtractor(QObject *parent) : QObject(parent)
7 {
8 
9 }
10 
data() const11 QVariant ModelDataExtractor::data() const
12 {
13     if (m_model) {
14         QModelIndex m = m_model->index(m_index, 0);
15         if (!m.isValid())
16             return {};
17 
18         int role = Qt::DisplayRole;
19         if (!m_role.isEmpty()) {
20             const auto& names = m_model->roleNames();
21             role = names.key(m_role.toUtf8(), Qt::DisplayRole);
22         }
23 
24         return m_model->data(m, role);
25     }
26 
27     if (!m_stringsModel.empty()) {
28         if ((m_index < 0) || (m_index >= m_stringsModel.size()))
29             return {};
30 
31         return m_stringsModel.at(m_index);
32     }
33 
34     if (m_rawModel.isArray()) {
35         quint32 uIndex = static_cast<quint32>(m_index);
36         auto v = m_rawModel.property(uIndex);
37         if (v.isQObject()) {
38             // handle the QList<QObject*> case
39             auto obj = v.toQObject();
40             return obj->property(m_role.toUtf8().constData());
41         }
42 
43         return m_rawModel.property(uIndex).toVariant();
44     }
45 
46     if (!m_rawModel.isUndefined() && !m_rawModel.isNull()) {
47         qWarning() << "Unable to convert model data:" << m_rawModel.toString();
48     }
49 
50     return {};
51 }
52 
clear()53 void ModelDataExtractor::clear()
54 {
55     if (m_model) {
56         // disconnect from everything
57         disconnect(m_model, nullptr, this, nullptr);
58         m_model = nullptr;
59     }
60 
61 }
62 
setModel(QJSValue raw)63 void ModelDataExtractor::setModel(QJSValue raw)
64 {
65     if (m_rawModel.strictlyEquals(raw))
66         return;
67 
68     clear();
69     m_rawModel = raw;
70 
71     if (raw.isQObject()) {
72         m_model = qobject_cast<QAbstractItemModel*>(raw.toQObject());
73         if (m_model) {
74             connect(m_model, &QAbstractItemModel::modelReset,
75                     this, &ModelDataExtractor::dataChanged);
76             connect(m_model, &QAbstractItemModel::dataChanged,
77                     this, &ModelDataExtractor::onDataChanged);
78 
79             // ToDo: handle rows added / removed
80         } else {
81             qWarning() << "object but not a QAIM" << raw.toQObject();
82         }
83     } else if (raw.isArray()) {
84 
85     } else if (raw.isVariant() || raw.isObject()) {
86         // special case the QStringList case
87 
88         // for reasons I don't understand yet, QStringList returned as a
89         // property value to JS, does not show up as a variant-in-JS-Value above
90         // (so ::isVariant returns false), but conversion to a variant
91         // works. Hence the 'raw.isObject' above
92 
93         const auto var = raw.toVariant();
94         if (var.type() == QVariant::StringList) {
95             m_stringsModel = var.toStringList();
96         } else {
97             qWarning() << Q_FUNC_INFO << "variant but not a QStringList" << var;
98         }
99     }
100 
101     emit modelChanged();
102     emit dataChanged();
103 }
104 
setIndex(int index)105 void ModelDataExtractor::setIndex(int index)
106 {
107     if (m_index == index)
108         return;
109 
110     m_index = index;
111     emit indexChanged(m_index);
112     emit dataChanged();
113 }
114 
setRole(QString role)115 void ModelDataExtractor::setRole(QString role)
116 {
117     if (m_role == role)
118         return;
119 
120     m_role = role;
121     emit roleChanged(m_role);
122     emit dataChanged();
123 }
124 
onDataChanged(const QModelIndex & topLeft,const QModelIndex & bottomRight)125 void ModelDataExtractor::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
126 {
127     if ((topLeft.row() >= m_index) && (bottomRight.row() <= m_index)) {
128         emit dataChanged();
129     }
130 }
131