]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kfileitemmodel.cpp
Use sub-menus for the "Sort By"- and "Additional Information"-menu
[dolphin.git] / src / kitemviews / kfileitemmodel.cpp
index e0ae033026f94b8d42f9362dc004fce904bbae19..0fef47787763ff746157884977beb93a4e62bb24 100644 (file)
@@ -50,7 +50,7 @@ KFileItemModel::KFileItemModel(KDirLister* dirLister, QObject* parent) :
     m_pendingItemsToInsert(),
     m_pendingEmitLoadingCompleted(false),
     m_groups(),
-    m_rootExpansionLevel(UninitializedRootExpansionLevel),
+    m_expandedParentsCountRoot(UninitializedExpandedParentsCountRoot),
     m_expandedUrls(),
     m_urlsToExpand()
 {
@@ -85,7 +85,7 @@ KFileItemModel::KFileItemModel(KDirLister* dirLister, QObject* parent) :
     m_maximumUpdateIntervalTimer->setInterval(2000);
     m_maximumUpdateIntervalTimer->setSingleShot(true);
     connect(m_maximumUpdateIntervalTimer, SIGNAL(timeout()), this, SLOT(dispatchPendingItemsToInsert()));
-    
+
     // When changing the value of an item which represents the sort-role a resorting must be
     // triggered. Especially in combination with KFileItemModelRolesUpdater this might be done
     // for a lot of items within a quite small timeslot. To prevent expensive resortings the
@@ -96,7 +96,7 @@ KFileItemModel::KFileItemModel(KDirLister* dirLister, QObject* parent) :
     connect(m_resortAllItemsTimer, SIGNAL(timeout()), this, SLOT(resortAllItems()));
 
     Q_ASSERT(m_minimumUpdateIntervalTimer->interval() <= m_maximumUpdateIntervalTimer->interval());
-    
+
     connect(KGlobalSettings::self(), SIGNAL(naturalSortingChanged()), this, SLOT(slotNaturalSortingChanged()));
 }
 
@@ -151,7 +151,7 @@ bool KFileItemModel::setData(int index, const QHash<QByteArray, QVariant>& value
     if (changedRoles.contains(sortRole())) {
         m_resortAllItemsTimer->start();
     }
-        
+
     return true;
 }
 
