28 #include "verticaljournal.h"
30 #pragma GCC diagnostic push
31 #pragma GCC diagnostic ignored "-pedantic"
32 #include <private/qquickitem_p.h>
33 #pragma GCC diagnostic pop
35 static const qreal bufferRatio = 0.5;
37 VerticalJournal::VerticalJournal()
42 qreal VerticalJournal::columnWidth()
const
47 void VerticalJournal::setColumnWidth(qreal columnWidth)
49 if (columnWidth != m_columnWidth) {
50 m_columnWidth = columnWidth;
51 Q_EMIT columnWidthChanged();
53 if (isComponentComplete()) {
54 Q_FOREACH(
const auto &column, m_columnVisibleItems) {
55 Q_FOREACH(
const ViewItem &item, column) {
56 item.m_item->setWidth(columnWidth);
64 void VerticalJournal::findBottomModelIndexToAdd(
int *modelIndex, qreal *yPos)
67 *yPos = std::numeric_limits<qreal>::max();
69 Q_FOREACH(
const auto &column, m_columnVisibleItems) {
70 if (!column.isEmpty()) {
71 const ViewItem &item = column.last();
72 *yPos = qMin(*yPos, item.y() + item.height() + rowSpacing());
73 *modelIndex = qMax(*modelIndex, item.m_modelIndex + 1);
80 void VerticalJournal::findTopModelIndexToAdd(
int *modelIndex, qreal *yPos)
83 *yPos = std::numeric_limits<qreal>::lowest();
84 int columnToAddTo = -1;
87 for (
int i = 0; i < m_columnVisibleItems.count(); ++i) {
88 const auto &column = m_columnVisibleItems[i];
89 if (!column.isEmpty()) {
90 const ViewItem &item = column.first();
91 const auto itemTopPos = item.y() - rowSpacing();
92 if (itemTopPos > *yPos) {
94 *modelIndex = item.m_modelIndex - 1;
100 if (*modelIndex > 0) {
101 Q_ASSERT(m_indexColumnMap.contains(*modelIndex));
102 while (m_indexColumnMap[*modelIndex] != columnToAddTo) {
107 *modelIndex = *modelIndex - 1;
108 Q_ASSERT(m_indexColumnMap.contains(*modelIndex));
113 bool VerticalJournal::removeNonVisibleItems(qreal bufferFromY, qreal bufferToY)
115 bool changed =
false;
117 for (
int i = 0; i < m_columnVisibleItems.count(); ++i) {
118 QList<ViewItem> &column = m_columnVisibleItems[i];
119 while (!column.isEmpty() && column.first().y() + column.first().height() < bufferFromY) {
120 releaseItem(column.takeFirst().m_item);
124 while (!column.isEmpty() && column.last().y() > bufferToY) {
125 releaseItem(column.takeLast().m_item);
133 void VerticalJournal::addItemToView(
int modelIndex, QQuickItem *item)
135 if (item->width() != m_columnWidth) {
136 qWarning() <<
"Item" << modelIndex <<
"width is not the one that the columnWidth mandates, resetting it";
137 item->setWidth(m_columnWidth);
141 const QList<ViewItem> &firstColumn = m_columnVisibleItems[0];
142 qreal columnToAddY = !firstColumn.isEmpty() ? firstColumn.last().y() + firstColumn.last().height() : -rowSpacing();
143 int columnToAddTo = 0;
144 for (
int i = 1; i < m_columnVisibleItems.count(); ++i) {
145 const QList<ViewItem> &column = m_columnVisibleItems[i];
146 const qreal iY = !column.isEmpty() ? column.last().y() + column.last().height() : -rowSpacing();
147 if (iY < columnToAddY) {
153 const QList<ViewItem> &columnToAdd = m_columnVisibleItems[columnToAddTo];
154 if (columnToAdd.isEmpty() || columnToAdd.last().m_modelIndex < modelIndex) {
155 item->setX(columnToAddTo * (m_columnWidth + columnSpacing()));
156 item->setY(columnToAddY + rowSpacing());
158 m_columnVisibleItems[columnToAddTo] << ViewItem(item, modelIndex);
159 m_indexColumnMap[modelIndex] = columnToAddTo;
161 Q_ASSERT(m_indexColumnMap.contains(modelIndex));
162 columnToAddTo = m_indexColumnMap[modelIndex];
163 columnToAddY = m_columnVisibleItems[columnToAddTo].first().y();
165 item->setX(columnToAddTo * (m_columnWidth + columnSpacing()));
166 item->setY(columnToAddY - rowSpacing() - item->height());
168 m_columnVisibleItems[columnToAddTo].prepend(ViewItem(item, modelIndex));
172 void VerticalJournal::cleanupExistingItems()
175 for (
int i = 0; i < m_columnVisibleItems.count(); ++i) {
176 QList<ViewItem> &column = m_columnVisibleItems[i];
177 Q_FOREACH(
const ViewItem &item, column)
178 releaseItem(item.m_item);
181 m_indexColumnMap.clear();
182 setImplicitHeightDirty();
187 int lastModelIndex = -1;
188 qreal bottomMostY = 0;
189 Q_FOREACH(
const auto &column, m_columnVisibleItems) {
190 if (!column.isEmpty()) {
191 const ViewItem &item = column.last();
192 lastModelIndex = qMax(lastModelIndex, item.m_modelIndex);
193 bottomMostY = qMax(bottomMostY, item.y() + item.height());
196 if (lastModelIndex >= 0) {
197 const double averageHeight = bottomMostY / (lastModelIndex + 1);
198 setImplicitHeight(bottomMostY + averageHeight * (model()->rowCount() - lastModelIndex - 1));
200 setImplicitHeight(0);
204 void VerticalJournal::doRelayout()
206 QList<ViewItem> allItems;
207 Q_FOREACH(
const auto &column, m_columnVisibleItems)
212 const
int nColumns = qMax(1., floor((
double)(width() + columnSpacing()) / (m_columnWidth + columnSpacing())));
213 m_columnVisibleItems.resize(nColumns);
214 m_indexColumnMap.clear();
215 for (
int i = 0; i < nColumns; ++i)
216 m_columnVisibleItems[i].clear();
221 if (!allItems.isEmpty()) {
222 if (allItems.first().m_modelIndex == 0) {
223 Q_FOREACH(
const ViewItem &item, allItems)
224 addItemToView(item.m_modelIndex, item.m_item);
226 Q_FOREACH(
const ViewItem &item, allItems)
227 releaseItem(item.m_item);
232 void VerticalJournal::updateItemCulling(qreal visibleFromY, qreal visibleToY)
234 Q_FOREACH(
const auto &column, m_columnVisibleItems) {
235 Q_FOREACH(
const ViewItem &item, column) {
236 const bool cull = item.y() + item.height() <= visibleFromY || item.y() >= visibleToY;
237 QQuickItemPrivate::get(item.m_item)->setCulled(cull);
242 void VerticalJournal::processModelRemoves(
const QVector<QQmlChangeSet::Remove> &removes)
244 Q_FOREACH(
const QQmlChangeSet::Remove &
remove, removes) {
245 for (
int i =
remove.count - 1; i >= 0; --i) {
246 const int indexToRemove =
remove.index + i;
252 int lastCreatedIndex = INT_MIN;
253 for (
int i = 0; !found && i < m_columnVisibleItems.count(); ++i) {
254 QList<ViewItem> &column = m_columnVisibleItems[i];
255 if (!column.isEmpty()) {
256 const int lastColumnIndex = column.last().m_modelIndex;
257 if (lastColumnIndex == indexToRemove) {
258 releaseItem(column.takeLast().m_item);
261 lastCreatedIndex = qMax(lastCreatedIndex, lastColumnIndex);
265 if (indexToRemove < lastCreatedIndex) {
266 qFatal(
"VerticalJournal only supports removal from the end of the model");
268 setImplicitHeightDirty();