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
= 3;
28 static int dolphinViewToDirModelColumn
[] = {
29 KDirModel::Name
, // DolphinView::SortByName
30 KDirModel::Size
, // DolphinView::SortBySize
31 KDirModel::ModifiedTime
// DolphinView::SortByDate
34 static DolphinView::Sorting dirModelColumnToDolphinView
[] = {
35 DolphinView::SortByName
, // KDirModel::Name
36 DolphinView::SortBySize
, // KDirModel::Size
37 DolphinView::SortByDate
// KDirModel::ModifiedTime
41 DolphinSortFilterProxyModel::DolphinSortFilterProxyModel(QObject
* parent
) :
42 QSortFilterProxyModel(parent
)
44 setDynamicSortFilter(true);
46 // sort by the user visible string for now
47 setSortRole(Qt::DisplayRole
);
48 setSortCaseSensitivity(Qt::CaseInsensitive
);
49 sort(KDirModel::Name
, Qt::Ascending
);
52 DolphinSortFilterProxyModel::~DolphinSortFilterProxyModel()
56 void DolphinSortFilterProxyModel::setSorting(DolphinView::Sorting sorting
)
58 // Update the sort column by mapping DolpginView::Sorting to
59 // KDirModel::ModelColumns. We will keep the sortOrder.
60 Q_ASSERT(static_cast<int>(sorting
) >= 0 && static_cast<int>(sorting
) <= dolphinMapSize
);
61 sort(dolphinViewToDirModelColumn
[static_cast<int>(sorting
)],
65 void DolphinSortFilterProxyModel::setSortOrder(Qt::SortOrder sortOrder
)
67 // change the sort order by keeping the current column
68 sort(dolphinViewToDirModelColumn
[m_sorting
], sortOrder
);
71 void DolphinSortFilterProxyModel::sort(int column
, Qt::SortOrder sortOrder
)
73 m_sortOrder
= sortOrder
;
74 m_sorting
= (column
>= 0) && (column
<= dolphinMapSize
) ?
75 dirModelColumnToDolphinView
[column
] :
76 DolphinView::SortByName
;
77 QSortFilterProxyModel::sort(column
,sortOrder
);
80 bool DolphinSortFilterProxyModel::lessThan(const QModelIndex
& left
,
81 const QModelIndex
& right
) const
83 KDirModel
* dirModel
= static_cast<KDirModel
*>(sourceModel());
85 QVariant leftData
= dirModel
->data(left
, sortRole());
86 QVariant rightData
= dirModel
->data(right
, sortRole());
88 if ((leftData
.type() == QVariant::String
) && (rightData
.type() == QVariant::String
)) {
89 const QString leftStr
= leftData
.toString();
90 const QString rightStr
= rightData
.toString();
92 const bool leftIsDir
= dirModel
->itemForIndex(left
)->isDir();
93 const bool rightIsDir
= dirModel
->itemForIndex(right
)->isDir();
95 // assure that directories are always sorted before files
96 if (leftIsDir
&& !rightIsDir
) {
100 if (!leftIsDir
&& rightIsDir
) {
104 return sortCaseSensitivity() ? (naturalCompare(leftStr
, rightStr
) < 0) :
105 (naturalCompare(leftStr
.toLower(), rightStr
.toLower()) < 0);
108 // We have set a SortRole and trust the ProxyModel to do
109 // the right thing for now.
110 return QSortFilterProxyModel::lessThan(left
, right
);
113 int DolphinSortFilterProxyModel::naturalCompare(const QString
& a
,
116 // This method chops the input a and b into pieces of
117 // digits and non-digits (a1.05 becomes a | 1 | . | 05)
118 // and compares these pieces of a and b to each other
119 // (first with first, second with second, ...).
121 // This is based on the natural sort order code code by Martin Pool
122 // http://sourcefrog.net/projects/natsort/
123 // Martin Pool agreed to license this under LGPL or GPL.
125 const QChar
* currA
= a
.unicode(); // iterator over a
126 const QChar
* currB
= b
.unicode(); // iterator over b
128 if (currA
== currB
) {
132 const QChar
* begSeqA
= currA
; // beginning of a new character sequence of a
133 const QChar
* begSeqB
= currB
;
135 while (!currA
->isNull() && !currB
->isNull()) {
136 // find sequence of characters ending at the first non-character
137 while (!currA
->isNull() && !currA
->isDigit()) {
141 while (!currB
->isNull() && !currB
->isDigit()) {
145 // compare these sequences
146 const QString
subA(begSeqA
, currA
- begSeqA
);
147 const QString
subB(begSeqB
, currB
- begSeqB
);
148 const int cmp
= QString::localeAwareCompare(subA
, subB
);
153 if (currA
->isNull() || currB
->isNull()) {
157 // now some digits follow...
158 if ((*currA
== '0') || (*currB
== '0')) {
159 // one digit-sequence starts with 0 -> assume we are in a fraction part
160 // do left aligned comparison (numbers are considered left aligned)
162 if (!currA
->isDigit() && !currB
->isDigit()) {
165 else if (!currA
->isDigit()) {
168 else if (!currB
->isDigit()) {
171 else if (*currA
< *currB
) {
174 else if (*currA
> *currB
) {
182 // No digit-sequence starts with 0 -> assume we are looking at some integer
183 // do right aligned comparison.
185 // The longest run of digits wins. That aside, the greatest
186 // value wins, but we can't know that it will until we've scanned
187 // both numbers to know that they have the same magnitude.
191 if (!currA
->isDigit() && !currB
->isDigit()) {
197 else if (!currA
->isDigit()) {
200 else if (!currB
->isDigit()) {
203 else if ((*currA
< *currB
) && (weight
== 0)) {
206 else if ((*currA
> *currB
) && (weight
== 0)) {
218 if (currA
->isNull() && currB
->isNull()) {
222 return currA
->isNull() ? -1 : +1;
225 #include "dolphinsortfilterproxymodel.moc"