KFile
kdirsortfilterproxymodel.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (C) 2006 by Peter Penz <peter.penz@gmx.at> 00003 Copyright (C) 2006 by Dominic Battre <dominic@battre.de> 00004 Copyright (C) 2006 by Martin Pool <mbp@canonical.com> 00005 00006 Separated from Dolphin by Nick Shaforostoff <shafff@ukr.net> 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public 00010 License version 2 as published by the Free Software Foundation. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00022 00023 #include "kdirsortfilterproxymodel.h" 00024 00025 #include <kdatetime.h> 00026 #include <kdirmodel.h> 00027 #include <kfileitem.h> 00028 #include <kglobalsettings.h> 00029 #include <klocale.h> 00030 #include <kstringhandler.h> 00031 00032 00033 class KDirSortFilterProxyModel::KDirSortFilterProxyModelPrivate 00034 { 00035 public: 00036 KDirSortFilterProxyModelPrivate(KDirSortFilterProxyModel* q); 00037 00038 int compare(const QString&, const QString&, Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive) const; 00039 void slotNaturalSortingChanged(); 00040 00041 bool m_sortFoldersFirst; 00042 bool m_naturalSorting; 00043 }; 00044 00045 KDirSortFilterProxyModel::KDirSortFilterProxyModelPrivate::KDirSortFilterProxyModelPrivate(KDirSortFilterProxyModel* q) : 00046 m_sortFoldersFirst(true), 00047 m_naturalSorting(KGlobalSettings::naturalSorting()) 00048 { 00049 connect(KGlobalSettings::self(), SIGNAL(naturalSortingChanged()), 00050 q, SLOT(slotNaturalSortingChanged())); 00051 } 00052 00053 int KDirSortFilterProxyModel::KDirSortFilterProxyModelPrivate::compare(const QString& a, 00054 const QString& b, 00055 Qt::CaseSensitivity caseSensitivity) const 00056 { 00057 if (caseSensitivity == Qt::CaseInsensitive) { 00058 const int result = m_naturalSorting ? KStringHandler::naturalCompare(a, b, Qt::CaseInsensitive) 00059 : QString::compare(a, b, Qt::CaseInsensitive); 00060 if (result != 0) { 00061 // Only return the result, if the strings are not equal. If they are equal by a case insensitive 00062 // comparison, still a deterministic sort order is required. A case sensitive 00063 // comparison is done as fallback. 00064 return result; 00065 } 00066 } 00067 00068 return m_naturalSorting ? KStringHandler::naturalCompare(a, b, Qt::CaseSensitive) 00069 : QString::compare(a, b, Qt::CaseSensitive); 00070 } 00071 00072 00073 void KDirSortFilterProxyModel::KDirSortFilterProxyModelPrivate::slotNaturalSortingChanged() 00074 { 00075 m_naturalSorting = KGlobalSettings::naturalSorting(); 00076 } 00077 00078 KDirSortFilterProxyModel::KDirSortFilterProxyModel(QObject* parent) 00079 : KCategorizedSortFilterProxyModel(parent), d(new KDirSortFilterProxyModelPrivate(this)) 00080 { 00081 setDynamicSortFilter(true); 00082 00083 // sort by the user visible string for now 00084 setSortCaseSensitivity(Qt::CaseInsensitive); 00085 sort(KDirModel::Name, Qt::AscendingOrder); 00086 00087 setSupportedDragActions(Qt::CopyAction | Qt::MoveAction | Qt::LinkAction | Qt::IgnoreAction); 00088 } 00089 00090 KDirSortFilterProxyModel::~KDirSortFilterProxyModel() 00091 { 00092 delete d; 00093 } 00094 00095 bool KDirSortFilterProxyModel::hasChildren(const QModelIndex& parent) const 00096 { 00097 const QModelIndex sourceParent = mapToSource(parent); 00098 return sourceModel()->hasChildren(sourceParent); 00099 } 00100 00101 bool KDirSortFilterProxyModel::canFetchMore(const QModelIndex& parent) const 00102 { 00103 const QModelIndex sourceParent = mapToSource(parent); 00104 return sourceModel()->canFetchMore(sourceParent); 00105 } 00106 00107 int KDirSortFilterProxyModel::pointsForPermissions(const QFileInfo &info) 00108 { 00109 int points = 0; 00110 00111 QFile::Permission permissionsCheck[] = { QFile::ReadUser, 00112 QFile::WriteUser, 00113 QFile::ExeUser, 00114 QFile::ReadGroup, 00115 QFile::WriteGroup, 00116 QFile::ExeGroup, 00117 QFile::ReadOther, 00118 QFile::WriteOther, 00119 QFile::ExeOther }; 00120 00121 for (int i = 0; i < 9; i++) { 00122 points += info.permission(permissionsCheck[i]) ? 1 : 0; 00123 } 00124 00125 return points; 00126 } 00127 00128 void KDirSortFilterProxyModel::setSortFoldersFirst(bool foldersFirst) 00129 { 00130 d->m_sortFoldersFirst = foldersFirst; 00131 } 00132 00133 bool KDirSortFilterProxyModel::sortFoldersFirst() const 00134 { 00135 return d->m_sortFoldersFirst; 00136 } 00137 00138 bool KDirSortFilterProxyModel::subSortLessThan(const QModelIndex& left, 00139 const QModelIndex& right) const 00140 { 00141 KDirModel* dirModel = static_cast<KDirModel*>(sourceModel()); 00142 00143 const KFileItem leftFileItem = dirModel->itemForIndex(left); 00144 const KFileItem rightFileItem = dirModel->itemForIndex(right); 00145 00146 const bool isLessThan = (sortOrder() == Qt::AscendingOrder); 00147 00148 // Folders go before files if the corresponding setting is set. 00149 if (d->m_sortFoldersFirst) { 00150 const bool leftItemIsDir = leftFileItem.isDir(); 00151 const bool rightItemIsDir = rightFileItem.isDir(); 00152 if (leftItemIsDir && !rightItemIsDir) { 00153 return isLessThan; 00154 } else if (!leftItemIsDir && rightItemIsDir) { 00155 return !isLessThan; 00156 } 00157 } 00158 00159 00160 // Hidden elements go before visible ones. 00161 const bool leftItemIsHidden = leftFileItem.isHidden(); 00162 const bool rightItemIsHidden = rightFileItem.isHidden(); 00163 if (leftItemIsHidden && !rightItemIsHidden) { 00164 return isLessThan; 00165 } else if (!leftItemIsHidden && rightItemIsHidden) { 00166 return !isLessThan; 00167 } 00168 00169 switch (left.column()) { 00170 case KDirModel::Name: { 00171 int result = d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()); 00172 if (result == 0) { 00173 // KFileItem::text() may not be unique in case UDS_DISPLAY_NAME is used 00174 result = d->compare(leftFileItem.name(sortCaseSensitivity() == Qt::CaseInsensitive), 00175 rightFileItem.name(sortCaseSensitivity() == Qt::CaseInsensitive), 00176 sortCaseSensitivity()); 00177 if (result == 0) { 00178 // If KFileItem::text() is also not unique most probably a search protocol is used 00179 // that allows showing the same file names from different directories 00180 result = d->compare(leftFileItem.url().url(), rightFileItem.url().url(), sortCaseSensitivity()); 00181 } 00182 } 00183 00184 return result < 0; 00185 } 00186 00187 case KDirModel::Size: { 00188 // If we have two folders, what we have to measure is the number of 00189 // items that contains each other 00190 if (leftFileItem.isDir() && rightFileItem.isDir()) { 00191 QVariant leftValue = dirModel->data(left, KDirModel::ChildCountRole); 00192 int leftCount = (leftValue.type() == QVariant::Int) ? leftValue.toInt() : KDirModel::ChildCountUnknown; 00193 00194 QVariant rightValue = dirModel->data(right, KDirModel::ChildCountRole); 00195 int rightCount = (rightValue.type() == QVariant::Int) ? rightValue.toInt() : KDirModel::ChildCountUnknown; 00196 00197 // In the case they two have the same child items, we sort them by 00198 // their names. So we have always everything ordered. We also check 00199 // if we are taking in count their cases. 00200 if (leftCount == rightCount) { 00201 return d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()) < 0; 00202 } 00203 00204 // If one of them has unknown child items, place them on the end. If we 00205 // were comparing two unknown childed items, the previous comparation 00206 // sorted them by naturalCompare between them. This case is when we 00207 // have an unknown childed item, and another known. 00208 if (leftCount == KDirModel::ChildCountUnknown) { 00209 return false; 00210 } 00211 00212 if (rightCount == KDirModel::ChildCountUnknown) { 00213 return true; 00214 } 00215 00216 // If they had different number of items, we sort them depending 00217 // on how many items had each other. 00218 return leftCount < rightCount; 00219 } 00220 00221 // If what we are measuring is two files and they have the same size, 00222 // sort them by their file names. 00223 if (leftFileItem.size() == rightFileItem.size()) { 00224 return d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()) < 0; 00225 } 00226 00227 // If their sizes are different, sort them by their sizes, as expected. 00228 return leftFileItem.size() < rightFileItem.size(); 00229 } 00230 00231 case KDirModel::ModifiedTime: { 00232 KDateTime leftModifiedTime = leftFileItem.time(KFileItem::ModificationTime).toLocalZone(); 00233 KDateTime rightModifiedTime = rightFileItem.time(KFileItem::ModificationTime).toLocalZone(); 00234 00235 if (leftModifiedTime == rightModifiedTime) { 00236 return d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()) < 0; 00237 } 00238 00239 return leftModifiedTime < rightModifiedTime; 00240 } 00241 00242 case KDirModel::Permissions: { 00243 // ### You can't use QFileInfo on urls!! Use the KFileItem instead. 00244 QFileInfo leftFileInfo(leftFileItem.url().pathOrUrl()); 00245 QFileInfo rightFileInfo(rightFileItem.url().pathOrUrl()); 00246 00247 int leftPermissionsPoints = pointsForPermissions(leftFileInfo); 00248 int rightPermissionsPoints = pointsForPermissions(rightFileInfo); 00249 00250 if (leftPermissionsPoints == rightPermissionsPoints) { 00251 return d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()) < 0; 00252 } 00253 00254 return leftPermissionsPoints > rightPermissionsPoints; 00255 } 00256 00257 case KDirModel::Owner: { 00258 if (leftFileItem.user() == rightFileItem.user()) { 00259 return d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()) < 0; 00260 } 00261 00262 return d->compare(leftFileItem.user(), rightFileItem.user()) < 0; 00263 } 00264 00265 case KDirModel::Group: { 00266 if (leftFileItem.group() == rightFileItem.group()) { 00267 return d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()) < 0; 00268 } 00269 00270 return d->compare(leftFileItem.group(), rightFileItem.group()) < 0; 00271 } 00272 00273 case KDirModel::Type: { 00274 if (leftFileItem.mimetype() == rightFileItem.mimetype()) { 00275 return d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()) < 0; 00276 } 00277 00278 return d->compare(leftFileItem.mimeComment(), rightFileItem.mimeComment()) < 0; 00279 } 00280 00281 } 00282 00283 // We have set a SortRole and trust the ProxyModel to do 00284 // the right thing for now. 00285 return KCategorizedSortFilterProxyModel::subSortLessThan(left, right); 00286 } 00287 00288 #include "kdirsortfilterproxymodel.moc"
KDE 4.7 API Reference