File indexing completed on 2024-04-28 04:18:52
0001 // vim: set tabstop=4 shiftwidth=4 expandtab: 0002 /* 0003 Gwenview: an image viewer 0004 Copyright 2012 Aurélien Gâteau <agateau@kde.org> 0005 0006 This program is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU General Public License 0008 as published by the Free Software Foundation; either version 2 0009 of the License, or (at your option) any later version. 0010 0011 This program is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 GNU General Public License for more details. 0015 0016 You should have received a copy of the GNU General Public License 0017 along with this program; if not, write to the Free Software 0018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. 0019 0020 */ 0021 // Self 0022 #include "recursivedirmodel.h" 0023 0024 // Local 0025 #include "gwenview_lib_debug.h" 0026 #include <lib/gvdebug.h> 0027 0028 // KF 0029 #include <KDirLister> 0030 #include <KDirModel> 0031 0032 // Qt 0033 0034 namespace Gwenview 0035 { 0036 struct RecursiveDirModelPrivate { 0037 KDirLister *mDirLister = nullptr; 0038 0039 int rowForUrl(const QUrl &url) const 0040 { 0041 return mRowForUrl.value(url, -1); 0042 } 0043 0044 void removeAt(int row) 0045 { 0046 KFileItem item = mList.takeAt(row); 0047 mRowForUrl.remove(item.url()); 0048 0049 // Decrease row value for all urls after the one we removed 0050 // ("row" now points to the item after the one we removed since we used takeAt) 0051 const int count = mList.count(); 0052 for (; row < count; ++row) { 0053 QUrl url = mList.at(row).url(); 0054 mRowForUrl[url]--; 0055 } 0056 } 0057 0058 void addItem(const KFileItem &item) 0059 { 0060 mRowForUrl.insert(item.url(), mList.count()); 0061 mList.append(item); 0062 } 0063 0064 void clear() 0065 { 0066 mRowForUrl.clear(); 0067 mList.clear(); 0068 } 0069 0070 // RecursiveDirModel can only access mList through this read-only getter. 0071 // This ensures it cannot introduce inconsistencies between mList and mRowForUrl. 0072 const KFileItemList &list() const 0073 { 0074 return mList; 0075 } 0076 0077 private: 0078 KFileItemList mList; 0079 QHash<QUrl, int> mRowForUrl; 0080 }; 0081 0082 RecursiveDirModel::RecursiveDirModel(QObject *parent) 0083 : QAbstractListModel(parent) 0084 , d(new RecursiveDirModelPrivate) 0085 { 0086 d->mDirLister = new KDirLister(this); 0087 connect(d->mDirLister, &KDirLister::itemsAdded, this, &RecursiveDirModel::slotItemsAdded); 0088 connect(d->mDirLister, &KDirLister::itemsDeleted, this, &RecursiveDirModel::slotItemsDeleted); 0089 connect(d->mDirLister, QOverload<>::of(&KDirLister::completed), this, &RecursiveDirModel::completed); 0090 connect(d->mDirLister, QOverload<>::of(&KDirLister::clear), this, &RecursiveDirModel::slotCleared); 0091 0092 connect(d->mDirLister, &KDirLister::clearDir, this, &RecursiveDirModel::slotDirCleared); 0093 } 0094 0095 RecursiveDirModel::~RecursiveDirModel() 0096 { 0097 delete d; 0098 } 0099 0100 QUrl RecursiveDirModel::url() const 0101 { 0102 return d->mDirLister->url(); 0103 } 0104 0105 void RecursiveDirModel::setUrl(const QUrl &url) 0106 { 0107 beginResetModel(); 0108 d->clear(); 0109 endResetModel(); 0110 d->mDirLister->openUrl(url); 0111 } 0112 0113 int RecursiveDirModel::rowCount(const QModelIndex &parent) const 0114 { 0115 if (parent.isValid()) { 0116 return 0; 0117 } else { 0118 return d->list().count(); 0119 } 0120 } 0121 0122 QVariant RecursiveDirModel::data(const QModelIndex &index, int role) const 0123 { 0124 if (index.parent().isValid()) { 0125 return {}; 0126 } 0127 KFileItem item = d->list().value(index.row()); 0128 if (item.isNull()) { 0129 qCWarning(GWENVIEW_LIB_LOG) << "Invalid row" << index.row(); 0130 return {}; 0131 } 0132 switch (role) { 0133 case Qt::DisplayRole: 0134 return item.text(); 0135 case Qt::DecorationRole: 0136 return item.iconName(); 0137 case KDirModel::FileItemRole: 0138 return QVariant(item); 0139 default: 0140 qCWarning(GWENVIEW_LIB_LOG) << "Unhandled role" << role; 0141 break; 0142 } 0143 return {}; 0144 } 0145 0146 void RecursiveDirModel::slotItemsAdded(const QUrl &, const KFileItemList &newList) 0147 { 0148 QList<QUrl> dirUrls; 0149 KFileItemList fileList; 0150 for (const KFileItem &item : newList) { 0151 if (item.isFile()) { 0152 if (d->rowForUrl(item.url()) == -1) { 0153 fileList << item; 0154 } 0155 } else { 0156 dirUrls << item.url(); 0157 } 0158 } 0159 0160 if (!fileList.isEmpty()) { 0161 beginInsertRows(QModelIndex(), d->list().count(), d->list().count() + fileList.count()); 0162 for (const KFileItem &item : qAsConst(fileList)) { 0163 d->addItem(item); 0164 } 0165 endInsertRows(); 0166 } 0167 0168 for (const QUrl &url : qAsConst(dirUrls)) { 0169 d->mDirLister->openUrl(url, KDirLister::Keep); 0170 } 0171 } 0172 0173 void RecursiveDirModel::slotItemsDeleted(const KFileItemList &list) 0174 { 0175 for (const KFileItem &item : list) { 0176 if (item.isDir()) { 0177 continue; 0178 } 0179 int row = d->rowForUrl(item.url()); 0180 if (row == -1) { 0181 qCWarning(GWENVIEW_LIB_LOG) << "Received itemsDeleted for an unknown item: this should not happen!"; 0182 GV_FATAL_FAILS; 0183 continue; 0184 } 0185 beginRemoveRows(QModelIndex(), row, row); 0186 d->removeAt(row); 0187 endRemoveRows(); 0188 } 0189 } 0190 0191 void RecursiveDirModel::slotCleared() 0192 { 0193 if (d->list().isEmpty()) { 0194 return; 0195 } 0196 beginResetModel(); 0197 d->clear(); 0198 endResetModel(); 0199 } 0200 0201 void RecursiveDirModel::slotDirCleared(const QUrl &dirUrl) 0202 { 0203 int row; 0204 for (row = d->list().count() - 1; row >= 0; --row) { 0205 const QUrl url = d->list().at(row).url(); 0206 if (dirUrl.isParentOf(url)) { 0207 beginRemoveRows(QModelIndex(), row, row); 0208 d->removeAt(row); 0209 endRemoveRows(); 0210 } 0211 } 0212 } 0213 0214 } // namespace 0215 0216 #include "moc_recursivedirmodel.cpp"