- const int itemCount = m_itemData.count();
- for (int index = 0; index < itemCount; ++index) {
- ItemData* itemData = m_itemData.at(index);
-
- // Only filter non-expanded items as child items may never
- // exist without a parent item
- if (!itemData->values.value("isExpanded").toBool()) {
- const KFileItem item = itemData->item;
- if (!m_filter.matches(item)) {
- newFilteredIndexes.append(index);
- m_filteredItems.insert(item, itemData);
- }
+ QList<int> newFilteredIndexes; // This structure is good for prepending. We will want an ascending sorted Container at the end, this will do fine.
+
+ // This pointer will refer to the next confirmed shown item from the point of
+ // view of the current "itemData" in the upcoming "for" loop.
+ ItemData *itemShownBelow = nullptr;
+
+ // We will iterate backwards because it's convenient to know beforehand if the item just below is its child or not.
+ for (int index = m_itemData.count() - 1; index >= 0; --index) {
+ ItemData *itemData = m_itemData.at(index);
+
+ if (m_filter.matches(itemData->item)
+ || (itemShownBelow && itemShownBelow->parent == itemData && itemData->values.value("isExpanded").toBool())) {
+ // We could've entered here for two reasons:
+ // 1. This item passes the filter itself
+ // 2. This is an expanded folder that doesn't pass the filter but sees a filter-passing child just below
+
+ // So this item must remain shown.
+ // Lets register this item as the next shown item from the point of view of the next iteration of this for loop
+ itemShownBelow = itemData;
+ } else {
+ // We hide this item for now, however, for expanded folders this is not final:
+ // if after the next "for" loop we discover that its children must now be shown with the newly applied fliter, we shall re-insert it
+ newFilteredIndexes.prepend(index);
+ m_filteredItems.insert(itemData->item, itemData);
+ // indexShownBelow doesn't get updated since this item will be hidden