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 // KFileItem::text() may not be unique (in case UDS_DISPLAY_NAME is used). In that case we 00172 // fall back to the name which is always unique 00173 const int result = d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()); 00174 if (result == 0) { 00175 return d->compare(leftFileItem.name(sortCaseSensitivity() == Qt::CaseInsensitive), 00176 rightFileItem.name(sortCaseSensitivity() == Qt::CaseInsensitive), 00177 sortCaseSensitivity()) < 0; 00178 } else { 00179 return result < 0; 00180 } 00181 } 00182 00183 case KDirModel::Size: { 00184 // If we have two folders, what we have to measure is the number of 00185 // items that contains each other 00186 if (leftFileItem.isDir() && rightFileItem.isDir()) { 00187 QVariant leftValue = dirModel->data(left, KDirModel::ChildCountRole); 00188 int leftCount = (leftValue.type() == QVariant::Int) ? leftValue.toInt() : KDirModel::ChildCountUnknown; 00189 00190 QVariant rightValue = dirModel->data(right, KDirModel::ChildCountRole); 00191 int rightCount = (rightValue.type() == QVariant::Int) ? rightValue.toInt() : KDirModel::ChildCountUnknown; 00192 00193 // In the case they two have the same child items, we sort them by 00194 // their names. So we have always everything ordered. We also check 00195 // if we are taking in count their cases. 00196 if (leftCount == rightCount) { 00197 return d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()) < 0; 00198 } 00199 00200 // If one of them has unknown child items, place them on the end. If we 00201 // were comparing two unknown childed items, the previous comparation 00202 // sorted them by naturalCompare between them. This case is when we 00203 // have an unknown childed item, and another known. 00204 if (leftCount == KDirModel::ChildCountUnknown) { 00205 return false; 00206 } 00207 00208 if (rightCount == KDirModel::ChildCountUnknown) { 00209 return true; 00210 } 00211 00212 // If they had different number of items, we sort them depending 00213 // on how many items had each other. 00214 return leftCount < rightCount; 00215 } 00216 00217 // If what we are measuring is two files and they have the same size, 00218 // sort them by their file names. 00219 if (leftFileItem.size() == rightFileItem.size()) { 00220 return d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()) < 0; 00221 } 00222 00223 // If their sizes are different, sort them by their sizes, as expected. 00224 return leftFileItem.size() < rightFileItem.size(); 00225 } 00226 00227 case KDirModel::ModifiedTime: { 00228 KDateTime leftModifiedTime = leftFileItem.time(KFileItem::ModificationTime).toLocalZone(); 00229 KDateTime rightModifiedTime = rightFileItem.time(KFileItem::ModificationTime).toLocalZone(); 00230 00231 if (leftModifiedTime == rightModifiedTime) { 00232 return d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()) < 0; 00233 } 00234 00235 return leftModifiedTime < rightModifiedTime; 00236 } 00237 00238 case KDirModel::Permissions: { 00239 // ### You can't use QFileInfo on urls!! Use the KFileItem instead. 00240 QFileInfo leftFileInfo(leftFileItem.url().pathOrUrl()); 00241 QFileInfo rightFileInfo(rightFileItem.url().pathOrUrl()); 00242 00243 int leftPermissionsPoints = pointsForPermissions(leftFileInfo); 00244 int rightPermissionsPoints = pointsForPermissions(rightFileInfo); 00245 00246 if (leftPermissionsPoints == rightPermissionsPoints) { 00247 return d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()) < 0; 00248 } 00249 00250 return leftPermissionsPoints > rightPermissionsPoints; 00251 } 00252 00253 case KDirModel::Owner: { 00254 if (leftFileItem.user() == rightFileItem.user()) { 00255 return d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()) < 0; 00256 } 00257 00258 return d->compare(leftFileItem.user(), rightFileItem.user()) < 0; 00259 } 00260 00261 case KDirModel::Group: { 00262 if (leftFileItem.group() == rightFileItem.group()) { 00263 return d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()) < 0; 00264 } 00265 00266 return d->compare(leftFileItem.group(), rightFileItem.group()) < 0; 00267 } 00268 00269 case KDirModel::Type: { 00270 if (leftFileItem.mimetype() == rightFileItem.mimetype()) { 00271 return d->compare(leftFileItem.text(), rightFileItem.text(), sortCaseSensitivity()) < 0; 00272 } 00273 00274 return d->compare(leftFileItem.mimeComment(), rightFileItem.mimeComment()) < 0; 00275 } 00276 00277 } 00278 00279 // We have set a SortRole and trust the ProxyModel to do 00280 // the right thing for now. 00281 return KCategorizedSortFilterProxyModel::subSortLessThan(left, right); 00282 } 00283 00284 #include "kdirsortfilterproxymodel.moc"
KDE 4.6 API Reference