1 /***************************************************************************
2 * Copyright (C) 2006 by Peter Penz <peter.penz@gmx.at> *
3 * Copyright (C) 2006 by Dominic Battre <dominic@battre.de> *
4 * Copyright (C) 2006 by Martin Pool <mbp@canonical.com> *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20 ***************************************************************************/
22 #include "dolphinsortfilterproxymodel.h"
24 #include <kdirmodel.h>
25 #include <kfileitem.h>
27 static const int dolphinMapSize
= 7;
28 static int dolphinViewToDirModelColumn
[] =
30 KDirModel::Name
, // DolphinView::SortByName
31 KDirModel::Size
, // DolphinView::SortBySize
32 KDirModel::ModifiedTime
, // DolphinView::SortByDate
33 KDirModel::Permissions
, // DolphinView::SortByPermissions
34 KDirModel::Owner
, // DolphinView::SortByOwner
35 KDirModel::Group
, // DolphinView::SortByGroup
36 KDirModel::Type
// DolphinView::SortByType
39 static DolphinView::Sorting dirModelColumnToDolphinView
[] =
41 DolphinView::SortByName
, // KDirModel::Name
42 DolphinView::SortBySize
, // KDirModel::Size
43 DolphinView::SortByDate
, // KDirModel::ModifiedTime
44 DolphinView::SortByPermissions
, // KDirModel::Permissions
45 DolphinView::SortByOwner
, // KDirModel::Owner
46 DolphinView::SortByGroup
, // KDirModel::Group
47 DolphinView::SortByType
// KDirModel::Type
51 DolphinSortFilterProxyModel::DolphinSortFilterProxyModel(QObject
* parent
) :
52 QSortFilterProxyModel(parent
),
54 m_sorting(DolphinView::SortByName
),
55 m_sortOrder(Qt::AscendingOrder
)
57 setDynamicSortFilter(true);
59 // sort by the user visible string for now
60 setSortRole(Qt::DisplayRole
);
61 setSortCaseSensitivity(Qt::CaseInsensitive
);
62 sort(KDirModel::Name
, Qt::AscendingOrder
);
65 DolphinSortFilterProxyModel::~DolphinSortFilterProxyModel()
68 void DolphinSortFilterProxyModel::setSorting(DolphinView::Sorting sorting
)
70 // Update the sort column by mapping DolpginView::Sorting to
71 // KDirModel::ModelColumns. We will keep the sortOrder.
72 Q_ASSERT(static_cast<int>(sorting
) >= 0 && static_cast<int>(sorting
) < dolphinMapSize
);
73 sort(dolphinViewToDirModelColumn
[static_cast<int>(sorting
)],
77 void DolphinSortFilterProxyModel::setSortOrder(Qt::SortOrder sortOrder
)
79 // change the sort order by keeping the current column
80 sort(dolphinViewToDirModelColumn
[m_sorting
], sortOrder
);
83 void DolphinSortFilterProxyModel::sort(int column
, Qt::SortOrder sortOrder
)
85 m_sortColumn
= column
;
86 m_sortOrder
= sortOrder
;
87 m_sorting
= (column
>= 0) && (column
< dolphinMapSize
) ?
88 dirModelColumnToDolphinView
[column
] :
89 DolphinView::SortByName
;
90 QSortFilterProxyModel::sort(column
, sortOrder
);
93 bool DolphinSortFilterProxyModel::hasChildren(const QModelIndex
& parent
) const
95 const QModelIndex sourceParent
= mapToSource(parent
);
96 return sourceModel()->hasChildren(sourceParent
);
99 bool DolphinSortFilterProxyModel::canFetchMore(const QModelIndex
& parent
) const
101 const QModelIndex sourceParent
= mapToSource(parent
);
102 return sourceModel()->canFetchMore(sourceParent
);
105 DolphinView::Sorting
DolphinSortFilterProxyModel::sortingForColumn(int column
)
107 if ((column
>= 0) && (column
< dolphinMapSize
)) {
108 return dirModelColumnToDolphinView
[column
];
110 return DolphinView::SortByName
;
113 bool DolphinSortFilterProxyModel::lessThan(const QModelIndex
& left
,
114 const QModelIndex
& right
) const
116 KDirModel
* dirModel
= static_cast<KDirModel
*>(sourceModel());
118 QVariant leftData
= dirModel
->data(left
, sortRole());
119 QVariant rightData
= dirModel
->data(right
, sortRole());
121 if ((leftData
.type() == QVariant::String
) && (rightData
.type() == QVariant::String
)) {
122 // assure that directories are always sorted before files
123 // if the sorting is done by the 'Name' column
124 if (m_sortColumn
== KDirModel::Name
) {
125 const bool leftIsDir
= dirModel
->itemForIndex(left
)->isDir();
126 const bool rightIsDir
= dirModel
->itemForIndex(right
)->isDir();
127 if (leftIsDir
&& !rightIsDir
) {
131 if (!leftIsDir
&& rightIsDir
) {
136 const QString leftStr
= leftData
.toString();
137 const QString rightStr
= rightData
.toString();
139 return sortCaseSensitivity() ? (naturalCompare(leftStr
, rightStr
) < 0) :
140 (naturalCompare(leftStr
.toLower(), rightStr
.toLower()) < 0);
143 // We have set a SortRole and trust the ProxyModel to do
144 // the right thing for now.
145 return QSortFilterProxyModel::lessThan(left
, right
);
148 int DolphinSortFilterProxyModel::naturalCompare(const QString
& a
,
151 // This method chops the input a and b into pieces of
152 // digits and non-digits (a1.05 becomes a | 1 | . | 05)
153 // and compares these pieces of a and b to each other
154 // (first with first, second with second, ...).
156 // This is based on the natural sort order code code by Martin Pool
157 // http://sourcefrog.net/projects/natsort/
158 // Martin Pool agreed to license this under LGPL or GPL.
160 const QChar
* currA
= a
.unicode(); // iterator over a
161 const QChar
* currB
= b
.unicode(); // iterator over b
163 if (currA
== currB
) {
167 const QChar
* begSeqA
= currA
; // beginning of a new character sequence of a
168 const QChar
* begSeqB
= currB
;
170 while (!currA
->isNull() && !currB
->isNull()) {
171 // find sequence of characters ending at the first non-character
172 while (!currA
->isNull() && !currA
->isDigit()) {
176 while (!currB
->isNull() && !currB
->isDigit()) {
180 // compare these sequences
181 const QString
subA(begSeqA
, currA
- begSeqA
);
182 const QString
subB(begSeqB
, currB
- begSeqB
);
183 const int cmp
= QString::localeAwareCompare(subA
, subB
);
188 if (currA
->isNull() || currB
->isNull()) {
192 // now some digits follow...
193 if ((*currA
== '0') || (*currB
== '0')) {
194 // one digit-sequence starts with 0 -> assume we are in a fraction part
195 // do left aligned comparison (numbers are considered left aligned)
197 if (!currA
->isDigit() && !currB
->isDigit()) {
199 } else if (!currA
->isDigit()) {
201 } else if (!currB
->isDigit()) {
203 } else if (*currA
< *currB
) {
205 } else if (*currA
> *currB
) {
212 // No digit-sequence starts with 0 -> assume we are looking at some integer
213 // do right aligned comparison.
215 // The longest run of digits wins. That aside, the greatest
216 // value wins, but we can't know that it will until we've scanned
217 // both numbers to know that they have the same magnitude.
221 if (!currA
->isDigit() && !currB
->isDigit()) {
226 } else if (!currA
->isDigit()) {
228 } else if (!currB
->isDigit()) {
230 } else if ((*currA
< *currB
) && (weight
== 0)) {
232 } else if ((*currA
> *currB
) && (weight
== 0)) {
244 if (currA
->isNull() && currB
->isNull()) {
248 return currA
->isNull() ? -1 : + 1;
251 #include "dolphinsortfilterproxymodel.moc"