]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kitemlistview.cpp
Merge remote-tracking branch 'origin/KDE/4.11'
[dolphin.git] / src / kitemviews / kitemlistview.cpp
index 9ebad7f8bda0a99a43256c6c529bed4027d689e8..d8edcfc50ac0a2a54314565ca502d2c2ceaa0e39 100644 (file)
@@ -44,6 +44,8 @@
 #include <QStyleOptionRubberBand>
 #include <QTimer>
 
+#include <algorithm>
+
 #include "kitemlistviewaccessible.h"
 
 namespace {
@@ -208,6 +210,11 @@ qreal KItemListView::maximumItemOffset() const
     return m_layouter->maximumItemOffset();
 }
 
+int KItemListView::maximumVisibleItems() const
+{
+    return m_layouter->maximumVisibleItems();
+}
+
 void KItemListView::setVisibleRoles(const QList<QByteArray>& roles)
 {
     const QList<QByteArray> previousRoles = m_visibleRoles;
@@ -673,6 +680,16 @@ void KItemListView::paint(QPainter* painter, const QStyleOptionGraphicsItem* opt
     }
 }
 
+QVariant KItemListView::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+    if (change == QGraphicsItem::ItemSceneHasChanged && scene()) {
+        if (!scene()->views().isEmpty()) {
+            m_styleOption.palette = scene()->views().at(0)->palette();
+        }
+    }
+    return QGraphicsItem::itemChange(change, value);
+}
+
 void KItemListView::setItemSize(const QSizeF& size)
 {
     const QSizeF previousSize = m_itemSize;
@@ -943,6 +960,8 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges)
 
     m_layouter->markAsDirty();
 
+    m_sizeHintResolver->itemsInserted(itemRanges);
+
     int previouslyInsertedCount = 0;
     foreach (const KItemRange& range, itemRanges) {
         // range.index is related to the model before anything has been inserted.
@@ -956,8 +975,6 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges)
         }
         previouslyInsertedCount += count;
 
-        m_sizeHintResolver->itemsInserted(index, count);
-
         // Determine which visible items must be moved
         QList<int> itemsToMove;
         QHashIterator<int, KItemListWidget*> it(m_visibleItems);
@@ -1015,12 +1032,6 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges)
     }
 
     if (hasMultipleRanges) {
-#ifndef QT_NO_DEBUG
-        // Important: Don't read any m_layouter-property inside the for-loop in case if
-        // multiple ranges are given! m_layouter accesses m_sizeHintResolver which is
-        // updated in each loop-cycle and has only a consistent state after the loop.
-        Q_ASSERT(m_layouter->isDirty());
-#endif
         m_endTransactionAnimationHint = NoAnimation;
         endTransaction();
 
@@ -1054,10 +1065,7 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges)
 
     m_layouter->markAsDirty();
 
-    int removedItemsCount = 0;
-    for (int i = 0; i < itemRanges.count(); ++i) {
-        removedItemsCount += itemRanges[i].count;
-    }
+    m_sizeHintResolver->itemsRemoved(itemRanges);
 
     for (int i = itemRanges.count() - 1; i >= 0; --i) {
         const KItemRange& range = itemRanges[i];
@@ -1068,17 +1076,19 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges)
             continue;
         }
 
-        m_sizeHintResolver->itemsRemoved(index, count);
-
         const int firstRemovedIndex = index;
         const int lastRemovedIndex = index + count - 1;
-        const int lastIndex = m_model->count() - 1 + removedItemsCount;
-        removedItemsCount -= count;
+
+        // Remeber which items have to be moved because they are behind the removed range.
+        QVector<int> itemsToMove;
 
         // Remove all KItemListWidget instances that got deleted
