17 #include "abstractdashview.h"
19 static const qreal bufferRatio = 0.5;
21 AbstractDashView::AbstractDashView()
22 : m_delegateModel(nullptr)
23 , m_asyncRequestedIndex(-1)
26 , m_displayMarginBeginning(0)
27 , m_displayMarginEnd(0)
28 , m_needsRelayout(false)
29 , m_delegateValidated(false)
30 , m_implicitHeightDirty(false)
32 connect(
this, SIGNAL(widthChanged()),
this, SLOT(relayout()));
33 connect(
this, SIGNAL(heightChanged()),
this, SLOT(onHeightChanged()));
36 QAbstractItemModel *AbstractDashView::model()
const
38 return m_delegateModel ? m_delegateModel->model().value<QAbstractItemModel *>() :
nullptr;
41 void AbstractDashView::setModel(QAbstractItemModel *model)
43 if (model != this->model()) {
44 if (!m_delegateModel) {
45 createDelegateModel();
47 disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,
bool)),
this, SLOT(onModelUpdated(QQmlChangeSet,
bool)));
49 m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
50 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,
bool)),
this, SLOT(onModelUpdated(QQmlChangeSet,
bool)));
52 cleanupExistingItems();
54 Q_EMIT modelChanged();
59 QQmlComponent *AbstractDashView::delegate()
const
61 return m_delegateModel ? m_delegateModel->delegate() :
nullptr;
64 void AbstractDashView::setDelegate(QQmlComponent *delegate)
66 if (delegate != this->delegate()) {
67 if (!m_delegateModel) {
68 createDelegateModel();
71 cleanupExistingItems();
73 m_delegateModel->setDelegate(delegate);
75 Q_EMIT delegateChanged();
76 m_delegateValidated =
false;
81 qreal AbstractDashView::columnSpacing()
const
83 return m_columnSpacing;
86 void AbstractDashView::setColumnSpacing(qreal columnSpacing)
88 if (columnSpacing != m_columnSpacing) {
89 m_columnSpacing = columnSpacing;
90 Q_EMIT columnSpacingChanged();
92 if (isComponentComplete()) {
98 qreal AbstractDashView::rowSpacing()
const
103 void AbstractDashView::setRowSpacing(qreal rowSpacing)
105 if (rowSpacing != m_rowSpacing) {
106 m_rowSpacing = rowSpacing;
107 Q_EMIT rowSpacingChanged();
109 if (isComponentComplete()) {
115 qreal AbstractDashView::displayMarginBeginning()
const
117 return m_displayMarginBeginning;
120 void AbstractDashView::setDisplayMarginBeginning(qreal begin)
122 if (m_displayMarginBeginning == begin)
124 m_displayMarginBeginning = begin;
125 if (isComponentComplete()) {
128 emit displayMarginBeginningChanged();
131 qreal AbstractDashView::displayMarginEnd()
const
133 return m_displayMarginEnd;
136 void AbstractDashView::setDisplayMarginEnd(qreal end)
138 if (m_displayMarginEnd == end)
140 m_displayMarginEnd = end;
141 if (isComponentComplete()) {
144 emit displayMarginEndChanged();
147 void AbstractDashView::createDelegateModel()
149 m_delegateModel =
new QQmlDelegateModel(qmlContext(
this),
this);
150 connect(m_delegateModel, SIGNAL(createdItem(
int,QObject*)),
this, SLOT(itemCreated(
int,QObject*)));
151 if (isComponentComplete())
152 m_delegateModel->componentComplete();
155 void AbstractDashView::refill()
157 if (!isComponentComplete() || height() < 0) {
161 const qreal from = -m_displayMarginBeginning;
162 const qreal to = height() + m_displayMarginEnd;
163 const qreal buffer = (to - from) * bufferRatio;
164 const qreal bufferFrom = from - buffer;
165 const qreal bufferTo = to + buffer;
167 bool added = addVisibleItems(from, to,
false);
168 bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
169 added |= addVisibleItems(bufferFrom, bufferTo,
true);
171 if (added || removed) {
172 m_implicitHeightDirty =
true;
177 bool AbstractDashView::addVisibleItems(qreal fillFromY, qreal fillToY,
bool asynchronous)
179 if (fillToY <= fillFromY)
185 if (m_delegateModel->count() == 0)
190 findBottomModelIndexToAdd(&modelIndex, &yPos);
191 bool changed =
false;
192 while (modelIndex < m_delegateModel->count() && yPos <= fillToY) {
193 if (!createItem(modelIndex, asynchronous))
197 findBottomModelIndexToAdd(&modelIndex, &yPos);
200 findTopModelIndexToAdd(&modelIndex, &yPos);
201 while (modelIndex >= 0 && yPos > fillFromY) {
202 if (!createItem(modelIndex, asynchronous))
206 findTopModelIndexToAdd(&modelIndex, &yPos);
212 QQuickItem *AbstractDashView::createItem(
int modelIndex,
bool asynchronous)
214 if (asynchronous && m_asyncRequestedIndex != -1)
217 m_asyncRequestedIndex = -1;
218 QObject*
object = m_delegateModel->object(modelIndex, asynchronous);
219 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
222 m_delegateModel->release(
object);
223 if (!m_delegateValidated) {
224 m_delegateValidated =
true;
225 QObject* delegateObj = delegate();
226 qmlInfo(delegateObj ? delegateObj :
this) <<
"Delegate must be of Item type";
229 m_asyncRequestedIndex = modelIndex;
233 addItemToView(modelIndex, item);
238 void AbstractDashView::releaseItem(QQuickItem *item)
240 QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
241 if (flags & QQmlDelegateModel::Destroyed) {
242 item->setParentItem(
nullptr);
246 void AbstractDashView::setImplicitHeightDirty()
248 m_implicitHeightDirty =
true;
251 void AbstractDashView::itemCreated(
int modelIndex, QObject *
object)
253 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
255 qWarning() <<
"AbstractDashView::itemCreated got a non item for index" << modelIndex;
258 item->setParentItem(
this);
265 if (modelIndex == m_asyncRequestedIndex) {
266 createItem(modelIndex,
false);
267 m_implicitHeightDirty =
true;
272 void AbstractDashView::onModelUpdated(
const QQmlChangeSet &changeSet,
bool reset)
275 cleanupExistingItems();
277 processModelRemoves(changeSet.removes());
283 void AbstractDashView::relayout()
285 m_needsRelayout =
true;
289 void AbstractDashView::onHeightChanged()
294 void AbstractDashView::updatePolish()
299 if (m_needsRelayout) {
301 m_needsRelayout =
false;
302 m_implicitHeightDirty =
true;
307 const qreal from = -m_displayMarginBeginning;
308 const qreal to = height() + m_displayMarginEnd;
309 updateItemCulling(from, to);
311 if (m_implicitHeightDirty) {
312 calculateImplicitHeight();
313 m_implicitHeightDirty =
false;
317 void AbstractDashView::componentComplete()
320 m_delegateModel->componentComplete();
322 QQuickItem::componentComplete();
324 m_needsRelayout =
true;