File indexing completed on 2025-01-05 04:02:13
0001 /* 0002 Gwenview: an image viewer 0003 Copyright 2007 Aurélien Gâteau <agateau@kde.org> 0004 0005 This program is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU General Public License 0007 as published by the Free Software Foundation; either version 2 0008 of the License, or (at your option) any later version. 0009 0010 This program is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 GNU General Public License for more details. 0014 0015 You should have received a copy of the GNU General Public License 0016 along with this program; if not, write to the Free Software 0017 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 0018 0019 */ 0020 #include "sorteddirmodel.h" 0021 0022 // Qt 0023 #include <QTimer> 0024 #include <QUrl> 0025 0026 // KF 0027 #include <KDirLister> 0028 #ifdef GWENVIEW_SEMANTICINFO_BACKEND_NONE 0029 #include <KDirModel> 0030 #endif 0031 // Local 0032 #include <lib/archiveutils.h> 0033 #include <lib/timeutils.h> 0034 #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE 0035 #include "abstractsemanticinfobackend.h" 0036 #include "semanticinfodirmodel.h" 0037 #include <lib/sorting.h> 0038 #endif 0039 0040 namespace Gwenview 0041 { 0042 AbstractSortedDirModelFilter::AbstractSortedDirModelFilter(SortedDirModel *model) 0043 : QObject(model) 0044 , mModel(model) 0045 { 0046 if (mModel) { 0047 mModel->addFilter(this); 0048 } 0049 } 0050 0051 AbstractSortedDirModelFilter::~AbstractSortedDirModelFilter() 0052 { 0053 if (mModel) { 0054 mModel->removeFilter(this); 0055 } 0056 } 0057 0058 struct SortedDirModelPrivate { 0059 #ifdef GWENVIEW_SEMANTICINFO_BACKEND_NONE 0060 KDirModel *mSourceModel; 0061 #else 0062 SemanticInfoDirModel *mSourceModel; 0063 #endif 0064 QStringList mBlackListedExtensions; 0065 QList<AbstractSortedDirModelFilter *> mFilters; 0066 QTimer mDelayedApplyFiltersTimer; 0067 MimeTypeUtils::Kinds mKindFilter; 0068 }; 0069 0070 SortedDirModel::SortedDirModel(QObject *parent) 0071 : KDirSortFilterProxyModel(parent) 0072 , d(new SortedDirModelPrivate) 0073 { 0074 #ifdef GWENVIEW_SEMANTICINFO_BACKEND_NONE 0075 d->mSourceModel = new KDirModel(this); 0076 #else 0077 d->mSourceModel = new SemanticInfoDirModel(this); 0078 #endif 0079 setSourceModel(d->mSourceModel); 0080 0081 d->mSourceModel->dirLister()->setRequestMimeTypeWhileListing(true); 0082 0083 d->mDelayedApplyFiltersTimer.setInterval(0); 0084 d->mDelayedApplyFiltersTimer.setSingleShot(true); 0085 connect(&d->mDelayedApplyFiltersTimer, &QTimer::timeout, this, &SortedDirModel::doApplyFilters); 0086 } 0087 0088 SortedDirModel::~SortedDirModel() 0089 { 0090 delete d; 0091 } 0092 0093 MimeTypeUtils::Kinds SortedDirModel::kindFilter() const 0094 { 0095 return d->mKindFilter; 0096 } 0097 0098 void SortedDirModel::setKindFilter(MimeTypeUtils::Kinds kindFilter) 0099 { 0100 if (d->mKindFilter == kindFilter) { 0101 return; 0102 } 0103 d->mKindFilter = kindFilter; 0104 applyFilters(); 0105 } 0106 0107 void SortedDirModel::adjustKindFilter(MimeTypeUtils::Kinds kinds, bool set) 0108 { 0109 MimeTypeUtils::Kinds kindFilter = d->mKindFilter; 0110 if (set) { 0111 kindFilter |= kinds; 0112 } else { 0113 kindFilter &= ~kinds; 0114 } 0115 setKindFilter(kindFilter); 0116 } 0117 0118 void SortedDirModel::addFilter(AbstractSortedDirModelFilter *filter) 0119 { 0120 d->mFilters << filter; 0121 applyFilters(); 0122 } 0123 0124 void SortedDirModel::removeFilter(AbstractSortedDirModelFilter *filter) 0125 { 0126 d->mFilters.removeAll(filter); 0127 applyFilters(); 0128 } 0129 0130 KDirLister *SortedDirModel::dirLister() const 0131 { 0132 return d->mSourceModel->dirLister(); 0133 } 0134 0135 void SortedDirModel::reload() 0136 { 0137 #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE 0138 d->mSourceModel->clearSemanticInfoCache(); 0139 #endif 0140 dirLister()->updateDirectory(dirLister()->url()); 0141 } 0142 0143 void SortedDirModel::setBlackListedExtensions(const QStringList &list) 0144 { 0145 d->mBlackListedExtensions = list; 0146 } 0147 0148 KFileItem SortedDirModel::itemForIndex(const QModelIndex &index) const 0149 { 0150 if (!index.isValid()) { 0151 return {}; 0152 } 0153 0154 QModelIndex sourceIndex = mapToSource(index); 0155 return d->mSourceModel->itemForIndex(sourceIndex); 0156 } 0157 0158 QUrl SortedDirModel::urlForIndex(const QModelIndex &index) const 0159 { 0160 KFileItem item = itemForIndex(index); 0161 return item.isNull() ? QUrl() : item.url(); 0162 } 0163 0164 KFileItem SortedDirModel::itemForSourceIndex(const QModelIndex &sourceIndex) const 0165 { 0166 if (!sourceIndex.isValid()) { 0167 return {}; 0168 } 0169 return d->mSourceModel->itemForIndex(sourceIndex); 0170 } 0171 0172 QModelIndex SortedDirModel::indexForItem(const KFileItem &item) const 0173 { 0174 if (item.isNull()) { 0175 return {}; 0176 } 0177 0178 QModelIndex sourceIndex = d->mSourceModel->indexForItem(item); 0179 return mapFromSource(sourceIndex); 0180 } 0181 0182 QModelIndex SortedDirModel::indexForUrl(const QUrl &url) const 0183 { 0184 if (!url.isValid()) { 0185 return {}; 0186 } 0187 QModelIndex sourceIndex = d->mSourceModel->indexForUrl(url); 0188 return mapFromSource(sourceIndex); 0189 } 0190 0191 bool SortedDirModel::filterAcceptsRow(int row, const QModelIndex &parent) const 0192 { 0193 QModelIndex index = d->mSourceModel->index(row, 0, parent); 0194 KFileItem fileItem = d->mSourceModel->itemForIndex(index); 0195 0196 MimeTypeUtils::Kinds kind = MimeTypeUtils::fileItemKind(fileItem); 0197 if (d->mKindFilter != MimeTypeUtils::Kinds() && !(d->mKindFilter & kind)) { 0198 return false; 0199 } 0200 0201 if (kind != MimeTypeUtils::KIND_DIR && kind != MimeTypeUtils::KIND_ARCHIVE) { 0202 int dotPos = fileItem.name().lastIndexOf(QLatin1Char('.')); 0203 if (dotPos >= 1) { 0204 QString extension = fileItem.name().mid(dotPos + 1).toLower(); 0205 if (d->mBlackListedExtensions.contains(extension)) { 0206 return false; 0207 } 0208 } 0209 #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE 0210 if (!d->mSourceModel->semanticInfoAvailableForIndex(index)) { 0211 for (const AbstractSortedDirModelFilter *filter : qAsConst(d->mFilters)) { 0212 // Make sure we have semanticinfo, otherwise retrieve it and 0213 // return false, we will be called again later when it is 0214 // there. 0215 if (filter->needsSemanticInfo()) { 0216 d->mSourceModel->retrieveSemanticInfoForIndex(index); 0217 return false; 0218 } 0219 } 0220 } 0221 #endif 0222 0223 for (const AbstractSortedDirModelFilter *filter : qAsConst(d->mFilters)) { 0224 if (!filter->acceptsIndex(index)) { 0225 return false; 0226 } 0227 } 0228 } 0229 return KDirSortFilterProxyModel::filterAcceptsRow(row, parent); 0230 } 0231 0232 AbstractSemanticInfoBackEnd *SortedDirModel::semanticInfoBackEnd() const 0233 { 0234 #ifdef GWENVIEW_SEMANTICINFO_BACKEND_NONE 0235 return 0; 0236 #else 0237 return d->mSourceModel->semanticInfoBackEnd(); 0238 #endif 0239 } 0240 0241 #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE 0242 SemanticInfo SortedDirModel::semanticInfoForSourceIndex(const QModelIndex &sourceIndex) const 0243 { 0244 return d->mSourceModel->semanticInfoForIndex(sourceIndex); 0245 } 0246 #endif 0247 0248 void SortedDirModel::applyFilters() 0249 { 0250 d->mDelayedApplyFiltersTimer.start(); 0251 } 0252 0253 void SortedDirModel::doApplyFilters() 0254 { 0255 QSortFilterProxyModel::invalidateFilter(); 0256 } 0257 0258 bool SortedDirModel::lessThan(const QModelIndex &left, const QModelIndex &right) const 0259 { 0260 const KFileItem leftItem = itemForSourceIndex(left); 0261 const KFileItem rightItem = itemForSourceIndex(right); 0262 0263 const bool leftIsDirOrArchive = ArchiveUtils::fileItemIsDirOrArchive(leftItem); 0264 const bool rightIsDirOrArchive = ArchiveUtils::fileItemIsDirOrArchive(rightItem); 0265 0266 if (leftIsDirOrArchive != rightIsDirOrArchive) { 0267 return sortOrder() == Qt::AscendingOrder ? leftIsDirOrArchive : rightIsDirOrArchive; 0268 } 0269 0270 // Apply special sort handling only to images. For folders/archives or when 0271 // a secondary criterion is needed, delegate sorting to the parent class. 0272 if (!leftIsDirOrArchive) { 0273 if (sortColumn() == KDirModel::ModifiedTime) { 0274 const QDateTime leftDate = TimeUtils::dateTimeForFileItem(leftItem); 0275 const QDateTime rightDate = TimeUtils::dateTimeForFileItem(rightItem); 0276 0277 if (leftDate != rightDate) { 0278 return leftDate < rightDate; 0279 } 0280 } 0281 #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE 0282 if (sortRole() == SemanticInfoDirModel::RatingRole) { 0283 const int leftRating = d->mSourceModel->data(left, SemanticInfoDirModel::RatingRole).toInt(); 0284 const int rightRating = d->mSourceModel->data(right, SemanticInfoDirModel::RatingRole).toInt(); 0285 0286 if (leftRating != rightRating) { 0287 return leftRating < rightRating; 0288 } 0289 } 0290 #endif 0291 } 0292 0293 return KDirSortFilterProxyModel::lessThan(left, right); 0294 } 0295 0296 bool SortedDirModel::hasDocuments() const 0297 { 0298 const int count = rowCount(); 0299 if (count == 0) { 0300 return false; 0301 } 0302 for (int row = 0; row < count; ++row) { 0303 const QModelIndex idx = index(row, 0); 0304 const KFileItem item = itemForIndex(idx); 0305 if (!ArchiveUtils::fileItemIsDirOrArchive(item)) { 0306 return true; 0307 } 0308 } 0309 return false; 0310 } 0311 0312 void SortedDirModel::setDirLister(KDirLister *dirLister) 0313 { 0314 d->mSourceModel->setDirLister(dirLister); 0315 } 0316 0317 } // namespace 0318 0319 #include "moc_sorteddirmodel.cpp"