-        for (int i = firstRemovedIndex; i <= lastRemovedIndex; ++i) {
-            KItemListWidget* widget = m_visibleItems.value(i);
-            if (!widget) {
+        foreach (KItemListWidget* widget, m_visibleItems) {
+            const int i = widget->index();
+            if (i < firstRemovedIndex) {
+                continue;
+            } else if (i > lastRemovedIndex) {
+                itemsToMove.append(i);
                 continue;
             }
 
@@ -1106,17 +1116,18 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges)
         }
 
         // Update the indexes of all KItemListWidget instances that are located
-        // after the deleted items
-        for (int i = lastRemovedIndex + 1; i <= lastIndex; ++i) {
+        // after the deleted items. It is important to update them in ascending
+        // order to prevent overlaps when setting the new index.
+        std::sort(itemsToMove.begin(), itemsToMove.end());
+        foreach (int i, itemsToMove) {
             KItemListWidget* widget = m_visibleItems.value(i);
-            if (widget) {
-                const int newIndex = i - count;
-                if (hasMultipleRanges) {
-                    setWidgetIndex(widget, newIndex);
-                } else {
-                    // Try to animate the moving of the item
-                    moveWidgetToIndex(widget, newIndex);
-                }
+            Q_ASSERT(widget);
+            const int newIndex = i - count;
+            if (hasMultipleRanges) {
+                setWidgetIndex(widget, newIndex);
+            } else {
+                // Try to animate the moving of the item
+                moveWidgetToIndex(widget, newIndex);
             }
         }
 
@@ -1138,12 +1149,6 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges)
     }
 
     if (hasMultipleRanges) {
-#ifndef QT_NO_DEBUG
-        // Important: Don't read any m_layouter-property inside the for-loop in case if
-        // multiple ranges are given! m_layouter accesses m_sizeHintResolver which is
-        // updated in each loop-cycle and has only a consistent state after the loop.
-        Q_ASSERT(m_layouter->isDirty());
-#endif
         m_endTransactionAnimationHint = NoAnimation;
         endTransaction();
         updateSiblingsInformation();
@@ -1162,7 +1167,7 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges)
 
 void KItemListView::slotItemsMoved(const KItemRange& itemRange, const QList<int>& movedToIndexes)
 {
-    m_sizeHintResolver->itemsMoved(itemRange.index, itemRange.count);
+    m_sizeHintResolver->itemsMoved(itemRange, movedToIndexes);
     m_layouter->markAsDirty();
 
     if (m_controller) {
@@ -1224,6 +1229,13 @@ void KItemListView::slotItemsChanged(const KItemRangeList& itemRanges,
     QAccessible::updateAccessibility(this, 0, QAccessible::TableModelChanged);
 }
 
+void KItemListView::slotGroupsChanged()
+{
+    updateVisibleGroupHeaders();
+    doLayout(NoAnimation);
+    updateSiblingsInformation();
+}
+
 void KItemListView::slotGroupedSortingChanged(bool current)
 {
     m_grouped = current;
@@ -1232,8 +1244,10 @@ void KItemListView::slotGroupedSortingChanged(bool current)
     if (m_grouped) {
         updateGroupHeaderHeight();
     } else {
-        // Clear all visible headers
-        QMutableHashIterator<KItemListWidget*, KItemListGroupHeader*> it (m_visibleGroups);
+        // Clear all visible headers. Note that the QHashIterator takes a copy of
+        // m_visibleGroups. Therefore, it remains valid even if items are removed
+        // from m_visibleGroups in recycleGroupHeaderForWidget().
+        QHashIterator<KItemListWidget*, KItemListGroupHeader*> it(m_visibleGroups);
         while (it.hasNext()) {
             it.next();
             recycleGroupHeaderForWidget(it.key());
@@ -1516,15 +1530,17 @@ void KItemListView::setModel(KItemModelBase* model)
                    this,    SLOT(slotItemsRemoved(KItemRangeList)));
         disconnect(m_model, SIGNAL(itemsMoved(KItemRange,QList<int>)),
                    this,    SLOT(slotItemsMoved(KItemRange,QList<int>)));
+        disconnect(m_model, SIGNAL(groupsChanged()),
+                   this,    SLOT(slotGroupsChanged()));
         disconnect(m_model, SIGNAL(groupedSortingChanged(bool)),
                    this,    SLOT(slotGroupedSortingChanged(bool)));
         disconnect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
                    this,    SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder)));
         disconnect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)),
                    this,    SLOT(slotSortRoleChanged(QByteArray,QByteArray)));
