2#include "verticaljournal.h"
5#pragma GCC diagnostic push
6#pragma GCC diagnostic ignored "-pedantic"
7#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
8#include <private/qquickvisualdatamodel_p.h>
10#include <private/qqmldelegatemodel_p.h>
13#include <private/qquickitem_p.h>
14#pragma GCC diagnostic pop
16static const qreal bufferRatio = 0.5;
18VerticalJournal::VerticalJournal()
19 : m_delegateModel(nullptr)
20 , m_asyncRequestedIndex(-1)
22 , m_horizontalSpacing(0)
23 , m_verticalSpacing(0)
24 , m_delegateCreationBegin(0)
25 , m_delegateCreationEnd(0)
26 , m_delegateCreationBeginValid(false)
27 , m_delegateCreationEndValid(false)
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()));
36QAbstractItemModel *VerticalJournal::model() const
38 return m_delegateModel ? m_delegateModel->model().value<QAbstractItemModel *>() : nullptr;
41void VerticalJournal::setModel(QAbstractItemModel *model)
43 if (model != this->model()) {
44 if (!m_delegateModel) {
45 createDelegateModel();
47#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
48 m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
50 m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
52 // Cleanup the existing items
53 for (int i = 0; i < m_columnVisibleItems.count(); ++i)
55 QList<ViewItem> &column = m_columnVisibleItems[i];
56 Q_FOREACH(const ViewItem &item, column)
60 m_indexColumnMap.clear();
62 Q_EMIT modelChanged();
67QQmlComponent *VerticalJournal::delegate() const
69 return m_delegateModel ? m_delegateModel->delegate() : nullptr;
72void VerticalJournal::setDelegate(QQmlComponent *delegate)
74 if (delegate != this->delegate()) {
75 if (!m_delegateModel) {
76 createDelegateModel();
79 // Cleanup the existing items
80 for (int i = 0; i < m_columnVisibleItems.count(); ++i)
82 QList<ViewItem> &column = m_columnVisibleItems[i];
83 Q_FOREACH(const ViewItem &item, column)
87 m_indexColumnMap.clear();
89 m_delegateModel->setDelegate(delegate);
91 Q_EMIT delegateChanged();
92 m_delegateValidated = false;
97qreal VerticalJournal::columnWidth() const
102void VerticalJournal::setColumnWidth(qreal columnWidth)
104 if (columnWidth != m_columnWidth) {
105 m_columnWidth = columnWidth;
106 Q_EMIT columnWidthChanged();
108 if (isComponentComplete()) {
109 Q_FOREACH(const auto &column, m_columnVisibleItems) {
110 Q_FOREACH(const ViewItem &item, column) {
111 item.m_item->setWidth(columnWidth);
119qreal VerticalJournal::horizontalSpacing() const
121 return m_horizontalSpacing;
124void VerticalJournal::setHorizontalSpacing(qreal horizontalSpacing)
126 if (horizontalSpacing != m_horizontalSpacing) {
127 m_horizontalSpacing = horizontalSpacing;
128 Q_EMIT horizontalSpacingChanged();
130 if (isComponentComplete()) {
136qreal VerticalJournal::verticalSpacing() const
138 return m_verticalSpacing;
141void VerticalJournal::setVerticalSpacing(qreal verticalSpacing)
143 if (verticalSpacing != m_verticalSpacing) {
144 m_verticalSpacing = verticalSpacing;
145 Q_EMIT verticalSpacingChanged();
147 if (isComponentComplete()) {
153qreal VerticalJournal::delegateCreationBegin() const
155 return m_delegateCreationBegin;
158void VerticalJournal::setDelegateCreationBegin(qreal begin)
160 m_delegateCreationBeginValid = true;
161 if (m_delegateCreationBegin == begin)
163 m_delegateCreationBegin = begin;
164 if (isComponentComplete()) {
167 emit delegateCreationBeginChanged();
170void VerticalJournal::resetDelegateCreationBegin()
172 m_delegateCreationBeginValid = false;
173 if (m_delegateCreationBegin == 0)
175 m_delegateCreationBegin = 0;
176 if (isComponentComplete()) {
179 emit delegateCreationBeginChanged();
182qreal VerticalJournal::delegateCreationEnd() const
184 return m_delegateCreationEnd;
187void VerticalJournal::setDelegateCreationEnd(qreal end)
189 m_delegateCreationEndValid = true;
190 if (m_delegateCreationEnd == end)
192 m_delegateCreationEnd = end;
193 if (isComponentComplete()) {
196 emit delegateCreationEndChanged();
199void VerticalJournal::resetDelegateCreationEnd()
201 m_delegateCreationEndValid = false;
202 if (m_delegateCreationEnd == 0)
204 m_delegateCreationEnd = 0;
205 if (isComponentComplete()) {
208 emit delegateCreationEndChanged();
211void VerticalJournal::createDelegateModel()
213#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
214 m_delegateModel = new QQuickVisualDataModel(qmlContext(this), this);
215 connect(m_delegateModel, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(itemCreated(int,QQuickItem*)));
217 m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
218 connect(m_delegateModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(itemCreated(int,QObject*)));
220 if (isComponentComplete())
221 m_delegateModel->componentComplete();
224void VerticalJournal::refill()
226 if (!isComponentComplete()) {
230 const bool delegateRangesValid = m_delegateCreationBeginValid && m_delegateCreationEndValid;
231 const qreal from = delegateRangesValid ? m_delegateCreationBegin : 0;
232 const qreal to = delegateRangesValid ? m_delegateCreationEnd : from + height();
233 const qreal buffer = (to - from) * bufferRatio;
234 const qreal bufferFrom = from - buffer;
235 const qreal bufferTo = to + buffer;
237 bool added = addVisibleItems(from, to, false);
238 bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
239 added |= addVisibleItems(bufferFrom, bufferTo, true);
241 if (added || removed) {
242 m_implicitHeightDirty = true;
246void VerticalJournal::findBottomModelIndexToAdd(int *modelIndex, double *yPos)
251 Q_FOREACH(const auto &column, m_columnVisibleItems) {
252 if (!column.isEmpty()) {
253 const ViewItem &item = column.last();
254 *yPos = qMin(*yPos, item.y() + item.height() + m_verticalSpacing);
255 *modelIndex = qMax(*modelIndex, item.m_modelIndex + 1);
262void VerticalJournal::findTopModelIndexToAdd(int *modelIndex, double *yPos)
264 *modelIndex = INT_MAX;
266 int columnToAddTo = -1;
268 // Find the topmost free column
269 for (int i = 0; i < m_columnVisibleItems.count(); ++i) {
270 const auto &column = m_columnVisibleItems[i];
271 if (!column.isEmpty()) {
272 const ViewItem &item = column.first();
273 const auto itemTopPos = item.y() - m_verticalSpacing;
274 if (itemTopPos > *yPos) {
276 *modelIndex = item.m_modelIndex - 1;
282 if (*modelIndex > 0) {
283 Q_ASSERT(m_indexColumnMap.contains(*modelIndex));
284 while (m_indexColumnMap[*modelIndex] != columnToAddTo) {
285 // We found out that we have to add to columnToAddTo
286 // and thought that we had to add *modelIndex, but history tells
287 // it is not correct, so find up from *modelIndex until we found the index
288 // that has to end up in columnToAddTo
289 *modelIndex = *modelIndex - 1;
290 Q_ASSERT(m_indexColumnMap.contains(*modelIndex));
295bool VerticalJournal::addVisibleItems(qreal fillFrom, qreal fillTo, bool asynchronous)
300 if (m_delegateModel->count() == 0)
305 findBottomModelIndexToAdd(&modelIndex, &yPos);
306 bool changed = false;
307 while (modelIndex < m_delegateModel->count() && yPos <= fillTo) {
308 if (!createItem(modelIndex, asynchronous))
312 findBottomModelIndexToAdd(&modelIndex, &yPos);
315 findTopModelIndexToAdd(&modelIndex, &yPos);
316 while (modelIndex >= 0 && yPos > fillFrom) {
317 if (!createItem(modelIndex, asynchronous))
321 findTopModelIndexToAdd(&modelIndex, &yPos);
327bool VerticalJournal::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
329 bool changed = false;
331 for (int i = 0; i < m_columnVisibleItems.count(); ++i) {
332 QList<ViewItem> &column = m_columnVisibleItems[i];
333 while (!column.isEmpty() && column.first().y() + column.first().height() < bufferFrom) {
334 releaseItem(column.takeFirst());
338 while (!column.isEmpty() && column.last().y() > bufferTo) {
339 releaseItem(column.takeLast());
347QQuickItem *VerticalJournal::createItem(int modelIndex, bool asynchronous)
349 if (asynchronous && m_asyncRequestedIndex != -1)
352 m_asyncRequestedIndex = -1;
353#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
354 QQuickItem *item = m_delegateModel->item(modelIndex, asynchronous);
356 QObject* object = m_delegateModel->object(modelIndex, asynchronous);
357 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
360#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
361 m_asyncRequestedIndex = modelIndex;
364 m_delegateModel->release(object);
365 if (!m_delegateValidated) {
366 m_delegateValidated = true;
367 QObject* delegateObj = delegate();
368 qmlInfo(delegateObj ? delegateObj : this) << "Delegate must be of Item type";
371 m_asyncRequestedIndex = modelIndex;
376 if (item->width() != m_columnWidth) {
377 qWarning() << "Item" << modelIndex << "width is not the one that the columnWidth mandates, resetting it";
378 item->setWidth(m_columnWidth);
380 positionItem(modelIndex, item);
385void VerticalJournal::positionItem(int modelIndex, QQuickItem *item)
387 // Check if we add it to the bottom of existing column items
388 qreal columnToAddY = !m_columnVisibleItems[0].isEmpty() ? m_columnVisibleItems[0].last().y() + m_columnVisibleItems[0].last().height() : 0;
389 int columnToAddTo = 0;
390 for (int i = 1; i < m_columnVisibleItems.count(); ++i) {
391 const qreal iY = !m_columnVisibleItems[i].isEmpty() ? m_columnVisibleItems[i].last().y() + m_columnVisibleItems[i].last().height() : 0;
392 if (iY < columnToAddY) {
397 if (m_columnVisibleItems[columnToAddTo].isEmpty() || m_columnVisibleItems[columnToAddTo].last().m_modelIndex < modelIndex) {
398 item->setX(columnToAddTo * m_columnWidth + m_horizontalSpacing * (columnToAddTo + 1));
399 item->setY(columnToAddY + m_verticalSpacing);
401 m_columnVisibleItems[columnToAddTo] << ViewItem(item, modelIndex);
402 m_indexColumnMap[modelIndex] = columnToAddTo;
404 Q_ASSERT(m_indexColumnMap.contains(modelIndex));
405 columnToAddTo = m_indexColumnMap[modelIndex];
406 columnToAddY = m_columnVisibleItems[columnToAddTo].first().y();
408 item->setX(columnToAddTo * m_columnWidth + m_horizontalSpacing * (columnToAddTo + 1));
409 item->setY(columnToAddY - m_verticalSpacing - item->height());
411 m_columnVisibleItems[columnToAddTo].prepend(ViewItem(item, modelIndex));
415void VerticalJournal::releaseItem(const ViewItem &item)
417#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
418 QQuickVisualModel::ReleaseFlags flags = m_delegateModel->release(item.m_item);
419 if (flags & QQuickVisualModel::Destroyed) {
421 QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item.m_item);
422 if (flags & QQmlDelegateModel::Destroyed) {
424 item.m_item->setParentItem(nullptr);
428#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
429void VerticalJournal::itemCreated(int modelIndex, QQuickItem *item)
432void VerticalJournal::itemCreated(int modelIndex, QObject *object)
434 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
436 qWarning() << "ListViewWithPageHeader::itemCreated got a non item for index" << modelIndex;
440 item->setParentItem(this);
441 if (modelIndex == m_asyncRequestedIndex) {
442 createItem(modelIndex, false);
443 m_implicitHeightDirty = true;
448void VerticalJournal::relayout()
450 m_needsRelayout = true;
454void VerticalJournal::onHeightChanged()
459void VerticalJournal::updatePolish()
464 if (m_needsRelayout) {
465 QList<ViewItem> allItems;
466 Q_FOREACH(const auto &column, m_columnVisibleItems)
471 const int nColumns = qMax(1., floor((double)(width() - m_horizontalSpacing) / (m_columnWidth + m_horizontalSpacing)));
472 m_columnVisibleItems.resize(nColumns);
473 m_indexColumnMap.clear();
474 for (int i = 0; i < nColumns; ++i)
475 m_columnVisibleItems[i].clear();
477 // If the first of allItems doesn't contain index 0 we need to drop them
478 // all since we can't consistently relayout without the first item being there
480 if (!allItems.isEmpty()) {
481 if (allItems.first().m_modelIndex == 0) {
482 Q_FOREACH(const ViewItem &item, allItems)
483 positionItem(item.m_modelIndex, item.m_item);
485 Q_FOREACH(const ViewItem &item, allItems)
490 m_needsRelayout = false;
495 const bool delegateRangesValid = m_delegateCreationBeginValid && m_delegateCreationEndValid;
496 const qreal from = delegateRangesValid ? m_delegateCreationBegin : 0;
497 const qreal to = delegateRangesValid ? m_delegateCreationEnd : from + height();
498 Q_FOREACH(const auto &column, m_columnVisibleItems) {
499 Q_FOREACH(const ViewItem &item, column) {
500 QQuickItemPrivate::get(item.m_item)->setCulled(item.y() + item.height() <= from || item.y() >= to);
504 if (m_implicitHeightDirty) {
505 m_implicitHeightDirty = false;
507 int lastModelIndex = -1;
508 qreal bottomMostY = 0;
509 Q_FOREACH(const auto &column, m_columnVisibleItems) {
510 if (!column.isEmpty()) {
511 const ViewItem &item = column.last();
512 lastModelIndex = qMax(lastModelIndex, item.m_modelIndex);
513 bottomMostY = qMax(bottomMostY, item.y() + item.height() + m_verticalSpacing);
516 if (lastModelIndex >= 0) {
517 const double averageHeight = bottomMostY / (lastModelIndex + 1);
518 setImplicitHeight(bottomMostY + averageHeight * (model()->rowCount() - lastModelIndex - 1));
520 setImplicitHeight(0);
525void VerticalJournal::componentComplete()
528 m_delegateModel->componentComplete();
530 QQuickItem::componentComplete();
532 const int nColumns = ceil((double)(width() - m_horizontalSpacing) / (m_columnWidth + m_horizontalSpacing));
533 m_columnVisibleItems.resize(nColumns);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list