]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Merge remote-tracking branch 'origin/KDE/4.11'
authorFrank Reininghaus <frank78ac@googlemail.com>
Mon, 30 Sep 2013 22:15:04 +0000 (00:15 +0200)
committerFrank Reininghaus <frank78ac@googlemail.com>
Mon, 30 Sep 2013 22:15:04 +0000 (00:15 +0200)
1  2 
src/kitemviews/kfileitemmodel.cpp
src/tests/kfileitemmodeltest.cpp

index c06f87e06ba8463b7a65c2c90c12d5ed2f3936f5,7b7c39ad74b643ae6c7ecc9867cdd8ffef46d05d..bd905bf07da126d8ddf2d1c3fe7a49e0c7bc3ac9
@@@ -468,7 -468,10 +468,7 @@@ bool KFileItemModel::isExpandable(int i
  int KFileItemModel::expandedParentsCount(int index) const
  {
      if (index >= 0 && index < count()) {
 -        const int parentsCount = m_itemData.at(index)->values.value("expandedParentsCount").toInt();
 -        if (parentsCount > 0) {
 -            return parentsCount;
 -        }
 +        return expandedParentsCount(m_itemData.at(index));
      }
      return 0;
  }
@@@ -682,6 -685,7 +682,6 @@@ void KFileItemModel::resortAllItems(
          oldUrls.append(itemData->item.url());
      }
  
 -    m_groups.clear();
      m_items.clear();
  
      // Resort the items
          m_items.insert(m_itemData.at(i)->item.url(), i);
      }
  
 -    // Determine the indexes that have been moved
 -    QList<int> movedToIndexes;
 -    movedToIndexes.reserve(itemCount);
 -    for (int i = 0; i < itemCount; i++) {
 -        const int newIndex = m_items.value(oldUrls.at(i));
 -        movedToIndexes.append(newIndex);
 +    // Determine the first index that has been moved.
 +    int firstMovedIndex = 0;
 +    while (firstMovedIndex < itemCount
 +           && firstMovedIndex == m_items.value(oldUrls.at(firstMovedIndex))) {
 +        ++firstMovedIndex;
      }
  
 -    // Don't check whether items have really been moved and always emit a
 -    // itemsMoved() signal after resorting: In case of grouped items
 -    // the groups might change even if the items themselves don't change their
 -    // position. Let the receiver of the signal decide whether a check for moved
 -    // items makes sense.
 -    emit itemsMoved(KItemRange(0, itemCount), movedToIndexes);
 +    const bool itemsHaveMoved = firstMovedIndex < itemCount;
 +    if (itemsHaveMoved) {
 +        m_groups.clear();
 +
 +        int lastMovedIndex = itemCount - 1;
 +        while (lastMovedIndex > firstMovedIndex
 +               && lastMovedIndex == m_items.value(oldUrls.at(lastMovedIndex))) {
 +            --lastMovedIndex;
 +        }
 +
 +        Q_ASSERT(firstMovedIndex <= lastMovedIndex);
 +
 +        // Create a list movedToIndexes, which has the property that
 +        // movedToIndexes[i] is the new index of the item with the old index
 +        // firstMovedIndex + i.
 +        const int movedItemsCount = lastMovedIndex - firstMovedIndex + 1;
 +        QList<int> movedToIndexes;
 +        movedToIndexes.reserve(movedItemsCount);
 +        for (int i = firstMovedIndex; i <= lastMovedIndex; ++i) {
 +            const int newIndex = m_items.value(oldUrls.at(i));
 +            movedToIndexes.append(newIndex);
 +        }
 +
 +        emit itemsMoved(KItemRange(firstMovedIndex, movedItemsCount), movedToIndexes);
 +    } else if (groupedSorting()) {
 +        // The groups might have changed even if the order of the items has not.
 +        const QList<QPair<int, QVariant> > oldGroups = m_groups;
 +        m_groups.clear();
 +        if (groups() != oldGroups) {
 +            emit groupsChanged();
 +        }
 +    }
  
  #ifdef KFILEITEMMODEL_DEBUG
      kDebug() << "[TIME] Resorting of" << itemCount << "items:" << timer.elapsed();
@@@ -916,7 -895,30 +916,7 @@@ void KFileItemModel::slotRefreshItems(c
  
      // Extract the item-ranges out of the changed indexes
      qSort(indexes);
 -
 -    KItemRangeList itemRangeList;
 -    int previousIndex = indexes.at(0);
 -    int rangeIndex = previousIndex;
 -    int rangeCount = 1;
 -
 -    const int maxIndex = indexes.count() - 1;
 -    for (int i = 1; i <= maxIndex; ++i) {
 -        const int currentIndex = indexes.at(i);
 -        if (currentIndex == previousIndex + 1) {
 -            ++rangeCount;
 -        } else {
 -            itemRangeList.append(KItemRange(rangeIndex, rangeCount));
 -
 -            rangeIndex = currentIndex;
 -            rangeCount = 1;
 -        }
 -        previousIndex = currentIndex;
 -    }
 -
 -    if (rangeCount > 0) {
 -        itemRangeList.append(KItemRange(rangeIndex, rangeCount));
 -    }
 -
 +    const KItemRangeList itemRangeList = KItemRangeList::fromSortedContainer(indexes);
      emitItemsChangedAndTriggerResorting(itemRangeList, changedRoles);
  }
  
@@@ -1054,6 -1056,36 +1054,6 @@@ void KFileItemModel::insertItems(QList<
  #endif
  }
  
 -static KItemRangeList sortedIndexesToKItemRangeList(const QList<int>& sortedNumbers)
 -{
 -    if (sortedNumbers.empty()) {
 -        return KItemRangeList();
 -    }
 -
 -    KItemRangeList result;
 -
 -    QList<int>::const_iterator it = sortedNumbers.begin();
 -    int index = *it;
 -    int count = 1;
 -
 -    ++it;
 -
 -    QList<int>::const_iterator end = sortedNumbers.end();
 -    while (it != end) {
 -        if (*it == index + count) {
 -            ++count;
 -        } else {
 -            result << KItemRange(index, count);
 -            index = *it;
 -            count = 1;
 -        }
 -        ++it;
 -    }
 -
 -    result << KItemRange(index, count);
 -    return result;
 -}
 -
  void KFileItemModel::removeItems(const KFileItemList& items, RemoveItemsBehavior behavior)
  {
  #ifdef KFILEITEMMODEL_DEBUG
      std::sort(indexesToRemove.begin(), indexesToRemove.end());
  
      // Step 2: Remove the ItemData pointers from the list m_itemData.
 -    const KItemRangeList itemRanges = sortedIndexesToKItemRangeList(indexesToRemove);
 +    const KItemRangeList itemRanges = KItemRangeList::fromSortedContainer(indexesToRemove);
      int target = itemRanges.at(0).index;
      int source = itemRanges.at(0).index + itemRanges.at(0).count;
      int nextRange = 1;
@@@ -1148,23 -1180,6 +1148,23 @@@ QList<KFileItemModel::ItemData*> KFileI
      return itemDataList;
  }
  
 +int KFileItemModel::expandedParentsCount(const ItemData* data)
 +{
 +    // The hash 'values' is only guaranteed to contain the key "expandedParentsCount"
 +    // if the corresponding item is expanded, and it is not a top-level item.
 +    const ItemData* parent = data->parent;
 +    if (parent) {
 +        if (parent->parent) {
 +            Q_ASSERT(parent->values.contains("expandedParentsCount"));
 +            return parent->values.value("expandedParentsCount").toInt() + 1;
 +        } else {
 +            return 1;
 +        }
 +    } else {
 +        return 0;
 +    }
 +}
 +
  void KFileItemModel::removeExpandedItems()
  {
      KFileItemList expandedItems;
      const int maxIndex = m_itemData.count() - 1;
      for (int i = 0; i <= maxIndex; ++i) {
          const ItemData* itemData = m_itemData.at(i);
 -        if (itemData->values.value("expandedParentsCount").toInt() > 0) {
 +        if (itemData->parent) {
              expandedItems.append(itemData->item);
          }
      }
  
 -    // The m_expandedParentsCountRoot may not get reset before all items with
 -    // a bigger count have been removed.
      removeItems(expandedItems, DeleteItemData);
 -
      m_expandedDirs.clear();
+     // Also remove all filtered items which have a parent.
+     QHash<KFileItem, ItemData*>::iterator it = m_filteredItems.begin();
+     const QHash<KFileItem, ItemData*>::iterator end = m_filteredItems.end();
+     while (it != end) {
+         if (it.value()->parent) {
+             delete it.value();
+             it = m_filteredItems.erase(it);
+         } else {
+             ++it;
+         }
+     }
  }
  
  void KFileItemModel::emitItemsChangedAndTriggerResorting(const KItemRangeList& itemRanges, const QSet<QByteArray>& changedRoles)
@@@ -1374,7 -1405,7 +1387,7 @@@ QHash<QByteArray, QVariant> KFileItemMo
  
      if (m_requestRole[ExpandedParentsCountRole]) {
          if (parent) {
 -            const int level = parent->values["expandedParentsCount"].toInt() + 1;
 +            const int level = expandedParentsCount(parent) + 1;
              data.insert(sharedValue("expandedParentsCount"), level);
          }
      }
@@@ -1398,8 -1429,8 +1411,8 @@@ bool KFileItemModel::lessThan(const Ite
      int result = 0;
  
      if (a->parent != b->parent) {
 -        const int expansionLevelA = a->values.value("expandedParentsCount").toInt();
 -        const int expansionLevelB = b->values.value("expandedParentsCount").toInt();
 +        const int expansionLevelA = expandedParentsCount(a);
 +        const int expansionLevelB = expandedParentsCount(b);
  
          // If b has a higher expansion level than a, check if a is a parent
          // of b, and make sure that both expansion levels are equal otherwise.
              a = a->parent;
          }
  
 -        Q_ASSERT(a->values.value("expandedParentsCount").toInt() == b->values.value("expandedParentsCount").toInt());
 +        Q_ASSERT(expandedParentsCount(a) == expandedParentsCount(b));
  
          // Compare the last parents of a and b which are different.
          while (a->parent != b->parent) {
@@@ -1918,9 -1949,9 +1931,9 @@@ KFileItemList KFileItemModel::childItem
  
      int index = m_items.value(item.url(), -1);
      if (index >= 0) {
 -        const int parentLevel = m_itemData.at(index)->values.value("expandedParentsCount").toInt();
 +        const int parentLevel = expandedParentsCount(index);
          ++index;
 -        while (index < m_itemData.count() && m_itemData.at(index)->values.value("expandedParentsCount").toInt() > parentLevel) {
 +        while (index < m_itemData.count() && expandedParentsCount(index) > parentLevel) {
              items.append(m_itemData.at(index)->item);
              ++index;
          }
@@@ -2055,7 -2086,7 +2068,7 @@@ bool KFileItemModel::isConsistent() con
          const ItemData* data = m_itemData.at(i);
          const ItemData* parent = data->parent;
          if (parent) {
 -            if (data->values.value("expandedParentsCount").toInt() != parent->values.value("expandedParentsCount").toInt() + 1) {
 +            if (expandedParentsCount(data) != expandedParentsCount(parent) + 1) {
                  qWarning() << "expandedParentsCount is inconsistent for parent" << parent->item << "and child" << data->item;
                  return false;
              }
index ff8dcd2686b8a0044eec87c6e365453c99018e18,5dd3417fc5c43225c58328e4b58ebbe987f40382..299ca6f92066984acc22c3462549ad287d6ef6f9
@@@ -49,7 -49,6 +49,7 @@@ namespace 
      const int DefaultTimeout = 5000;
  };
  
 +Q_DECLARE_METATYPE(KItemRange)
  Q_DECLARE_METATYPE(KItemRangeList)
  Q_DECLARE_METATYPE(QList<int>)
  
@@@ -77,6 -76,7 +77,7 @@@ private slots
      void testExpandItems();
      void testExpandParentItems();
      void testMakeExpandedItemHidden();
+     void testRemoveFilteredExpandedItems();
      void testSorting();
      void testIndexForKeyboardSearch();
      void testNameFilter();
@@@ -87,6 -87,7 +88,7 @@@
      void removeParentOfHiddenItems();
      void testGeneralParentChildRelationships();
      void testNameRoleGroups();
+     void testNameRoleGroupsWithExpandedItems();
  
  private:
      QStringList itemsInModel() const;
@@@ -498,8 -499,7 +500,8 @@@ void KFileItemModelTest::testExpandItem
      // KFileItemModel::expansionLevelsCompare(const KFileItem& a, const KFileItem& b)
      // yields the correct result for "a/a/1" and "a/a-1/", whis is non-trivial because they share the
      // first three characters.
 -    QSet<QByteArray> modelRoles = m_model->roles();
 +    QSet<QByteArray> originalModelRoles = m_model->roles();
 +    QSet<QByteArray> modelRoles = originalModelRoles;
      modelRoles << "isExpanded" << "isExpandable" << "expandedParentsCount";
      m_model->setRoles(modelRoles);
  
      QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(directoryLoadingCompleted()), DefaultTimeout));
      QCOMPARE(m_model->count(), 5);  // 5 items: "a/", "a/a/", "a/a/1", "a/a-1/", "a/a-1/1"
      QCOMPARE(m_model->expandedDirectories(), allFolders);
 +
 +    // Remove all expanded items by changing the roles
 +    spyRemoved.clear();
 +    m_model->setRoles(originalModelRoles);
 +    QVERIFY(!m_model->isExpanded(0));
 +    QCOMPARE(m_model->count(), 1);
 +    QVERIFY(!m_model->expandedDirectories().contains(KUrl(m_testDir->name() + 'a')));
 +
 +    QCOMPARE(spyRemoved.count(), 1);
 +    itemRangeList = spyRemoved.takeFirst().at(0).value<KItemRangeList>();
 +    QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(1, 4)); // 4 items removed
 +    QVERIFY(m_model->isConsistent());
  }
  
  void KFileItemModelTest::testExpandParentItems()
      QVERIFY(m_model->isExpanded(3));
      QVERIFY(!m_model->isExpanded(4));
      QVERIFY(m_model->isConsistent());
 +
 +    // Expand "a 1/b1/".
 +    m_model->setExpanded(1, true);
 +    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(directoryLoadingCompleted()), DefaultTimeout));
 +    QCOMPARE(m_model->count(), 6);
 +    QVERIFY(m_model->isExpanded(0));
 +    QVERIFY(m_model->isExpanded(1));
 +    QVERIFY(!m_model->isExpanded(2));
 +    QVERIFY(m_model->isExpanded(3));
 +    QVERIFY(m_model->isExpanded(4));
 +    QVERIFY(!m_model->isExpanded(5));
 +    QVERIFY(m_model->isConsistent());
 +
 +    // Collapse "a 1/b1/" again, and verify that the previous state is restored.
 +    m_model->setExpanded(1, false);
 +    QCOMPARE(m_model->count(), 5);
 +    QVERIFY(m_model->isExpanded(0));
 +    QVERIFY(!m_model->isExpanded(1));
 +    QVERIFY(m_model->isExpanded(2));
 +    QVERIFY(m_model->isExpanded(3));
 +    QVERIFY(!m_model->isExpanded(4));
 +    QVERIFY(m_model->isConsistent());
  }
  
  /**
@@@ -743,6 -709,51 +745,51 @@@ void KFileItemModelTest::testMakeExpand
  
  }
  
+ void KFileItemModelTest::testRemoveFilteredExpandedItems()
+ {
+     QSet<QByteArray> originalModelRoles = m_model->roles();
+     QSet<QByteArray> modelRoles = originalModelRoles;
+     modelRoles << "isExpanded" << "isExpandable" << "expandedParentsCount";
+     m_model->setRoles(modelRoles);
+     QStringList files;
+     files << "folder/child" << "file"; // missing folders are created automatically
+     m_testDir->createFiles(files);
+     m_model->loadDirectory(m_testDir->url());
+     QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+     // So far, the model contains only "folder/" and "file".
+     QCOMPARE(m_model->count(), 2);
+     QVERIFY(m_model->isExpandable(0));
+     QVERIFY(!m_model->isExpandable(1));
+     QVERIFY(!m_model->isExpanded(0));
+     QVERIFY(!m_model->isExpanded(1));
+     QCOMPARE(itemsInModel(), QStringList() << "folder" << "file");
+     // Expand "folder" -> "folder/child" becomes visible.
+     m_model->setExpanded(0, true);
+     QVERIFY(m_model->isExpanded(0));
+     QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+     QCOMPARE(itemsInModel(), QStringList() << "folder" << "child" << "file");
+     // Add a name filter.
+     m_model->setNameFilter("f");
+     QCOMPARE(itemsInModel(), QStringList() << "folder" << "file");
+     m_model->setNameFilter("fo");
+     QCOMPARE(itemsInModel(), QStringList() << "folder");
+     // Remove all expanded items by changing the roles
+     m_model->setRoles(originalModelRoles);
+     QVERIFY(!m_model->isExpanded(0));
+     QCOMPARE(itemsInModel(), QStringList() << "folder");
+     // Remove the name filter and verify that "folder/child" does not reappear.
+     m_model->setNameFilter(QString());
+     QCOMPARE(itemsInModel(), QStringList() << "folder" << "file");
+ }
  void KFileItemModelTest::testSorting()
  {
      // Create some files with different sizes and modification times to check the different sorting options
      QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder);
      QCOMPARE(itemsInModel(), QStringList() << "a" << "b" << "c" << "c-1" << "c-2" << "c-3" << "d" << "e");
      QCOMPARE(spyItemsMoved.count(), 1);
 -    QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 2 << 4 << 5 << 3 << 0 << 1 << 6 << 7);
 +    QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(0, 6));
 +    QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 2 << 4 << 5 << 3 << 0 << 1);
  
      // Sort by Name, descending
      m_model->setSortDirectoriesFirst(true);
      QCOMPARE(m_model->sortOrder(), Qt::DescendingOrder);
      QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "e" << "d" << "b" << "a");
      QCOMPARE(spyItemsMoved.count(), 2);
 -    QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 4 << 5 << 0 << 3 << 1 << 2 << 6 << 7);
 -    QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 0 << 1 << 2 << 3 << 7 << 6 << 5 << 4);
 +    QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(0, 6));
 +    QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 4 << 5 << 0 << 3 << 1 << 2);
 +    QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(4, 4));
 +    QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 7 << 6 << 5 << 4);
  
      // Sort by Date, descending
      m_model->setSortDirectoriesFirst(true);
      QCOMPARE(m_model->sortOrder(), Qt::DescendingOrder);
      QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "b" << "d" << "a" << "e");
      QCOMPARE(spyItemsMoved.count(), 1);
 -    QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 0 << 1 << 2 << 3 << 7 << 5 << 4 << 6);
 +    QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(4, 4));
 +    QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 7 << 5 << 4 << 6);
  
      // Sort by Date, ascending
      m_model->setSortOrder(Qt::AscendingOrder);
      QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder);
      QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "e" << "a" << "d" << "b");
      QCOMPARE(spyItemsMoved.count(), 1);
 -    QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 0 << 1 << 2 << 3 << 7 << 6 << 5 << 4);
 +    QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(4, 4));
 +    QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 7 << 6 << 5 << 4);
  
      // Sort by Date, ascending, 'Sort Folders First' disabled
      m_model->setSortDirectoriesFirst(false);
      QVERIFY(!m_model->sortDirectoriesFirst());
      QCOMPARE(itemsInModel(), QStringList() << "e" << "a" << "c" << "c-1" << "c-2" << "c-3" << "d" << "b");
      QCOMPARE(spyItemsMoved.count(), 1);
 -    QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 2 << 4 << 5 << 3 << 0 << 1 << 6 << 7);
 +    QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(0, 6));
 +    QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 2 << 4 << 5 << 3 << 0 << 1);
  
      // Sort by Name, ascending, 'Sort Folders First' disabled
      m_model->setSortRole("text");
      QVERIFY(!m_model->sortDirectoriesFirst());
      QCOMPARE(itemsInModel(), QStringList() << "a" << "b" << "c" << "c-1" << "c-2" << "c-3" << "d" << "e");
      QCOMPARE(spyItemsMoved.count(), 1);
 +    QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(0, 8));
      QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 7 << 0 << 2 << 3 << 4 << 5 << 6 << 1);
  
      // Sort by Size, ascending, 'Sort Folders First' disabled
      QVERIFY(!m_model->sortDirectoriesFirst());
      QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "a" << "b" << "e" << "d");
      QCOMPARE(spyItemsMoved.count(), 1);
 +    QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(0, 8));
      QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 4 << 5 << 0 << 3 << 1 << 2 << 7 << 6);
  
 -    QSKIP("2 tests of testSorting() are temporary deactivated as in KFileItemModel resortAllItems() "
 -          "always emits a itemsMoved() signal. Before adjusting the tests think about probably introducing "
 -          "another signal", SkipSingle);
 -    // Internal note: Check comment in KFileItemModel::resortAllItems() for details.
 -
      // In 'Sort by Size' mode, folders are always first -> changing 'Sort Folders First' does not resort the model
      m_model->setSortDirectoriesFirst(true);
      QCOMPARE(m_model->sortRole(), QByteArray("size"));
      QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder);
      QVERIFY(m_model->sortDirectoriesFirst());
 -    QCOMPARE(itemsInModel(), QStringList() << "c" << "a" << "b" << "e" << "d");
 +    QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "a" << "b" << "e" << "d");
      QCOMPARE(spyItemsMoved.count(), 0);
  
      // Sort by Size, descending, 'Sort Folders First' enabled
      QCOMPARE(m_model->sortRole(), QByteArray("size"));
      QCOMPARE(m_model->sortOrder(), Qt::DescendingOrder);
      QVERIFY(m_model->sortDirectoriesFirst());
 -    QCOMPARE(itemsInModel(), QStringList() << "c" << "d" << "e" << "b" << "a");
 +    QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "d" << "e" << "b" << "a");
      QCOMPARE(spyItemsMoved.count(), 1);
 -    QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 0 << 4 << 3 << 2 << 1);
 +    QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(4, 4));
 +    QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 7 << 6 << 5 << 4);
  
      // TODO: Sort by other roles; show/hide hidden files
  }
@@@ -1289,7 -1296,7 +1336,7 @@@ void KFileItemModelTest::testNameRoleGr
      // Rename c.txt to d.txt.
      data.insert("text", "d.txt");
      m_model->setData(2, data);
 -    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsMoved(KItemRange,QList<int>)), DefaultTimeout));
 +    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(groupsChanged()), DefaultTimeout));
      QCOMPARE(itemsInModel(), QStringList() << "a.txt" << "b.txt" << "d.txt" << "e.txt");
  
      expectedGroups.clear();
      fileItemC.setUrl(urlC);
  
      m_model->slotRefreshItems(QList<QPair<KFileItem, KFileItem> >() << qMakePair(fileItemD, fileItemC));
 -    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsMoved(KItemRange,QList<int>)), DefaultTimeout));
 +    QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(groupsChanged()), DefaultTimeout));
      QCOMPARE(itemsInModel(), QStringList() << "a.txt" << "b.txt" << "c.txt" << "e.txt");
  
      expectedGroups.clear();
      QCOMPARE(m_model->groups(), expectedGroups);
  }
  
+ void KFileItemModelTest::testNameRoleGroupsWithExpandedItems()
+ {
+     QSet<QByteArray> modelRoles = m_model->roles();
+     modelRoles << "isExpanded" << "isExpandable" << "expandedParentsCount";
+     m_model->setRoles(modelRoles);
+     QStringList files;
+     files << "a/b.txt" << "a/c.txt" << "d/e.txt" << "d/f.txt";
+     m_testDir->createFiles(files);
+     m_model->setGroupedSorting(true);
+     m_model->loadDirectory(m_testDir->url());
+     QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+     QCOMPARE(itemsInModel(), QStringList() << "a" << "d");
+     QList<QPair<int, QVariant> > expectedGroups;
+     expectedGroups << QPair<int, QVariant>(0, QLatin1String("A"));
+     expectedGroups << QPair<int, QVariant>(1, QLatin1String("D"));
+     QCOMPARE(m_model->groups(), expectedGroups);
+     // Verify that expanding "a" and "d" will not change the groups (except for the index of "D").
+     expectedGroups.clear();
+     expectedGroups << QPair<int, QVariant>(0, QLatin1String("A"));
+     expectedGroups << QPair<int, QVariant>(3, QLatin1String("D"));
+     m_model->setExpanded(0, true);
+     QVERIFY(m_model->isExpanded(0));
+     QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+     QCOMPARE(itemsInModel(), QStringList() << "a" << "b.txt" << "c.txt" << "d");
+     QCOMPARE(m_model->groups(), expectedGroups);
+     m_model->setExpanded(3, true);
+     QVERIFY(m_model->isExpanded(3));
+     QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+     QCOMPARE(itemsInModel(), QStringList() << "a" << "b.txt" << "c.txt" << "d" << "e.txt" << "f.txt");
+     QCOMPARE(m_model->groups(), expectedGroups);
+ }
  QStringList KFileItemModelTest::itemsInModel() const
  {
      QStringList items;
      for (int i = 0; i < m_model->count(); i++) {
-         items << m_model->data(i).value("text").toString();
+         items << m_model->fileItem(i).text();
      }
      return items;
  }