-    }
 
-    m_sizeHintResolver->clearCache();
+        m_sizeHintResolver->itemsRemoved(KItemRangeList() << KItemRange(0, m_model->count()));
+    }
 
     m_model = model;
     m_layouter->setModel(model);
@@ -1539,6 +1555,8 @@ void KItemListView::setModel(KItemModelBase* model)
                 this,    SLOT(slotItemsRemoved(KItemRangeList)));
         connect(m_model, SIGNAL(itemsMoved(KItemRange,QList<int>)),
                 this,    SLOT(slotItemsMoved(KItemRange,QList<int>)));
+        connect(m_model, SIGNAL(groupsChanged()),
+                this,    SLOT(slotGroupsChanged()));
         connect(m_model, SIGNAL(groupedSortingChanged(bool)),
                 this,    SLOT(slotGroupedSortingChanged(bool)));
         connect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
@@ -1548,7 +1566,6 @@ void KItemListView::setModel(KItemModelBase* model)
 
         const int itemCount = m_model->count();
         if (itemCount > 0) {
-            m_sizeHintResolver->itemsInserted(0, itemCount);
             slotItemsInserted(KItemRangeList() << KItemRange(0, itemCount));
         }
     }
@@ -1631,18 +1648,22 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha
             widget->resize(itemBounds.size());
 
             if (animate && changedCount < 0) {
-                // Items have been deleted, move the created item to the
-                // imaginary old position. They will get animated to the new position
-                // later.
-                const QRectF itemRect = m_layouter->itemRect(i - changedCount);
-                if (itemRect.isEmpty()) {
-                    const QPointF invisibleOldPos = (scrollOrientation() == Qt::Vertical)
-                                                    ? QPointF(0, size().height()) : QPointF(size().width(), 0);
-                    widget->setPos(invisibleOldPos);
-                } else {
-                    widget->setPos(itemRect.topLeft());
+                // Items have been deleted.
+                if (i >= changedIndex) {
+                    // The item is located behind the removed range. Move the
+                    // created item to the imaginary old position outside the
+                    // view. It will get animated to the new position later.
+                    const int previousIndex = i - changedCount;
+                    const QRectF itemRect = m_layouter->itemRect(previousIndex);
+                    if (itemRect.isEmpty()) {
+                        const QPointF invisibleOldPos = (scrollOrientation() == Qt::Vertical)
+                                                        ? QPointF(0, size().height()) : QPointF(size().width(), 0);
+                        widget->setPos(invisibleOldPos);
+                    } else {
+                        widget->setPos(itemRect.topLeft());
+                    }
+                    applyNewPos = false;
                 }
-                applyNewPos = false;
             }
 
             if (supportsExpanding && changedCount == 0) {
@@ -1661,7 +1682,7 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha
 
             const bool itemsRemoved = (changedCount < 0);
             const bool itemsInserted = (changedCount > 0);
-            if (itemsRemoved && (i >= changedIndex + changedCount + 1)) {
+            if (itemsRemoved && (i >= changedIndex)) {
                 // The item is located after the removed items. Animate the moving of the position.
                 applyNewPos = !moveWidget(widget, newPos);
             } else if (itemsInserted && i >= changedIndex) {
@@ -2357,7 +2378,8 @@ int KItemListView::showDropIndicator(const QPointF& 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);
+                // Keep 30% of the rectangle as the gap instead of always having a fixed gap
+                const int gap = qMax(4.0, 0.3 * rect.height());
                 if (mappedPos.y() >= gap && mappedPos.y() <= rect.height() - gap) {
                     return -1;
                 }