2 * This file is part of the KDE project
3 * Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
21 #include "dolphinmodel.h"
23 #include "dolphinsortfilterproxymodel.h"
25 #include <KCategorizedView>
29 #include <KIconLoader>
34 #include <KStandardDirs>
37 #include <QSortFilterProxyModel>
39 #include <QPersistentModelIndex>
43 const char* const DolphinModel::m_others
= I18N_NOOP2("@title:group Name", "Others");
45 DolphinModel::DolphinModel(QObject
* parent
) :
47 m_hasVersionData(false),
50 setJobTransfersVisible(true);
53 DolphinModel::~DolphinModel()
57 bool DolphinModel::setData(const QModelIndex
& index
, const QVariant
& value
, int role
)
59 if ((index
.column() == DolphinModel::Version
) && (role
== Qt::DecorationRole
)) {
60 // TODO: remove data again when items are deleted...
62 const QPersistentModelIndex key
= index
;
63 const KVersionControlPlugin::VersionState state
= static_cast<KVersionControlPlugin::VersionState
>(value
.toInt());
64 if (m_revisionHash
.value(key
, KVersionControlPlugin::UnversionedVersion
) != state
) {
65 if (!m_hasVersionData
) {
66 connect(this, SIGNAL(rowsRemoved (const QModelIndex
&, int, int)),
67 this, SLOT(slotRowsRemoved(const QModelIndex
&, int, int)));
68 m_hasVersionData
= true;
71 m_revisionHash
.insert(key
, state
);
72 emit
dataChanged(index
, index
);
77 return KDirModel::setData(index
, value
, role
);
80 QVariant
DolphinModel::data(const QModelIndex
& index
, int role
) const
83 case KCategorizedSortFilterProxyModel::CategoryDisplayRole
:
84 return displayRoleData(index
);
86 case KCategorizedSortFilterProxyModel::CategorySortRole
:
87 return sortRoleData(index
);
89 case Qt::DecorationRole
:
90 if (index
.column() == DolphinModel::Version
) {
91 return m_revisionHash
.value(index
, KVersionControlPlugin::UnversionedVersion
);
96 switch (index
.column()) {
97 case DolphinModel::LinkDest
: {
98 const KDirModel
*dirModel
= qobject_cast
<const KDirModel
*>(index
.model());
99 const KFileItem item
= dirModel
->itemForIndex(index
);
100 return item
.linkDest();
103 case DolphinModel::LocalPathOrUrl
:
104 const KDirModel
*dirModel
= qobject_cast
<const KDirModel
*>(index
.model());
105 const KFileItem item
= dirModel
->itemForIndex(index
);
106 const KUrl url
= item
.mostLocalUrl();
107 if (url
.protocol() == QLatin1String("trash")) {
108 const KIO::UDSEntry udsEntry
= item
.entry();
109 return udsEntry
.stringValue(KIO::UDSEntry::UDS_EXTRA
);
111 return url
.directory();
119 return KDirModel::data(index
, role
);
122 QVariant
DolphinModel::headerData(int section
, Qt::Orientation orientation
, int role
) const
124 if ((orientation
== Qt::Horizontal
) && (role
== Qt::DisplayRole
)) {
126 case DolphinModel::LinkDest
:
127 return i18nc("@title::column", "Link Destination");
128 case DolphinModel::LocalPathOrUrl
:
129 return i18nc("@title::column", "Path");
131 return KDirModel::headerData(section
, orientation
, role
);
137 int DolphinModel::columnCount(const QModelIndex
& parent
) const
139 return KDirModel::columnCount(parent
) + (ExtraColumnCount
- ColumnCount
);
142 void DolphinModel::clearVersionData()
144 m_revisionHash
.clear();
145 m_hasVersionData
= false;
148 bool DolphinModel::hasVersionData() const
150 return m_hasVersionData
;
153 void DolphinModel::slotRowsRemoved(const QModelIndex
& parent
, int start
, int end
)
155 if (m_hasVersionData
) {
156 const int column
= parent
.column();
157 for (int row
= start
; row
<= end
; ++row
) {
158 m_revisionHash
.remove(parent
.child(row
, column
));
163 QVariant
DolphinModel::displayRoleData(const QModelIndex
& index
) const
167 if (!index
.isValid()) {
171 const KDirModel
*dirModel
= qobject_cast
<const KDirModel
*>(index
.model());
172 KFileItem item
= dirModel
->itemForIndex(index
);
174 switch (index
.column()) {
175 case KDirModel::Name
: {
176 // KDirModel checks columns to know to which role are
178 const QModelIndex nameIndex
= index
.model()->index(index
.row(), KDirModel::Name
, index
.parent());
179 if (!nameIndex
.isValid()) {
182 const QVariant data
= nameIndex
.model()->data(nameIndex
, Qt::DisplayRole
);
183 const QString name
= data
.toString();
184 if (!name
.isEmpty()) {
185 if (!item
.isHidden() && name
.at(0).isLetter())
186 retString
= name
.at(0).toUpper();
187 else if (item
.isHidden()) {
188 if (name
.at(0) == '.') {
189 if (name
.size() > 1 && name
.at(1).isLetter()) {
190 retString
= name
.at(1).toUpper();
192 retString
= i18nc("@title:group Name", m_others
);
195 retString
= name
.at(0).toUpper();
198 bool validCategory
= false;
200 const QString
str(name
.toUpper());
201 const QChar
* currA
= str
.unicode();
202 while (!currA
->isNull() && !validCategory
) {
203 if (currA
->isLetter()) {
204 validCategory
= true;
205 } else if (currA
->isDigit()) {
206 return i18nc("@title:group Name", m_others
);
212 retString
= validCategory
? *currA
: i18nc("@title:group Name", m_others
);
218 case KDirModel::Size
: {
219 const KIO::filesize_t fileSize
= !item
.isNull() ? item
.size() : ~0U;
220 if (!item
.isNull() && item
.isDir()) {
221 retString
= i18nc("@title:group Size", "Folders");
222 } else if (fileSize
< 5242880) {
223 retString
= i18nc("@title:group Size", "Small");
224 } else if (fileSize
< 10485760) {
225 retString
= i18nc("@title:group Size", "Medium");
227 retString
= i18nc("@title:group Size", "Big");
232 case KDirModel::ModifiedTime
: {
233 KDateTime modifiedTime
= item
.time(KFileItem::ModificationTime
);
234 modifiedTime
= modifiedTime
.toLocalZone();
236 const QDate currentDate
= KDateTime::currentLocalDateTime().date();
237 const QDate modifiedDate
= modifiedTime
.date();
239 const int daysDistance
= modifiedDate
.daysTo(currentDate
);
241 int yearForCurrentWeek
= 0;
242 int currentWeek
= currentDate
.weekNumber(&yearForCurrentWeek
);
243 if (yearForCurrentWeek
== currentDate
.year() + 1) {
247 int yearForModifiedWeek
= 0;
248 int modifiedWeek
= modifiedDate
.weekNumber(&yearForModifiedWeek
);
249 if (yearForModifiedWeek
== modifiedDate
.year() + 1) {
253 if (currentDate
.year() == modifiedDate
.year() && currentDate
.month() == modifiedDate
.month()) {
254 if (modifiedWeek
> currentWeek
) {
255 // use case: modified date = 2010-01-01, current date = 2010-01-22
256 // modified week = 53, current week = 3
259 switch (currentWeek
- modifiedWeek
) {
261 switch (daysDistance
) {
262 case 0: retString
= i18nc("@title:group Date", "Today"); break;
263 case 1: retString
= i18nc("@title:group Date", "Yesterday"); break;
264 default: retString
= modifiedTime
.toString(i18nc("@title:group The week day name: %A", "%A"));
268 retString
= i18nc("@title:group Date", "Last Week");
271 retString
= i18nc("@title:group Date", "Two Weeks Ago");
274 retString
= i18nc("@title:group Date", "Three Weeks Ago");
278 retString
= i18nc("@title:group Date", "Earlier this Month");
284 const QDate lastMonthDate
= currentDate
.addMonths(-1);
285 if (lastMonthDate
.year() == modifiedDate
.year() && lastMonthDate
.month() == modifiedDate
.month()) {
286 if (daysDistance
== 1) {
287 retString
= modifiedTime
.toString(i18nc("@title:group Date: %B is full month name in current locale, and %Y is full year number", "Yesterday (%B, %Y)"));
288 } else if (daysDistance
<= 7) {
289 retString
= 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)"));
290 } else if (daysDistance
<= 7 * 2) {
291 retString
= modifiedTime
.toString(i18nc("@title:group Date: %B is full month name in current locale, and %Y is full year number", "Last Week (%B, %Y)"));
292 } else if (daysDistance
<= 7 * 3) {
293 retString
= 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)"));
294 } else if (daysDistance
<= 7 * 4) {
295 retString
= 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)"));
297 retString
= modifiedTime
.toString(i18nc("@title:group Date: %B is full month name in current locale, and %Y is full year number", "Earlier on %B, %Y"));
300 retString
= 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"));
306 case KDirModel::Permissions
: {
311 QFileInfo
info(item
.url().pathOrUrl());
314 if (info
.permission(QFile::ReadUser
)) {
315 user
= i18nc("@item:intext Access permission, concatenated", "Read, ");
317 if (info
.permission(QFile::WriteUser
)) {
318 user
+= i18nc("@item:intext Access permission, concatenated", "Write, ");
320 if (info
.permission(QFile::ExeUser
)) {
321 user
+= i18nc("@item:intext Access permission, concatenated", "Execute, ");
323 user
= user
.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : user
.mid(0, user
.count() - 2);
326 if (info
.permission(QFile::ReadGroup
)) {
327 group
= i18nc("@item:intext Access permission, concatenated", "Read, ");
329 if (info
.permission(QFile::WriteGroup
)) {
330 group
+= i18nc("@item:intext Access permission, concatenated", "Write, ");
332 if (info
.permission(QFile::ExeGroup
)) {
333 group
+= i18nc("@item:intext Access permission, concatenated", "Execute, ");
335 group
= group
.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : group
.mid(0, group
.count() - 2);
337 // set permission string
338 if (info
.permission(QFile::ReadOther
)) {
339 others
= i18nc("@item:intext Access permission, concatenated", "Read, ");
341 if (info
.permission(QFile::WriteOther
)) {
342 others
+= i18nc("@item:intext Access permission, concatenated", "Write, ");
344 if (info
.permission(QFile::ExeOther
)) {
345 others
+= i18nc("@item:intext Access permission, concatenated", "Execute, ");
347 others
= others
.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : others
.mid(0, others
.count() - 2);
349 retString
= i18nc("@title:group Files and folders by permissions", "(User: %1) (Group: %2) (Others: %3)", user
, group
, others
);
353 case KDirModel::Owner
:
354 retString
= item
.user();
357 case KDirModel::Group
:
358 retString
= item
.group();
361 case KDirModel::Type
:
362 retString
= item
.mimeComment();
365 case DolphinModel::Version
:
373 QVariant
DolphinModel::sortRoleData(const QModelIndex
& index
) const
377 if (!index
.isValid()) {
381 const KDirModel
*dirModel
= qobject_cast
<const KDirModel
*>(index
.model());
382 KFileItem item
= dirModel
->itemForIndex(index
);
384 switch (index
.column()) {
385 case KDirModel::Name
: {
386 retVariant
= data(index
, KCategorizedSortFilterProxyModel::CategoryDisplayRole
);
387 if (retVariant
== i18nc("@title:group Name", m_others
)) {
388 // assure that the "Others" group is always the last categorization
389 retVariant
= QString('Z').append(QChar::ReplacementCharacter
);
394 case KDirModel::Size
: {
395 const KIO::filesize_t fileSize
= !item
.isNull() ? item
.size() : ~0U;
398 } else if (fileSize
< 5242880) {
400 } else if (fileSize
< 10485760) {
408 case KDirModel::ModifiedTime
: {
409 KDateTime modifiedTime
= item
.time(KFileItem::ModificationTime
);
410 modifiedTime
= modifiedTime
.toLocalZone();
412 const QDate currentDate
= KDateTime::currentLocalDateTime().date();
413 const QDate modifiedDate
= modifiedTime
.date();
415 retVariant
= -modifiedDate
.daysTo(currentDate
);
419 case KDirModel::Permissions
: {
420 QFileInfo
info(item
.url().pathOrUrl());
422 retVariant
= -KDirSortFilterProxyModel::pointsForPermissions(info
);
426 case KDirModel::Owner
:
427 retVariant
= item
.user();
430 case KDirModel::Group
:
431 retVariant
= item
.group();
434 case KDirModel::Type
:
436 // when sorting we want folders to be placed first
437 retVariant
= QString(); // krazy:exclude=nullstrassign
439 retVariant
= item
.mimeComment();