+QList<QPair<int, QVariant> > KFileItemModel::nameRoleGroups() const
+{
+ Q_ASSERT(!m_itemData.isEmpty());
+
+ const int maxIndex = count() - 1;
+ QList<QPair<int, QVariant> > groups;
+
+ QString groupValue;
+ QChar firstChar;
+ bool isLetter = false;
+ for (int i = 0; i <= maxIndex; ++i) {
+ if (isChildItem(i)) {
+ continue;
+ }
+
+ const QString name = m_itemData.at(i)->values.value("name").toString();
+
+ // Use the first character of the name as group indication
+ QChar newFirstChar = name.at(0).toUpper();
+ if (newFirstChar == QLatin1Char('~') && name.length() > 1) {
+ newFirstChar = name.at(1).toUpper();
+ }
+
+ if (firstChar != newFirstChar) {
+ QString newGroupValue;
+ if (newFirstChar >= QLatin1Char('A') && newFirstChar <= QLatin1Char('Z')) {
+ // Apply group 'A' - 'Z'
+ newGroupValue = newFirstChar;
+ isLetter = true;
+ } else if (newFirstChar >= QLatin1Char('0') && newFirstChar <= QLatin1Char('9')) {
+ // Apply group '0 - 9' for any name that starts with a digit
+ newGroupValue = i18nc("@title:group Groups that start with a digit", "0 - 9");
+ isLetter = false;
+ } else {
+ if (isLetter) {
+ // If the current group is 'A' - 'Z' check whether a locale character
+ // fits into the existing group.
+ // TODO: This does not work in the case if e.g. the group 'O' starts with
+ // an umlaut 'O' -> provide unit-test to document this known issue
+ const QChar prevChar(firstChar.unicode() - ushort(1));
+ const QChar nextChar(firstChar.unicode() + ushort(1));
+ const QString currChar(newFirstChar);
+ const bool partOfCurrentGroup = currChar.localeAwareCompare(prevChar) > 0 &&
+ currChar.localeAwareCompare(nextChar) < 0;
+ if (partOfCurrentGroup) {
+ continue;
+ }
+ }
+ newGroupValue = i18nc("@title:group", "Others");
+ isLetter = false;
+ }
+
+ if (newGroupValue != groupValue) {
+ groupValue = newGroupValue;
+ groups.append(QPair<int, QVariant>(i, newGroupValue));
+ }
+
+ firstChar = newFirstChar;
+ }
+ }
+ return groups;
+}
+
+QList<QPair<int, QVariant> > KFileItemModel::sizeRoleGroups() const
+{
+ Q_ASSERT(!m_itemData.isEmpty());
+
+ const int maxIndex = count() - 1;
+ QList<QPair<int, QVariant> > groups;
+
+ QString groupValue;
+ for (int i = 0; i <= maxIndex; ++i) {
+ if (isChildItem(i)) {
+ continue;
+ }
+
+ const KFileItem& item = m_itemData.at(i)->item;
+ const KIO::filesize_t fileSize = !item.isNull() ? item.size() : ~0U;
+ QString newGroupValue;
+ if (!item.isNull() && item.isDir()) {
+ newGroupValue = i18nc("@title:group Size", "Folders");
+ } else if (fileSize < 5 * 1024 * 1024) {
+ newGroupValue = i18nc("@title:group Size", "Small");
+ } else if (fileSize < 10 * 1024 * 1024) {
+ newGroupValue = i18nc("@title:group Size", "Medium");
+ } else {
+ newGroupValue = i18nc("@title:group Size", "Big");
+ }
+
+ if (newGroupValue != groupValue) {
+ groupValue = newGroupValue;
+ groups.append(QPair<int, QVariant>(i, newGroupValue));
+ }
+ }
+
+ return groups;
+}
+
+QList<QPair<int, QVariant> > KFileItemModel::dateRoleGroups() const
+{
+ Q_ASSERT(!m_itemData.isEmpty());
+
+ const int maxIndex = count() - 1;
+ QList<QPair<int, QVariant> > groups;
+
+ const QDate currentDate = KDateTime::currentLocalDateTime().date();
+
+ int yearForCurrentWeek = 0;
+ int currentWeek = currentDate.weekNumber(&yearForCurrentWeek);
+ if (yearForCurrentWeek == currentDate.year() + 1) {
+ currentWeek = 53;
+ }
+
+ QDate previousModifiedDate;
+ QString groupValue;
+ for (int i = 0; i <= maxIndex; ++i) {
+ if (isChildItem(i)) {
+ continue;
+ }
+
+ const KDateTime modifiedTime = m_itemData.at(i)->item.time(KFileItem::ModificationTime);
+ const QDate modifiedDate = modifiedTime.date();
+ if (modifiedDate == previousModifiedDate) {
+ // The current item is in the same group as the previous item
+ continue;
+ }
+ previousModifiedDate = modifiedDate;
+
+ const int daysDistance = modifiedDate.daysTo(currentDate);
+
+ int yearForModifiedWeek = 0;
+ int modifiedWeek = modifiedDate.weekNumber(&yearForModifiedWeek);
+ if (yearForModifiedWeek == modifiedDate.year() + 1) {
+ modifiedWeek = 53;
+ }
+
+ QString newGroupValue;
+ if (currentDate.year() == modifiedDate.year() && currentDate.month() == modifiedDate.month()) {
+ if (modifiedWeek > currentWeek) {
+ // Usecase: modified date = 2010-01-01, current date = 2010-01-22
+ // modified week = 53, current week = 3
+ modifiedWeek = 0;
+ }
+ switch (currentWeek - modifiedWeek) {
+ case 0:
+ switch (daysDistance) {
+ case 0: newGroupValue = i18nc("@title:group Date", "Today"); break;
+ case 1: newGroupValue = i18nc("@title:group Date", "Yesterday"); break;
+ default: newGroupValue = modifiedTime.toString(i18nc("@title:group The week day name: %A", "%A"));
+ }
+ break;
+ case 1:
+ newGroupValue = i18nc("@title:group Date", "Last Week");
+ break;
+ case 2:
+ newGroupValue = i18nc("@title:group Date", "Two Weeks Ago");
+ break;
+ case 3:
+ newGroupValue = i18nc("@title:group Date", "Three Weeks Ago");
+ break;
+ case 4:
+ case 5:
+ newGroupValue = i18nc("@title:group Date", "Earlier this Month");
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+ } else {
+ const QDate lastMonthDate = currentDate.addMonths(-1);
+ if (lastMonthDate.year() == modifiedDate.year() && lastMonthDate.month() == modifiedDate.month()) {
+ if (daysDistance == 1) {
+ newGroupValue = modifiedTime.toString(i18nc("@title:group Date: %B is full month name in current locale, and %Y is full year number", "Yesterday (%B, %Y)"));
+ } else if (daysDistance <= 7) {
+ newGroupValue = modifiedTime.toString(i18nc("@title:group The week day name: %A, %B is full month name in current locale, and %Y is full year number", "%A (%B, %Y)"));
+ } else if (daysDistance <= 7 * 2) {
+ newGroupValue = modifiedTime.toString(i18nc("@title:group Date: %B is full month name in current locale, and %Y is full year number", "Last Week (%B, %Y)"));
+ } else if (daysDistance <= 7 * 3) {
+ newGroupValue = modifiedTime.toString(i18nc("@title:group Date: %B is full month name in current locale, and %Y is full year number", "Two Weeks Ago (%B, %Y)"));
+ } else if (daysDistance <= 7 * 4) {
+ newGroupValue = modifiedTime.toString(i18nc("@title:group Date: %B is full month name in current locale, and %Y is full year number", "Three Weeks Ago (%B, %Y)"));
+ } else {
+ newGroupValue = modifiedTime.toString(i18nc("@title:group Date: %B is full month name in current locale, and %Y is full year number", "Earlier on %B, %Y"));
+ }
+ } else {
+ newGroupValue = modifiedTime.toString(i18nc("@title:group The month and year: %B is full month name in current locale, and %Y is full year number", "%B, %Y"));
+ }
+ }
+
+ if (newGroupValue != groupValue) {
+ groupValue = newGroupValue;
+ groups.append(QPair<int, QVariant>(i, newGroupValue));
+ }
+ }
+
+ return groups;
+}
+
+QList<QPair<int, QVariant> > KFileItemModel::permissionRoleGroups() const
+{
+ Q_ASSERT(!m_itemData.isEmpty());
+
+ const int maxIndex = count() - 1;
+ QList<QPair<int, QVariant> > groups;
+
+ QString permissionsString;
+ QString groupValue;
+ for (int i = 0; i <= maxIndex; ++i) {
+ if (isChildItem(i)) {
+ continue;
+ }
+
+ const ItemData* itemData = m_itemData.at(i);
+ const QString newPermissionsString = itemData->values.value("permissions").toString();
+ if (newPermissionsString == permissionsString) {
+ continue;
+ }
+ permissionsString = newPermissionsString;
+
+ const QFileInfo info(itemData->item.url().pathOrUrl());
+
+ // Set user string
+ QString user;
+ if (info.permission(QFile::ReadUser)) {
+ user = i18nc("@item:intext Access permission, concatenated", "Read, ");
+ }
+ if (info.permission(QFile::WriteUser)) {
+ user += i18nc("@item:intext Access permission, concatenated", "Write, ");
+ }
+ if (info.permission(QFile::ExeUser)) {
+ user += i18nc("@item:intext Access permission, concatenated", "Execute, ");
+ }
+ user = user.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : user.mid(0, user.count() - 2);
+
+ // Set group string
+ QString group;
+ if (info.permission(QFile::ReadGroup)) {
+ group = i18nc("@item:intext Access permission, concatenated", "Read, ");
+ }
+ if (info.permission(QFile::WriteGroup)) {
+ group += i18nc("@item:intext Access permission, concatenated", "Write, ");
+ }
+ if (info.permission(QFile::ExeGroup)) {
+ group += i18nc("@item:intext Access permission, concatenated", "Execute, ");
+ }
+ group = group.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : group.mid(0, group.count() - 2);
+
+ // Set others string
+ QString others;
+ if (info.permission(QFile::ReadOther)) {
+ others = i18nc("@item:intext Access permission, concatenated", "Read, ");
+ }
+ if (info.permission(QFile::WriteOther)) {
+ others += i18nc("@item:intext Access permission, concatenated", "Write, ");
+ }
+ if (info.permission(QFile::ExeOther)) {
+ others += i18nc("@item:intext Access permission, concatenated", "Execute, ");
+ }
+ others = others.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : others.mid(0, others.count() - 2);
+
+ const QString newGroupValue = i18nc("@title:group Files and folders by permissions", "User: %1 | Group: %2 | Others: %3", user, group, others);
+ if (newGroupValue != groupValue) {
+ groupValue = newGroupValue;
+ groups.append(QPair<int, QVariant>(i, newGroupValue));
+ }
+ }
+
+ return groups;
+}
+
+QList<QPair<int, QVariant> > KFileItemModel::ratingRoleGroups() const
+{
+ Q_ASSERT(!m_itemData.isEmpty());
+
+ const int maxIndex = count() - 1;
+ QList<QPair<int, QVariant> > groups;
+
+ int groupValue;
+ for (int i = 0; i <= maxIndex; ++i) {
+ if (isChildItem(i)) {
+ continue;
+ }
+ const int newGroupValue = m_itemData.at(i)->values.value("rating").toInt();
+ if (newGroupValue != groupValue) {
+ groupValue = newGroupValue;
+ groups.append(QPair<int, QVariant>(i, newGroupValue));
+ }
+ }
+
+ return groups;
+}
+
+QList<QPair<int, QVariant> > KFileItemModel::genericStringRoleGroups(const QByteArray& role) const
+{
+ Q_ASSERT(!m_itemData.isEmpty());
+
+ const int maxIndex = count() - 1;
+ QList<QPair<int, QVariant> > groups;
+
+ QString groupValue;
+ for (int i = 0; i <= maxIndex; ++i) {
+ if (isChildItem(i)) {
+ continue;
+ }
+ const QString newGroupValue = m_itemData.at(i)->values.value(role).toString();
+ if (newGroupValue != groupValue) {
+ groupValue = newGroupValue;
+ groups.append(QPair<int, QVariant>(i, newGroupValue));
+ }
+ }
+
+ return groups;
+}
+
+KFileItemList KFileItemModel::childItems(const KFileItem& item) const
+{
+ KFileItemList items;
+
+ int index = m_items.value(item.url(), -1);
+ if (index >= 0) {
+ const int parentLevel = m_itemData.at(index)->values.value("expansionLevel").toInt();
+ ++index;
+ while (index < m_itemData.count() && m_itemData.at(index)->values.value("expansionLevel").toInt() > parentLevel) {
+ items.append(m_itemData.at(index)->item);
+ ++index;
+ }
+ }
+
+ return items;
+}
+