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
connect(m_resortAllItemsTimer, SIGNAL(timeout()), this, SLOT(resortAllItems()));
Q_ASSERT(m_minimumUpdateIntervalTimer->interval() <= m_maximumUpdateIntervalTimer->interval());
-
+
connect(KGlobalSettings::self(), SIGNAL(naturalSortingChanged()), this, SLOT(slotNaturalSortingChanged()));
}
if (changedRoles.contains(sortRole())) {
m_resortAllItemsTimer->start();
}
-
+
return true;
}
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 ExpandedParentsCountRole: 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
QElapsedTimer timer;
timer.start();
#endif
- switch (roleIndex(sortRole())) {
+ switch (typeForRole(sortRole())) {
case NameRole: m_groups = nameRoleGroups(); break;
case SizeRole: m_groups = sizeRoleGroups(); break;
case DateRole: m_groups = dateRoleGroups(); break;
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) {
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);
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]) {
{
Q_UNUSED(current);
Q_UNUSED(previous);
- resortAllItems();
+ resortAllItems();
}
void KFileItemModel::resortAllItems()
{
m_resortAllItemsTimer->stop();
-
+
const int itemCount = count();
if (itemCount <= 0) {
return;
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
// 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()
// 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) {
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()) {
itemDataList.append(itemData);
}
-
+
return itemDataList;
}
}
}
-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("expandedParentsCount", ExpandedParentsCountRole);
- }
- 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",
- "expandedParentsCount"
+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.
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():
}
break;
}
-
+
case RatingRole: {
result = a->values.value("rating").toInt() - b->values.value("rating").toInt();
break;
}
-
+
case PermissionsRole:
case OwnerRole:
case GroupRole:
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;
}
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);
{
// 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;
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);
{
// 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;
{
// 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;
{
// 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
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"