@@ -257,34 +257,21 @@ int KFileItemModel::indexForKeyboardSearch(const QString& text, int startFromInd
 bool KFileItemModel::supportsDropping(int index) const
 {
     const KFileItem item = fileItem(index);
-    return item.isNull() ? false : item.isDir() || item.isDesktopFile();
+    return !item.isNull() && (item.isDir() || item.isDesktopFile());
 }
 
 QString KFileItemModel::roleDescription(const QByteArray& role) const
 {
-    QString descr;
-
-    switch (roleIndex(role)) {
-    case NameRole:           descr = i18nc("@item:intable", "Name"); break;
-    case SizeRole:           descr = i18nc("@item:intable", "Size"); break;
-    case DateRole:           descr = i18nc("@item:intable", "Date"); break;
-    case PermissionsRole:    descr = i18nc("@item:intable", "Permissions"); break;
-    case OwnerRole:          descr = i18nc("@item:intable", "Owner"); break;
-    case GroupRole:          descr = i18nc("@item:intable", "Group"); break;
-    case TypeRole:           descr = i18nc("@item:intable", "Type"); break;
-    case DestinationRole:    descr = i18nc("@item:intable", "Destination"); break;
-    case PathRole:           descr = i18nc("@item:intable", "Path"); break;
-    case CommentRole:        descr = i18nc("@item:intable", "Comment"); break;
-    case TagsRole:           descr = i18nc("@item:intable", "Tags"); break;
-    case RatingRole:         descr = i18nc("@item:intable", "Rating"); break;
-    case NoRole:             break;
-    case IsDirRole:          break;
-    case IsExpandedRole:     break;
-    case ExpansionLevelRole: break;
-    default:                 Q_ASSERT(false); break;
+    static QHash<QByteArray, QString> description;
+    if (description.isEmpty()) {
+        int count = 0;
+        const RoleInfoMap* map = rolesInfoMap(count);
+        for (int i = 0; i < count; ++i) {
+            description.insert(map[i].role, map[i].roleTranslation);
+        }
     }
 
-    return descr;
+    return description.value(role);
 }
 
 QList<QPair<int, QVariant> > KFileItemModel::groups() const
@@ -294,23 +281,23 @@ QList<QPair<int, QVariant> > KFileItemModel::groups() const
         QElapsedTimer timer;
         timer.start();
 #endif
-        switch (roleIndex(sortRole())) {
-        case NameRole:           m_groups = nameRoleGroups(); break;
-        case SizeRole:           m_groups = sizeRoleGroups(); break;
-        case DateRole:           m_groups = dateRoleGroups(); break;
-        case PermissionsRole:    m_groups = permissionRoleGroups(); break;
-        case OwnerRole:          m_groups = genericStringRoleGroups("owner"); break;
-        case GroupRole:          m_groups = genericStringRoleGroups("group"); break;
-        case TypeRole:           m_groups = genericStringRoleGroups("type"); break;
-        case DestinationRole:    m_groups = genericStringRoleGroups("destination"); break;
-        case PathRole:           m_groups = genericStringRoleGroups("path"); break;
-        case CommentRole:        m_groups = genericStringRoleGroups("comment"); break;
-        case TagsRole:           m_groups = genericStringRoleGroups("tags"); break;
-        case RatingRole:         m_groups = ratingRoleGroups(); break;
-        case NoRole:             break;
-        case IsDirRole:          break;
-        case IsExpandedRole:     break;
-        case ExpansionLevelRole: break;
+        switch (typeForRole(sortRole())) {
+        case NameRole:        m_groups = nameRoleGroups(); break;
+        case SizeRole:        m_groups = sizeRoleGroups(); break;
+        case DateRole:        m_groups = dateRoleGroups(); break;
+        case PermissionsRole: m_groups = permissionRoleGroups(); break;
+        case OwnerRole:       m_groups = genericStringRoleGroups("owner"); break;
+        case GroupRole:       m_groups = genericStringRoleGroups("group"); break;
+        case TypeRole:        m_groups = genericStringRoleGroups("type"); break;
+        case DestinationRole: m_groups = genericStringRoleGroups("destination"); break;
+        case PathRole:        m_groups = genericStringRoleGroups("path"); break;
+        case CommentRole:     m_groups = genericStringRoleGroups("comment"); break;
+        case TagsRole:        m_groups = genericStringRoleGroups("tags"); break;
+        case RatingRole:      m_groups = ratingRoleGroups(); break;
+        case NoRole:          break;
+        case IsDirRole:       break;
+        case IsExpandedRole:  break;
+        case ExpandedParentsCountRole: break;
         default:                 Q_ASSERT(false); break;
         }
 
@@ -372,11 +359,14 @@ void KFileItemModel::clear()
 
 void KFileItemModel::setRoles(const QSet<QByteArray>& roles)
 {
+    if (m_roles == roles) {
+        return;
+    }
     m_roles = roles;
 
     if (count() > 0) {
-        const bool supportedExpanding = m_requestRole[ExpansionLevelRole];
-        const bool willSupportExpanding = roles.contains("expansionLevel");
+        const bool supportedExpanding = m_requestRole[ExpandedParentsCountRole];
+        const bool willSupportExpanding = roles.contains("expandedParentsCount");
         if (supportedExpanding && !willSupportExpanding) {
             // No expanding is supported anymore. Take care to delete all items that have an expansion level
             // that is not 0 (and hence are part of an expanded item).
@@ -390,7 +380,7 @@ void KFileItemModel::setRoles(const QSet<QByteArray>& roles)
     QSetIterator<QByteArray> it(roles);
     while (it.hasNext()) {
         const QByteArray& role = it.next();
-        m_requestRole[roleIndex(role)] = true;
+        m_requestRole[typeForRole(role)] = true;
     }
 
     if (count() > 0) {
@@ -439,9 +429,9 @@ bool KFileItemModel::setExpanded(int index, bool expanded)
         }
 
         KFileItemList itemsToRemove;
-        const int expansionLevel = data(index)["expansionLevel"].toInt();
+        const int expandedParentsCount = data(index)["expandedParentsCount"].toInt();
         ++index;
-        while (index < count() && data(index)["expansionLevel"].toInt() > expansionLevel) {
+        while (index < count() && data(index)["expandedParentsCount"].toInt() > expandedParentsCount) {
             itemsToRemove.append(m_itemData.at(index)->item);
             ++index;
         }
@@ -468,6 +458,17 @@ bool KFileItemModel::isExpandable(int index) const
     return false;
 }
 
+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 0;
+}
+
 QSet<KUrl> KFileItemModel::expandedUrls() const
 {
     return m_expandedUrls;
@@ -557,6 +558,26 @@ QString KFileItemModel::nameFilter() const
     return m_filter.pattern();
 }
 
+QList<KFileItemModel::RoleInfo> KFileItemModel::rolesInformation()
+{
+    static QList<RoleInfo> rolesInfo;
+    if (rolesInfo.isEmpty()) {
+        int count = 0;
+        const RoleInfoMap* map = rolesInfoMap(count);
+        for (int i = 0; i < count; ++i) {
+            if (map[i].roleType != NoRole) {
+                RoleInfo info;
+                info.role = map[i].role;
+                info.translation = map[i].roleTranslation;
+                info.group = map[i].groupTranslation;
+                rolesInfo.append(info);
+            }
+        }
+    }
+
+    return rolesInfo;
+}
+
 void KFileItemModel::onGroupedSortingChanged(bool current)
 {
     Q_UNUSED(current);
@@ -566,7 +587,7 @@ void KFileItemModel::onGroupedSortingChanged(bool current)
 void KFileItemModel::onSortRoleChanged(const QByteArray& current, const QByteArray& previous)
 {
     Q_UNUSED(previous);
-    m_sortRole = roleIndex(current);
+    m_sortRole = typeForRole(current);
 
 #ifdef KFILEITEMMODEL_DEBUG
     if (!m_requestRole[m_sortRole]) {
@@ -581,13 +602,13 @@ void KFileItemModel::onSortOrderChanged(Qt::SortOrder current, Qt::SortOrder pre
 {
     Q_UNUSED(current);
     Q_UNUSED(previous);
-    resortAllItems();    
+    resortAllItems();
 }
 
 void KFileItemModel::resortAllItems()
 {
     m_resortAllItemsTimer->stop();
-    
+
     const int itemCount = count();
     if (itemCount <= 0) {
         return;
@@ -608,23 +629,23 @@ void KFileItemModel::resortAllItems()
     foreach (const ItemData* itemData, m_itemData) {
         oldUrls.append(itemData->item.url());
     }
-   
+
     m_groups.clear();
     m_items.clear();
-    
+
     // Resort the items
-    sort(m_itemData.begin(), m_itemData.end());    
+    sort(m_itemData.begin(), m_itemData.end());
     for (int i = 0; i < itemCount; ++i) {
         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).url());
         movedToIndexes.append(newIndex);
-    }   
+    }
 
     // Don't check whether items have really been moved and always emit a
     // itemsMoved() signal after resorting: In case of grouped items
@@ -632,10 +653,10 @@ void KFileItemModel::resortAllItems()
     // position. Let the receiver of the signal decide whether a check for moved
     // items makes sense.
     emit itemsMoved(KItemRange(0, itemCount), movedToIndexes);
-    
+
 #ifdef KFILEITEMMODEL_DEBUG
     kDebug() << "[TIME] Resorting of" << itemCount << "items:" << timer.elapsed();
-#endif    
+#endif
 }
 
 void KFileItemModel::slotCompleted()
@@ -687,7 +708,7 @@ void KFileItemModel::slotNewItems(const KFileItemList& items)
 {
     Q_ASSERT(!items.isEmpty());
 
-    if (m_requestRole[ExpansionLevelRole] && m_rootExpansionLevel >= 0) {
+    if (m_requestRole[ExpandedParentsCountRole] && m_expandedParentsCountRoot >= 0) {
         // To be able to compare whether the new items may be inserted as children
         // of a parent item the pending items must be added to the model first.
         dispatchPendingItemsToInsert();
@@ -747,7 +768,7 @@ void KFileItemModel::slotItemsDeleted(const KFileItemList& items)
     dispatchPendingItemsToInsert();
 
     KFileItemList itemsToRemove = items;
-    if (m_requestRole[ExpansionLevelRole] && m_rootExpansionLevel >= 0) {
+    if (m_requestRole[ExpandedParentsCountRole] && m_expandedParentsCountRoot >= 0) {
         // Assure that removing a parent item also results in removing all children
         foreach (const KFileItem& item, items) {
             itemsToRemove.append(childItems(item));
@@ -842,7 +863,7 @@ void KFileItemModel::slotClear()
     m_resortAllItemsTimer->stop();
     m_pendingItemsToInsert.clear();
 
-    m_rootExpansionLevel = UninitializedRootExpansionLevel;
+    m_expandedParentsCountRoot = UninitializedExpandedParentsCountRoot;
 
     const int removedCount = m_itemData.count();
     if (removedCount > 0) {
@@ -927,7 +948,7 @@ void KFileItemModel::insertItems(const KFileItemList& items)
         // Insert item at the position targetIndex by transfering
         // the ownership of the item-data from sortedItems to m_itemData.
         // m_items will be inserted after the loop (see comment below)
-        m_itemData.insert(targetIndex, sortedItems.at(sourceIndex));        
+        m_itemData.insert(targetIndex, sortedItems.at(sourceIndex));
         ++insertedCount;
 
         if (insertedAtIndex < 0) {
@@ -985,7 +1006,7 @@ void KFileItemModel::removeItems(const KFileItemList& items)
     int targetIndex = 0;
     foreach (const ItemData* itemData, sortedItems) {
         const KFileItem& itemToRemove = itemData->item;
-        
+
         const int previousTargetIndex = targetIndex;
         while (targetIndex < m_itemData.count()) {
             if (m_itemData.at(targetIndex)->item.url() == itemToRemove.url()) {
@@ -1031,7 +1052,7 @@ void KFileItemModel::removeItems(const KFileItemList& items)
     }
 
     if (count() <= 0) {
-        m_rootExpansionLevel = UninitializedRootExpansionLevel;
+        m_expandedParentsCountRoot = UninitializedExpandedParentsCountRoot;
     }
 
     itemRanges << KItemRange(removedAtIndex, removedCount);
@@ -1049,8 +1070,8 @@ QList<KFileItemModel::ItemData*> KFileItemModel::createItemDataList(const KFileI
         itemData->values = retrieveData(item);
         itemData->parent = 0;
 
-        const bool determineParent = m_requestRole[ExpansionLevelRole]
-                                     && itemData->values["expansionLevel"].toInt() > 0;
+        const bool determineParent = m_requestRole[ExpandedParentsCountRole]
+                                     && itemData->values["expandedParentsCount"].toInt() > 0;
         if (determineParent) {
             KUrl parentUrl = item.url().upUrl();
             parentUrl.adjustPath(KUrl::RemoveTrailingSlash);
@@ -1064,7 +1085,7 @@ QList<KFileItemModel::ItemData*> KFileItemModel::createItemDataList(const KFileI
 
         itemDataList.append(itemData);
     }
+
     return itemDataList;
 }
 
@@ -1075,17 +1096,17 @@ void KFileItemModel::removeExpandedItems()
     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("expansionLevel").toInt() > 0) {
+        if (itemData->values.value("expandedParentsCount").toInt() > 0) {
             expandedItems.append(itemData->item);
         }
     }
 
-    // The m_rootExpansionLevel may not get reset before all items with
-    // a bigger expansionLevel have been removed.
-    Q_ASSERT(m_rootExpansionLevel >= 0);
+    // The m_expandedParentsCountRoot may not get reset before all items with
+    // a bigger count have been removed.
+    Q_ASSERT(m_expandedParentsCountRoot >= 0);
     removeItems(expandedItems);
 
-    m_rootExpansionLevel = UninitializedRootExpansionLevel;
+    m_expandedParentsCountRoot = UninitializedExpandedParentsCountRoot;
     m_expandedUrls.clear();
 }
 
@@ -1096,56 +1117,58 @@ void KFileItemModel::resetRoles()
     }
 }
 
-KFileItemModel::Role KFileItemModel::roleIndex(const QByteArray& role) const
-{
-    static QHash<QByteArray, Role> rolesHash;
-    if (rolesHash.isEmpty()) {
-        rolesHash.insert("name", NameRole);
-        rolesHash.insert("size", SizeRole);
-        rolesHash.insert("date", DateRole);
-        rolesHash.insert("permissions", PermissionsRole);
-        rolesHash.insert("owner", OwnerRole);
-        rolesHash.insert("group", GroupRole);
-        rolesHash.insert("type", TypeRole);
-        rolesHash.insert("destination", DestinationRole);
-        rolesHash.insert("path", PathRole);
-        rolesHash.insert("comment", CommentRole);
-        rolesHash.insert("tags", TagsRole);
-        rolesHash.insert("rating", RatingRole);
-        rolesHash.insert("isDir", IsDirRole);
-        rolesHash.insert("isExpanded", IsExpandedRole);
-        rolesHash.insert("isExpandable", IsExpandableRole);
-        rolesHash.insert("expansionLevel", ExpansionLevelRole);
-    }
-    return rolesHash.value(role, NoRole);
-}
-
-QByteArray KFileItemModel::roleByteArray(Role role) const
-{
-    static const char* const roles[RolesCount] = {
-        0, // NoRole
-        "name",
-        "size",
-        "date",
-        "permissions",
-        "owner",
-        "group",
-        "type",
-        "destination",
-        "path",
-        "comment",
-        "tags",
-        "rating",
-        "isDir",
-        "isExpanded",
-        "isExpandable",
-        "expansionLevel"        
+KFileItemModel::RoleType KFileItemModel::typeForRole(const QByteArray& role) const
+{
+    static QHash<QByteArray, RoleType> roles;
+    if (roles.isEmpty()) {
+        // Insert user visible roles that can be accessed with
+        // KFileItemModel::roleInformation()
+        int count = 0;
+        const RoleInfoMap* map = rolesInfoMap(count);
+        for (int i = 0; i < count; ++i) {
+            roles.insert(map[i].role, map[i].roleType);
+        }
+
+        // Insert internal roles (take care to synchronize the implementation
+        // with KFileItemModel::roleForType() in case if a change is done).
+        roles.insert("isDir", IsDirRole);
+        roles.insert("isExpanded", IsExpandedRole);
+        roles.insert("isExpandable", IsExpandableRole);
+        roles.insert("expandedParentsCount", ExpandedParentsCountRole);
+
+        Q_ASSERT(roles.count() == RolesCount);
+    }
+
+    return roles.value(role, NoRole);
+}
+
+QByteArray KFileItemModel::roleForType(RoleType roleType) const
+{
+    static QHash<RoleType, QByteArray> roles;
+    if (roles.isEmpty()) {
+        // Insert user visible roles that can be accessed with
+        // KFileItemModel::roleInformation()
+        int count = 0;
+        const RoleInfoMap* map = rolesInfoMap(count);
+        for (int i = 0; i < count; ++i) {
+            roles.insert(map[i].roleType, map[i].role);
+        }
+
+        // Insert internal roles (take care to synchronize the implementation
+        // with KFileItemModel::typeForRole() in case if a change is done).
+        roles.insert(IsDirRole, "isDir");
+        roles.insert(IsExpandedRole, "isExpanded");
+        roles.insert(IsExpandableRole, "isExpandable");
+        roles.insert(ExpandedParentsCountRole, "expandedParentsCount");
+
+        Q_ASSERT(roles.count() == RolesCount);
     };
-    return roles[role];
+
+    return roles.value(roleType);
 }
 
 QHash<QByteArray, QVariant> KFileItemModel::retrieveData(const KFileItem& item) const
-{    
+{
     // It is important to insert only roles that are fast to retrieve. E.g.
     // KFileItem::iconName() can be very expensive if the MIME-type is unknown
     // and hence will be retrieved asynchronously by KFileItemModelRolesUpdater.
@@ -1219,28 +1242,28 @@ QHash<QByteArray, QVariant> KFileItemModel::retrieveData(const KFileItem& item)
         data.insert("isExpandable", item.isDir() && item.url() == item.targetUrl());
     }
 
-    if (m_requestRole[ExpansionLevelRole]) {
-        if (m_rootExpansionLevel == UninitializedRootExpansionLevel && m_dirLister.data()) {
+    if (m_requestRole[ExpandedParentsCountRole]) {
+        if (m_expandedParentsCountRoot == UninitializedExpandedParentsCountRoot && m_dirLister.data()) {
             const KUrl rootUrl = m_dirLister.data()->url();
             const QString protocol = rootUrl.protocol();
-            const bool forceRootExpansionLevel = (protocol == QLatin1String("trash") ||
-                                                  protocol == QLatin1String("nepomuk") ||
-                                                  protocol == QLatin1String("remote") ||
-                                                  protocol.contains(QLatin1String("search")));
-            if (forceRootExpansionLevel) {
-                m_rootExpansionLevel = ForceRootExpansionLevel;
+            const bool forceExpandedParentsCountRoot = (protocol == QLatin1String("trash") ||
+                                                        protocol == QLatin1String("nepomuk") ||
+                                                        protocol == QLatin1String("remote") ||
+                                                        protocol.contains(QLatin1String("search")));
+            if (forceExpandedParentsCountRoot) {
+                m_expandedParentsCountRoot = ForceExpandedParentsCountRoot;
             } else {
                 const QString rootDir = rootUrl.path(KUrl::AddTrailingSlash);
-                m_rootExpansionLevel = rootDir.count('/');
+                m_expandedParentsCountRoot = rootDir.count('/');
             }
         }
 
-        if (m_rootExpansionLevel == ForceRootExpansionLevel) {
-            data.insert("expansionLevel", -1);
+        if (m_expandedParentsCountRoot == ForceExpandedParentsCountRoot) {
+            data.insert("expandedParentsCount", -1);
         } else {
             const QString dir = item.url().directory(KUrl::AppendTrailingSlash);
-            const int level = dir.count('/') - m_rootExpansionLevel;
-            data.insert("expansionLevel", level);
+            const int level = dir.count('/') - m_expandedParentsCountRoot;
+            data.insert("expandedParentsCount", level);
         }
     }
 
@@ -1259,8 +1282,8 @@ bool KFileItemModel::lessThan(const ItemData* a, const ItemData* b) const
 {
     int result = 0;
 
-    if (m_rootExpansionLevel >= 0) {
-        result = expansionLevelsCompare(a, b);
+    if (m_expandedParentsCountRoot >= 0) {
+        result = expandedParentsCountCompare(a, b);
         if (result != 0) {
             // The items have parents with different expansion levels
             return (sortOrder() == Qt::AscendingOrder) ? result < 0 : result > 0;
@@ -1293,7 +1316,7 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b) const
     case NameRole:
         // The name role is handled as default fallback after the switch
         break;
-        
+
     case SizeRole: {
         if (itemA.isDir()) {
             // See "if (m_sortFoldersFirst || m_sortRole == SizeRole)" in KFileItemModel::lessThan():
@@ -1336,12 +1359,12 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b) const
         }
         break;
     }
-    
+
     case RatingRole: {
         result = a->values.value("rating").toInt() - b->values.value("rating").toInt();
         break;
     }
-    
+
     case PermissionsRole:
     case OwnerRole:
     case GroupRole:
@@ -1350,12 +1373,12 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b) const
     case PathRole:
     case CommentRole:
     case TagsRole: {
-        const QByteArray role = roleByteArray(m_sortRole);
+        const QByteArray role = roleForType(m_sortRole);
         result = QString::compare(a->values.value(role).toString(),
                                   b->values.value(role).toString());
         break;
     }
-        
+
     default:
         break;
     }
@@ -1386,16 +1409,16 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b) const
 
 void KFileItemModel::sort(QList<ItemData*>::iterator begin,
                           QList<ItemData*>::iterator end)
-{   
+{
     // The implementation is based on qStableSortHelper() from qalgorithms.h
     // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
     // In opposite to qStableSort() it allows to use a member-function for the comparison of elements.
-    
+
     const int span = end - begin;
     if (span < 2) {
         return;
     }
-    
+
     const QList<ItemData*>::iterator middle = begin + span / 2;
     sort(begin, middle);
     sort(middle, end);
@@ -1408,21 +1431,21 @@ void KFileItemModel::merge(QList<ItemData*>::iterator begin,
 {
     // The implementation is based on qMerge() from qalgorithms.h
     // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-    
+
     const int len1 = pivot - begin;
     const int len2 = end - pivot;
-    
+
     if (len1 == 0 || len2 == 0) {
         return;
     }
-    
+
     if (len1 + len2 == 2) {
         if (lessThan(*(begin + 1), *(begin))) {
             qSwap(*begin, *(begin + 1));
         }
         return;
     }
-    
+
     QList<ItemData*>::iterator firstCut;
     QList<ItemData*>::iterator secondCut;
     int len2Half;
@@ -1436,11 +1459,11 @@ void KFileItemModel::merge(QList<ItemData*>::iterator begin,
         secondCut = pivot + len2Half;
         firstCut = upperBound(begin, pivot, *secondCut);
     }
-    
+
     reverse(firstCut, pivot);
     reverse(pivot, secondCut);
     reverse(firstCut, secondCut);
-    
+
     const QList<ItemData*>::iterator newPivot = firstCut + len2Half;
     merge(begin, firstCut, newPivot);
     merge(newPivot, secondCut, end);
@@ -1452,7 +1475,7 @@ QList<KFileItemModel::ItemData*>::iterator KFileItemModel::lowerBound(QList<Item
 {
     // The implementation is based on qLowerBound() from qalgorithms.h
     // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-    
+
     QList<ItemData*>::iterator middle;
     int n = int(end - begin);
     int half;
@@ -1476,7 +1499,7 @@ QList<KFileItemModel::ItemData*>::iterator KFileItemModel::upperBound(QList<Item
 {
     // The implementation is based on qUpperBound() from qalgorithms.h
     // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-    
+
     QList<ItemData*>::iterator middle;
     int n = end - begin;
     int half;
@@ -1499,11 +1522,11 @@ void KFileItemModel::reverse(QList<ItemData*>::iterator begin,
 {
     // The implementation is based on qReverse() from qalgorithms.h
     // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-    
+
     --end;
     while (begin < end) {
         qSwap(*begin++, *end--);
-    }    
+    }
 }
 
 int KFileItemModel::stringCompare(const QString& a, const QString& b) const
@@ -1528,7 +1551,7 @@ int KFileItemModel::stringCompare(const QString& a, const QString& b) const
                             : QString::compare(a, b, Qt::CaseSensitive);
 }
 
-int KFileItemModel::expansionLevelsCompare(const ItemData* a, const ItemData* b) const
+int KFileItemModel::expandedParentsCountCompare(const ItemData* a, const ItemData* b) const
 {
     const KUrl urlA = a->item.url();
     const KUrl urlB = b->item.url();
@@ -1935,9 +1958,9 @@ KFileItemList KFileItemModel::childItems(const KFileItem& item) const
 
     int index = m_items.value(item.url(), -1);
     if (index >= 0) {
-        const int parentLevel = m_itemData.at(index)->values.value("expansionLevel").toInt();
+        const int parentLevel = m_itemData.at(index)->values.value("expandedParentsCount").toInt();
         ++index;
-        while (index < m_itemData.count() && m_itemData.at(index)->values.value("expansionLevel").toInt() > parentLevel) {
+        while (index < m_itemData.count() && m_itemData.at(index)->values.value("expandedParentsCount").toInt() > parentLevel) {
             items.append(m_itemData.at(index)->item);
             ++index;
         }
@@ -1946,4 +1969,36 @@ KFileItemList KFileItemModel::childItems(const KFileItem& item) const
     return items;
 }
 
+const KFileItemModel::RoleInfoMap* KFileItemModel::rolesInfoMap(int& count)
+{
+    static const RoleInfoMap rolesInfoMap[] = {
+    //    role           roleType         role translation                                  group translation
+        { 0,             NoRole,          0, 0,                                             0, 0 },
+        { "name",        NameRole,        I18N_NOOP2_NOSTRIP("@label", "Name"),             0, 0 },
+        { "size",        SizeRole,        I18N_NOOP2_NOSTRIP("@label", "Size"),             0, 0 },
+        { "date",        DateRole,        I18N_NOOP2_NOSTRIP("@label", "Date"),             0, 0 },
+        { "type",        TypeRole,        I18N_NOOP2_NOSTRIP("@label", "Type"),             0, 0 },
+        { "rating",      RatingRole,      I18N_NOOP2_NOSTRIP("@label", "Rating"),           0, 0 },
+        { "tags",        TagsRole,        I18N_NOOP2_NOSTRIP("@label", "Tags"),             0, 0 },
+        { "comment",     CommentRole,     I18N_NOOP2_NOSTRIP("@label", "Comment"),          0, 0 },
+        { "wordCount",   WordCountRole,   I18N_NOOP2_NOSTRIP("@label", "Word Count"),       I18N_NOOP2_NOSTRIP("@label", "Document") },
+        { "lineCount",   LineCountRole,   I18N_NOOP2_NOSTRIP("@label", "Line Count"),       I18N_NOOP2_NOSTRIP("@label", "Document") },
+        { "imageSize",   ImageSizeRole,   I18N_NOOP2_NOSTRIP("@label", "Image Size"),       I18N_NOOP2_NOSTRIP("@label", "Image") },
+        { "orientation", OrientationRole, I18N_NOOP2_NOSTRIP("@label", "Orientation"),      I18N_NOOP2_NOSTRIP("@label", "Image") },
+        { "artist",      ArtistRole,      I18N_NOOP2_NOSTRIP("@label", "Artist"),           I18N_NOOP2_NOSTRIP("@label", "Music") },
+        { "album",       AlbumRole,       I18N_NOOP2_NOSTRIP("@label", "Album"),            I18N_NOOP2_NOSTRIP("@label", "Music") },
+        { "duration",    DurationRole,    I18N_NOOP2_NOSTRIP("@label", "Duration"),         I18N_NOOP2_NOSTRIP("@label", "Music") },
+        { "track",       TrackRole,       I18N_NOOP2_NOSTRIP("@label", "Track"),            I18N_NOOP2_NOSTRIP("@label", "Music") },
+        { "path",        PathRole,        I18N_NOOP2_NOSTRIP("@label", "Path"),             I18N_NOOP2_NOSTRIP("@label", "Other") },
+        { "destination", DestinationRole, I18N_NOOP2_NOSTRIP("@label", "Link Destination"), I18N_NOOP2_NOSTRIP("@label", "Other") },
+        { "copiedFrom",  CopiedFromRole,  I18N_NOOP2_NOSTRIP("@label", "Copied From"),      I18N_NOOP2_NOSTRIP("@label", "Other") },
+        { "permissions", PermissionsRole, I18N_NOOP2_NOSTRIP("@label", "Permissions"),      I18N_NOOP2_NOSTRIP("@label", "Other") },
+        { "owner",       OwnerRole,       I18N_NOOP2_NOSTRIP("@label", "Owner"),            I18N_NOOP2_NOSTRIP("@label", "Other") },
+        { "group",       GroupRole,       I18N_NOOP2_NOSTRIP("@label", "Group"),            I18N_NOOP2_NOSTRIP("@label", "Other") },
+    };
+
+    count = sizeof(rolesInfoMap) / sizeof(RoleInfoMap);
+    return rolesInfoMap;
+}
+
 #include "kfileitemmodel.moc"