]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kitemlistview.cpp
Compact view: Padding- and margin-improvements for grouped alignments
[dolphin.git] / src / kitemviews / kitemlistview.cpp
index 323e6745296e276392b17c81d143781b5e381f11..b7d4c247097577ea8759832e57138b1f26397d43 100644 (file)
@@ -833,6 +833,7 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges)
 
         if (!hasMultipleRanges) {
             doLayout(animateChangedItemCount(count) ? Animation : NoAnimation, index, count);
+            updateSiblingsInformation();
         }
     }
 
@@ -841,7 +842,9 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges)
     }
 
     if (hasMultipleRanges) {
+        m_endTransactionAnimationHint = NoAnimation;
         endTransaction();
+        updateSiblingsInformation();
     }
 }
 
@@ -919,6 +922,7 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges)
             m_activeTransactions = 0;
             doLayout(animateChangedItemCount(count) ? Animation : NoAnimation, index, -count);
             m_activeTransactions = activeTransactions;
+            updateSiblingsInformation();
         }
     }
 
@@ -927,7 +931,9 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges)
     }
 
     if (hasMultipleRanges) {
+        m_endTransactionAnimationHint = NoAnimation;
         endTransaction();
+        updateSiblingsInformation();
     }
 }
 
@@ -955,6 +961,7 @@ void KItemListView::slotItemsMoved(const KItemRange& itemRange, const QList<int>
     }
 
     doLayout(NoAnimation);
+    updateSiblingsInformation();
 }
 
 void KItemListView::slotItemsChanged(const KItemRangeList& itemRanges,
@@ -1346,6 +1353,10 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha
 
     const int lastVisibleIndex = m_layouter->lastVisibleIndex();
 
+    int firstSibblingIndex = -1;
+    int lastSibblingIndex = -1;
+    const bool supportsExpanding = supportsItemExpanding();
+
     QList<int> reusableItems = recycleInvisibleItems(firstVisibleIndex, lastVisibleIndex, hint);
 
     // Assure that for each visible item a KItemListWidget is available. KItemListWidget
@@ -1390,6 +1401,13 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha
                 }
                 applyNewPos = false;
             }
+
+            if (supportsExpanding && changedCount == 0) {
+                if (firstSibblingIndex < 0) {
+                    firstSibblingIndex = i;
+                }
+                lastSibblingIndex = i;
+            }
         }
 
         if (animate) {
@@ -1452,6 +1470,11 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha
         recycleWidget(m_visibleItems.value(index));
     }
 
+    if (supportsExpanding && firstSibblingIndex >= 0) {
+        Q_ASSERT(lastSibblingIndex >= 0);
+        updateSiblingsInformation(firstSibblingIndex, lastSibblingIndex);
+    }
+
     if (m_grouped) {
         // Update the layout of all visible group headers
         QHashIterator<KItemListWidget*, KItemListGroupHeader*> it(m_visibleGroups);
@@ -1627,6 +1650,7 @@ void KItemListView::updateWidgetProperties(KItemListWidget* widget, int index)
     widget->setEnabledSelectionToggle(enabledSelectionToggles());
     widget->setIndex(index);
     widget->setData(m_model->data(index));
+    widget->setSiblingsInformation(QBitArray());
 }
 
 void KItemListView::updateGroupHeaderForWidget(KItemListWidget* widget)
@@ -1696,7 +1720,7 @@ void KItemListView::updateGroupHeaderLayout(KItemListWidget* widget)
         groupHeader->setPos(-widget->x(), -groupHeaderRect.height());
         groupHeader->resize(size().width(), groupHeaderRect.size().height());
     } else {
-        groupHeader->setPos(groupHeaderRect.x() - itemRect.x(), -groupHeaderRect.height());
+        groupHeader->setPos(groupHeaderRect.x() - itemRect.x(), -widget->y());
         groupHeader->resize(groupHeaderRect.size());
     }
 }
@@ -1952,15 +1976,21 @@ bool KItemListView::scrollBarRequired(const QSizeF& size) const
 
 void KItemListView::updateGroupHeaderHeight()
 {
-    const qreal groupHeaderHeight = m_styleOption.fontMetrics.height() + m_styleOption.padding * 2;
-
+    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()){
-        groupHeaderMargin = groupHeaderHeight / 2;
+        groupHeaderHeight += 2 * m_styleOption.padding;
+        groupHeaderMargin = m_styleOption.iconSize / 2;
     } else {
-        groupHeaderMargin = m_styleOption.verticalMargin * 2;
+        groupHeaderHeight += 2 * m_styleOption.padding;
+        groupHeaderMargin = m_styleOption.iconSize / 4;
     }
     m_layouter->setGroupHeaderHeight(groupHeaderHeight);
     m_layouter->setGroupHeaderMargin(groupHeaderMargin);
@@ -1968,6 +1998,133 @@ void KItemListView::updateGroupHeaderHeight()
     updateVisibleGroupHeaders();
 }
 
+void KItemListView::updateSiblingsInformation(int firstIndex, int lastIndex)
+{
+    if (!supportsItemExpanding()) {
+        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;
+}
+
 int KItemListView::calculateAutoScrollingIncrement(int pos, int range, int oldInc)
 {
     int inc = 0;