+
+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())) {
+ const int gap = qMax(4, m_styleOption.padding);
+ 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;
+ }
+ }
+
+ int previousParents = 0;
+ QBitArray previousSiblings;
+
+ // The rootIndex describes the first index where the siblings get
+ // calculated from. For the calculation the upper most parent item
+ // is required. For performance reasons it is checked first whether
+ // the visible items before or after the current range already
+ // contain a siblings information which can be used as base.
+ int rootIndex = firstIndex;
+
+ KItemListWidget* widget = m_visibleItems.value(firstIndex - 1);
+ if (!widget) {
+ // There is no visible widget before the range, check whether there
+ // is one after the range:
+ widget = m_visibleItems.value(lastIndex + 1);
+ if (widget) {
+ // The sibling information of the widget may only be used if
+ // all items of the range have the same number of parents.
+ const int parents = m_model->expandedParentsCount(lastIndex + 1);
+ for (int i = lastIndex; i >= firstIndex; --i) {
+ if (m_model->expandedParentsCount(i) != parents) {
+ widget = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ if (widget) {
+ // Performance optimization: Use the sibling information of the visible
+ // widget beside the given range.
+ previousSiblings = widget->siblingsInformation();
+ if (previousSiblings.isEmpty()) {
+ return;
+ }
+ previousParents = previousSiblings.count() - 1;
+ previousSiblings.truncate(previousParents);
+ } else {
+ // Potentially slow path: Go back to the upper most parent of firstIndex
+ // to be able to calculate the initial value for the siblings.
+ while (rootIndex > 0 && m_model->expandedParentsCount(rootIndex) > 0) {
+ --rootIndex;
+ }
+ }
+
+ Q_ASSERT(previousParents >= 0);
+ for (int i = rootIndex; i <= lastIndex; ++i) {
+ // Update the parent-siblings in case if the current item represents
+ // a child or an upper parent.
+ const int currentParents = m_model->expandedParentsCount(i);
+ Q_ASSERT(currentParents >= 0);
+ if (previousParents < currentParents) {
+ previousParents = currentParents;
+ previousSiblings.resize(currentParents);
+ previousSiblings.setBit(currentParents - 1, hasSiblingSuccessor(i - 1));
+ } else if (previousParents > currentParents) {
+ previousParents = currentParents;
+ previousSiblings.truncate(currentParents);
+ }
+
+ if (i >= firstIndex) {
+ // The index represents a visible item. Apply the parent-siblings
+ // and update the sibling of the current item.
+ KItemListWidget* widget = m_visibleItems.value(i);
+ if (!widget) {
+ continue;
+ }
+
+ QBitArray siblings = previousSiblings;
+ siblings.resize(siblings.count() + 1);
+ siblings.setBit(siblings.count() - 1, hasSiblingSuccessor(i));
+
+ widget->setSiblingsInformation(siblings);
+ }
+ }
+}
+
+bool KItemListView::hasSiblingSuccessor(int index) const
+{
+ bool hasSuccessor = false;
+ const int parentsCount = m_model->expandedParentsCount(index);
+ int successorIndex = index + 1;
+
+ // Search the next sibling
+ const int itemCount = m_model->count();
+ while (successorIndex < itemCount) {
+ const int currentParentsCount = m_model->expandedParentsCount(successorIndex);
+ if (currentParentsCount == parentsCount) {
+ hasSuccessor = true;
+ break;
+ } else if (currentParentsCount < parentsCount) {
+ break;
+ }
+ ++successorIndex;
+ }
+
+ if (m_grouped && hasSuccessor) {
+ // If the sibling is part of another group, don't mark it as
+ // successor as the group header is between the sibling connections.
+ for (int i = index + 1; i <= successorIndex; ++i) {
+ if (m_layouter->isFirstGroupItem(i)) {
+ hasSuccessor = false;
+ break;
+ }
+ }
+ }
+
+ return hasSuccessor;
+}
+
+void KItemListView::disconnectRoleEditingSignals(int index)
+{
+ KItemListWidget* widget = m_visibleItems.value(index);
+ if (!widget) {
+ return;
+ }
+
+ widget->disconnect(SIGNAL(roleEditingCanceled(int,QByteArray,QVariant)), this);
+ widget->disconnect(SIGNAL(roleEditingFinished(int,QByteArray,QVariant)), this);
+}
+