File indexing completed on 2024-05-05 04:50:34
0001 /* 0002 SPDX-FileCopyrightText: 2016 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr> 0003 SPDX-FileCopyrightText: 2018 (c) Alexander Stippich <a.stippich@gmx.net> 0004 0005 SPDX-License-Identifier: LGPL-3.0-or-later 0006 */ 0007 0008 #include "filebrowserproxymodel.h" 0009 0010 #include "filebrowsermodel.h" 0011 #include "mediaplaylistproxymodel.h" 0012 0013 #include "models/modelLogging.h" 0014 0015 #include <stack> 0016 0017 FileBrowserProxyModel::FileBrowserProxyModel(QObject *parent) 0018 : KDirSortFilterProxyModel(parent) 0019 { 0020 setFilterCaseSensitivity(Qt::CaseInsensitive); 0021 setSortFoldersFirst(true); 0022 sort(Qt::AscendingOrder); 0023 } 0024 0025 FileBrowserProxyModel::~FileBrowserProxyModel() = default; 0026 0027 QString FileBrowserProxyModel::filterText() const 0028 { 0029 return mFilterText; 0030 } 0031 0032 void FileBrowserProxyModel::setFilterText(const QString &filterText) 0033 { 0034 if (mFilterText == filterText) 0035 return; 0036 0037 mFilterText = filterText; 0038 0039 mFilterExpression.setPattern(mFilterText.normalized(QString::NormalizationForm_KC)); 0040 mFilterExpression.setPatternOptions(QRegularExpression::CaseInsensitiveOption); 0041 mFilterExpression.optimize(); 0042 0043 setFilterRegularExpression(mFilterExpression); 0044 setFilterRole(Qt::DisplayRole); 0045 0046 Q_EMIT filterTextChanged(mFilterText); 0047 } 0048 0049 void FileBrowserProxyModel::listRecursiveResult(KJob *) 0050 { 0051 if (mPendingEntries.empty()) { 0052 mEnqueueInProgress = false; 0053 Q_EMIT entriesToEnqueue(mAllData, mEnqueueMode, mTriggerPlay); 0054 return; 0055 } 0056 0057 recursiveEnqueue(); 0058 } 0059 0060 void FileBrowserProxyModel::listRecursiveNewEntries(KIO::Job *job, const KIO::UDSEntryList &list) 0061 { 0062 Q_UNUSED(job) 0063 0064 DataTypes::EntryDataList newData; 0065 0066 auto vNewEntries = QVector<QString>{}; 0067 0068 vNewEntries.reserve(list.size()); 0069 0070 for (const auto &oneEntry : list) { 0071 if (oneEntry.isDir()) { 0072 continue; 0073 } 0074 0075 vNewEntries.push_back(oneEntry.stringValue(KIO::UDSEntry::UDS_NAME)); 0076 } 0077 0078 std::sort(std::begin(vNewEntries), std::end(vNewEntries), [this](auto first, auto second) { 0079 return (sortOrder() == Qt::AscendingOrder) ? (first < second) : (first > second); 0080 }); 0081 0082 for (const auto &oneEntry : vNewEntries) { 0083 auto fullPath = QString{}; 0084 auto fullPathUrl = QUrl{}; 0085 0086 if (mCurentUrl.isLocalFile()) { 0087 fullPath = QStringLiteral("%0/%1").arg(mCurentUrl.toLocalFile(), oneEntry); 0088 fullPathUrl = QUrl::fromLocalFile(fullPath); 0089 } else { 0090 fullPath = QStringLiteral("%0/%1").arg(mCurentUrl.toString(), oneEntry); 0091 fullPathUrl = QUrl{fullPath}; 0092 } 0093 0094 auto mimeType = mMimeDatabase.mimeTypeForUrl(fullPathUrl); 0095 0096 if (!mimeType.name().startsWith(QLatin1String("audio/")) || ElisaUtils::isPlayList(mimeType)) { 0097 continue; 0098 } 0099 0100 newData.push_back({{{DataTypes::ElementTypeRole, ElisaUtils::FileName}, {DataTypes::ResourceRole, fullPathUrl}}, fullPath, {}}); 0101 } 0102 0103 mAllData.append(newData); 0104 } 0105 0106 void FileBrowserProxyModel::genericEnqueueToPlayList(const QModelIndex &rootIndex, 0107 ElisaUtils::PlayListEnqueueMode enqueueMode, 0108 ElisaUtils::PlayListEnqueueTriggerPlay triggerPlay) 0109 { 0110 if (mEnqueueInProgress) { 0111 // display error 0112 return; 0113 } 0114 0115 mPendingEntries = {}; 0116 mAllData.clear(); 0117 0118 for (int rowIndex = 0, maxRowCount = rowCount(); rowIndex < maxRowCount; ++rowIndex) { 0119 auto currentIndex = index(rowIndex, 0, rootIndex); 0120 mPendingEntries.emplace(currentIndex.data(DataTypes::FilePathRole).toUrl(), 0121 currentIndex.data(DataTypes::ElementTypeRole).value<ElisaUtils::PlayListEntryType>() == ElisaUtils::Container); 0122 } 0123 0124 mEnqueueInProgress = true; 0125 mEnqueueMode = enqueueMode; 0126 mTriggerPlay = triggerPlay; 0127 recursiveEnqueue(); 0128 } 0129 0130 void FileBrowserProxyModel::enqueueToPlayList(const QModelIndex &rootIndex) 0131 { 0132 genericEnqueueToPlayList(rootIndex, 0133 ElisaUtils::AppendPlayList, 0134 ElisaUtils::DoNotTriggerPlay); 0135 } 0136 0137 void FileBrowserProxyModel::enqueue(const DataTypes::MusicDataType &newEntry, 0138 const QString &newEntryTitle, 0139 ElisaUtils::PlayListEnqueueMode enqueueMode, 0140 ElisaUtils::PlayListEnqueueTriggerPlay triggerPlay) 0141 { 0142 Q_UNUSED(newEntryTitle) 0143 0144 if (mEnqueueInProgress) { 0145 // display error 0146 return; 0147 } 0148 0149 mPendingEntries = {}; 0150 mAllData.clear(); 0151 0152 switch (newEntry.elementType()) 0153 { 0154 case ElisaUtils::Container: 0155 mPendingEntries.emplace(newEntry[DataTypes::FilePathRole].toUrl(), true); 0156 break; 0157 case ElisaUtils::FileName: 0158 case ElisaUtils::Track: 0159 mPendingEntries.emplace(newEntry[DataTypes::ResourceRole].toUrl(), false); 0160 break; 0161 case ElisaUtils::PlayList: 0162 if (mPlayList) { 0163 QMetaObject::invokeMethod(mPlayList, 0164 "loadPlayList", 0165 Q_ARG(QUrl, newEntry[DataTypes::ResourceRole].toUrl()), 0166 Q_ARG(ElisaUtils::PlayListEnqueueMode, enqueueMode), 0167 Q_ARG(ElisaUtils::PlayListEnqueueTriggerPlay, triggerPlay)); 0168 } 0169 return; 0170 case ElisaUtils::Album: 0171 case ElisaUtils::Artist: 0172 case ElisaUtils::Composer: 0173 case ElisaUtils::Genre: 0174 case ElisaUtils::Lyricist: 0175 case ElisaUtils::Radio: 0176 case ElisaUtils::Unknown: 0177 break; 0178 } 0179 0180 if (mPendingEntries.empty()) { 0181 return; 0182 } 0183 0184 mEnqueueInProgress = true; 0185 mEnqueueMode = enqueueMode; 0186 mTriggerPlay = triggerPlay; 0187 recursiveEnqueue(); 0188 } 0189 0190 void FileBrowserProxyModel::replaceAndPlayOfPlayList(const QModelIndex &rootIndex) 0191 { 0192 genericEnqueueToPlayList(rootIndex, 0193 ElisaUtils::ReplacePlayList, 0194 ElisaUtils::TriggerPlay); 0195 } 0196 0197 void FileBrowserProxyModel::disconnectPlayList() 0198 { 0199 if (mPlayList) { 0200 disconnect(this, &FileBrowserProxyModel::entriesToEnqueue, 0201 mPlayList, static_cast<void (MediaPlayListProxyModel::*)(const DataTypes::EntryDataList &, ElisaUtils::PlayListEnqueueMode, ElisaUtils::PlayListEnqueueTriggerPlay)>(&MediaPlayListProxyModel::enqueue)); 0202 } 0203 } 0204 0205 void FileBrowserProxyModel::connectPlayList() 0206 { 0207 if (mPlayList) { 0208 connect(this, &FileBrowserProxyModel::entriesToEnqueue, 0209 mPlayList, static_cast<void (MediaPlayListProxyModel::*)(const DataTypes::EntryDataList &, ElisaUtils::PlayListEnqueueMode, ElisaUtils::PlayListEnqueueTriggerPlay)>(&MediaPlayListProxyModel::enqueue)); 0210 } 0211 } 0212 0213 void FileBrowserProxyModel::recursiveEnqueue() 0214 { 0215 auto [rootUrl, isDirectory] = mPendingEntries.front(); 0216 0217 if (rootUrl.isEmpty()) { 0218 return; 0219 } 0220 0221 mPendingEntries.pop(); 0222 if (isDirectory) { 0223 mCurentUrl = rootUrl; 0224 mCurrentJob = KIO::listRecursive(rootUrl, { KIO::HideProgressInfo }); 0225 0226 connect(mCurrentJob, &KJob::result, this, &FileBrowserProxyModel::listRecursiveResult); 0227 0228 connect(dynamic_cast<KIO::ListJob*>(mCurrentJob), &KIO::ListJob::entries, 0229 this, &FileBrowserProxyModel::listRecursiveNewEntries); 0230 } else { 0231 if (mPlayList) { 0232 if (!ElisaUtils::isPlayList(mMimeDatabase.mimeTypeForUrl(rootUrl))) { 0233 mAllData.push_back({{{DataTypes::ElementTypeRole, ElisaUtils::FileName}, {DataTypes::ResourceRole, rootUrl}}, rootUrl.toString(), rootUrl}); 0234 } 0235 0236 if (mPendingEntries.empty()) { 0237 mEnqueueInProgress = false; 0238 Q_EMIT entriesToEnqueue(mAllData, mEnqueueMode, mTriggerPlay); 0239 return; 0240 } 0241 0242 recursiveEnqueue(); 0243 } 0244 } 0245 } 0246 0247 void FileBrowserProxyModel::setSourceModel(QAbstractItemModel *sourceModel) 0248 { 0249 KDirSortFilterProxyModel::setSourceModel(sourceModel); 0250 0251 auto fileBrowserModel = dynamic_cast<FileBrowserModel *>(sourceModel); 0252 0253 if (!fileBrowserModel) { 0254 return; 0255 } 0256 } 0257 0258 MediaPlayListProxyModel *FileBrowserProxyModel::playList() const 0259 { 0260 return mPlayList; 0261 } 0262 0263 int FileBrowserProxyModel::filterRating() const 0264 { 0265 return mFilterRating; 0266 } 0267 0268 bool FileBrowserProxyModel::sortedAscending() const 0269 { 0270 return sortOrder() ? false : true; 0271 } 0272 0273 void FileBrowserProxyModel::sortModel(Qt::SortOrder order) 0274 { 0275 sort(0, order); 0276 Q_EMIT sortedAscendingChanged(); 0277 } 0278 0279 void FileBrowserProxyModel::setPlayList(MediaPlayListProxyModel *playList) 0280 { 0281 disconnectPlayList(); 0282 0283 if (mPlayList == playList) { 0284 return; 0285 } 0286 0287 mPlayList = playList; 0288 Q_EMIT playListChanged(); 0289 0290 connectPlayList(); 0291 } 0292 0293 void FileBrowserProxyModel::setFilterRating(int filterRating) 0294 { 0295 if (mFilterRating == filterRating) { 0296 return; 0297 } 0298 0299 mFilterRating = filterRating; 0300 Q_EMIT filterRatingChanged(); 0301 } 0302 0303 #include "moc_filebrowserproxymodel.cpp"