]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphinsortfilterproxymodel.cpp
783a0af42646e6db4d038641a4eec854a04649dc
[dolphin.git] / src / dolphinsortfilterproxymodel.cpp
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> *
5 * *
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. *
10 * *
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. *
15 * *
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 ***************************************************************************/
21
22 #include "dolphinsortfilterproxymodel.h"
23
24 #include <kdirmodel.h>
25 #include <kfileitem.h>
26
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
32 };
33
34 static DolphinView::Sorting dirModelColumnToDolphinView[] = {
35 DolphinView::SortByName, // KDirModel::Name
36 DolphinView::SortBySize, // KDirModel::Size
37 DolphinView::SortByDate // KDirModel::ModifiedTime
38 };
39
40
41 DolphinSortFilterProxyModel::DolphinSortFilterProxyModel(QObject* parent) :
42 QSortFilterProxyModel(parent)
43 {
44 setDynamicSortFilter(true);
45
46 // sort by the user visible string for now
47 setSortRole(Qt::DisplayRole);
48 setSortCaseSensitivity(Qt::CaseInsensitive);
49 sort(KDirModel::Name, Qt::Ascending);
50 }
51
52 DolphinSortFilterProxyModel::~DolphinSortFilterProxyModel()
53 {
54 }
55
56 void DolphinSortFilterProxyModel::setSorting(DolphinView::Sorting sorting)
57 {
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)],
62 m_sortOrder );
63 }
64
65 void DolphinSortFilterProxyModel::setSortOrder(Qt::SortOrder sortOrder)
66 {
67 // change the sort order by keeping the current column
68 sort(dolphinViewToDirModelColumn[m_sorting], sortOrder);
69 }
70
71 void DolphinSortFilterProxyModel::sort(int column, Qt::SortOrder sortOrder)
72 {
73 m_sortOrder = sortOrder;
74 m_sorting = (column >= 0) && (column <= dolphinMapSize) ?
75 dirModelColumnToDolphinView[column] :
76 DolphinView::SortByName;
77 QSortFilterProxyModel::sort(column,sortOrder);
78 }
79
80 bool DolphinSortFilterProxyModel::lessThan(const QModelIndex& left,
81 const QModelIndex& right) const
82 {
83 KDirModel* dirModel = static_cast<KDirModel*>(sourceModel());
84
85 QVariant leftData = dirModel->data(left, sortRole());
86 QVariant rightData = dirModel->data(right, sortRole());
87
88 if ((leftData.type() == QVariant::String) && (rightData.type() == QVariant::String)) {
89 const QString leftStr = leftData.toString();
90 const QString rightStr = rightData.toString();
91
92 const bool leftIsDir = dirModel->itemForIndex(left)->isDir();
93 const bool rightIsDir = dirModel->itemForIndex(right)->isDir();
94
95 // assure that directories are always sorted before files
96 if (leftIsDir && !rightIsDir) {
97 return true;
98 }
99
100 if (!leftIsDir && rightIsDir) {
101 return false;
102 }
103
104 return sortCaseSensitivity() ? (naturalCompare(leftStr, rightStr) < 0) :
105 (naturalCompare(leftStr.toLower(), rightStr.toLower()) < 0);
106 }
107
108 // We have set a SortRole and trust the ProxyModel to do
109 // the right thing for now.
110 return QSortFilterProxyModel::lessThan(left, right);
111 }
112
113 int DolphinSortFilterProxyModel::naturalCompare(const QString& a,
114 const QString& b)
115 {
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, ...).
120 //
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.
124
125 const QChar* currA = a.unicode(); // iterator over a
126 const QChar* currB = b.unicode(); // iterator over b
127
128 if (currA == currB) {
129 return 0;
130 }
131
132 const QChar* begSeqA = currA; // beginning of a new character sequence of a
133 const QChar* begSeqB = currB;
134
135 while (!currA->isNull() && !currB->isNull()) {
136 // find sequence of characters ending at the first non-character
137 while (!currA->isNull() && !currA->isDigit()) {
138 ++currA;
139 }
140
141 while (!currB->isNull() && !currB->isDigit()) {
142 ++currB;
143 }
144
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);
149 if (cmp != 0) {
150 return cmp;
151 }
152
153 if (currA->isNull() || currB->isNull()) {
154 break;
155 }
156
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)
161 while (1) {
162 if (!currA->isDigit() && !currB->isDigit()) {
163 break;
164 }
165 else if (!currA->isDigit()) {
166 return -1;
167 }
168 else if (!currB->isDigit()) {
169 return +1;
170 }
171 else if (*currA < *currB ) {
172 return -1;
173 }
174 else if (*currA > *currB) {
175 return +1;
176 }
177 ++currA;
178 ++currB;
179 }
180 }
181 else {
182 // No digit-sequence starts with 0 -> assume we are looking at some integer
183 // do right aligned comparison.
184 //
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.
188
189 int weight = 0;
190 while (1) {
191 if (!currA->isDigit() && !currB->isDigit()) {
192 if (weight != 0) {
193 return weight;
194 }
195 break;
196 }
197 else if (!currA->isDigit()) {
198 return -1;
199 }
200 else if (!currB->isDigit()) {
201 return +1;
202 }
203 else if ((*currA < *currB) && (weight == 0)) {
204 weight = -1;
205 }
206 else if ((*currA > *currB) && (weight == 0)) {
207 weight = +1;
208 }
209 ++currA;
210 ++currB;
211 }
212 }
213
214 begSeqA = currA;
215 begSeqB = currB;
216 }
217
218 if (currA->isNull() && currB->isNull()) {
219 return 0;
220 }
221
222 return currA->isNull() ? -1 : +1;
223 }
224
225 #include "dolphinsortfilterproxymodel.moc"