+ QHashIterator<int, KItemListWidget *> it(m_visibleItems);
+ while (it.hasNext()) {
+ it.next();
+ updateWidgetColumnWidths(it.value());
+ }
+}
+
+qreal KItemListView::columnWidthsSum() const
+{
+ qreal widthsSum = 0;
+ for (const QByteArray &role : qAsConst(m_visibleRoles)) {
+ widthsSum += m_headerWidget->columnWidth(role);
+ }
+ return widthsSum;
+}
+
+QRectF KItemListView::headerBoundaries() const
+{
+ return m_headerWidget->isVisible() ? m_headerWidget->geometry() : QRectF();
+}
+
+bool KItemListView::changesItemGridLayout(const QSizeF &newGridSize, const QSizeF &newItemSize, const QSizeF &newItemMargin) const
+{
+ if (newItemSize.isEmpty() || newGridSize.isEmpty()) {
+ return false;
+ }
+
+ if (m_layouter->scrollOrientation() == Qt::Vertical) {
+ const qreal itemWidth = m_layouter->itemSize().width();
+ if (itemWidth > 0) {
+ const int newColumnCount = itemsPerSize(newGridSize.width(), newItemSize.width(), newItemMargin.width());
+ if (m_model->count() > newColumnCount) {
+ const int oldColumnCount = itemsPerSize(m_layouter->size().width(), itemWidth, m_layouter->itemMargin().width());
+ return oldColumnCount != newColumnCount;
+ }
+ }
+ } else {
+ const qreal itemHeight = m_layouter->itemSize().height();
+ if (itemHeight > 0) {
+ const int newRowCount = itemsPerSize(newGridSize.height(), newItemSize.height(), newItemMargin.height());
+ if (m_model->count() > newRowCount) {
+ const int oldRowCount = itemsPerSize(m_layouter->size().height(), itemHeight, m_layouter->itemMargin().height());
+ return oldRowCount != newRowCount;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool KItemListView::animateChangedItemCount(int changedItemCount) const
+{
+ if (m_itemSize.isEmpty()) {
+ // We have only columns or only rows, but no grid: An animation is usually
+ // welcome when inserting or removing items.
+ return !supportsItemExpanding();
+ }
+
+ if (m_layouter->size().isEmpty() || m_layouter->itemSize().isEmpty()) {
+ return false;
+ }
+
+ const int maximum = (scrollOrientation() == Qt::Vertical) ? m_layouter->size().width() / m_layouter->itemSize().width()
+ : m_layouter->size().height() / m_layouter->itemSize().height();
+ // Only animate if up to 2/3 of a row or column are inserted or removed
+ return changedItemCount <= maximum * 2 / 3;
+}
+
+bool KItemListView::scrollBarRequired(const QSizeF &size) const
+{
+ const QSizeF oldSize = m_layouter->size();
+
+ m_layouter->setSize(size);
+ const qreal maxOffset = m_layouter->maximumScrollOffset();
+ m_layouter->setSize(oldSize);
+
+ return m_layouter->scrollOrientation() == Qt::Vertical ? maxOffset > size.height() : maxOffset > size.width();
+}
+
+int KItemListView::showDropIndicator(const QPointF &pos)
+{
+ QHashIterator<int, KItemListWidget *> it(m_visibleItems);
+ while (it.hasNext()) {
+ it.next();
+ const KItemListWidget *widget = it.value();
+
+ const QPointF mappedPos = widget->mapFromItem(this, pos);
+ const QRectF rect = itemRect(widget->index());
+ if (mappedPos.y() >= 0 && mappedPos.y() <= rect.height()) {
+ if (m_model->supportsDropping(widget->index())) {
+ // Keep 30% of the rectangle as the gap instead of always having a fixed gap
+ const int gap = qMax(qreal(4.0), qreal(0.3) * rect.height());
+ if (mappedPos.y() >= gap && mappedPos.y() <= rect.height() - gap) {
+ return -1;
+ }
+ }
+
+ const bool isAboveItem = (mappedPos.y() < rect.height() / 2);
+ const qreal y = isAboveItem ? rect.top() : rect.bottom();
+
+ const QRectF draggingInsertIndicator(rect.left(), y, rect.width(), 1);
+ if (m_dropIndicator != draggingInsertIndicator) {
+ m_dropIndicator = draggingInsertIndicator;
+ update();
+ }
+
+ int index = widget->index();
+ if (!isAboveItem) {
+ ++index;
+ }
+ return index;
+ }
+ }
+
+ const QRectF firstItemRect = itemRect(firstVisibleIndex());
+ return (pos.y() <= firstItemRect.top()) ? 0 : -1;
+}
+
+void KItemListView::hideDropIndicator()
+{
+ if (!m_dropIndicator.isNull()) {
+ m_dropIndicator = QRectF();
+ update();
+ }
+}
+
+void KItemListView::updateGroupHeaderHeight()
+{
+ qreal groupHeaderHeight = m_styleOption.fontMetrics.height();
+ qreal groupHeaderMargin = 0;
+
+ if (scrollOrientation() == Qt::Horizontal) {
+ // The vertical margin above and below the header should be
+ // equal to the horizontal margin, not the vertical margin
+ // from m_styleOption.
+ groupHeaderHeight += 2 * m_styleOption.horizontalMargin;
+ groupHeaderMargin = m_styleOption.horizontalMargin;
+ } else if (m_itemSize.isEmpty()) {
+ groupHeaderHeight += 4 * m_styleOption.padding;
+ groupHeaderMargin = m_styleOption.iconSize / 2;
+ } else {
+ groupHeaderHeight += 2 * m_styleOption.padding + m_styleOption.verticalMargin;
+ groupHeaderMargin = m_styleOption.iconSize / 4;
+ }
+ m_layouter->setGroupHeaderHeight(groupHeaderHeight);
+ m_layouter->setGroupHeaderMargin(groupHeaderMargin);
+
+ updateVisibleGroupHeaders();
+}
+
+void KItemListView::updateSiblingsInformation(int firstIndex, int lastIndex)
+{
+ if (!supportsItemExpanding() || !m_model) {
+ return;
+ }
+
+ if (firstIndex < 0 || lastIndex < 0) {
+ firstIndex = m_layouter->firstVisibleIndex();
+ lastIndex = m_layouter->lastVisibleIndex();
+ } else {
+ const bool isRangeVisible = (firstIndex <= m_layouter->lastVisibleIndex() && lastIndex >= m_layouter->firstVisibleIndex());
+ if (!isRangeVisible) {
+ return;
+ }