File indexing completed on 2024-03-24 04:51:47
0001 /* 0002 SPDX-FileCopyrightText: 2020 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr> 0003 0004 SPDX-License-Identifier: LGPL-3.0-or-later 0005 */ 0006 0007 #include "viewslistdata.h" 0008 0009 #include "modeldataloader.h" 0010 #include "databaseinterface.h" 0011 #include "musiclistenersmanager.h" 0012 0013 #include "viewsLogging.h" 0014 0015 #include <KLocalizedString> 0016 0017 #include <QUrl> 0018 #include <QDir> 0019 #include <QStandardPaths> 0020 0021 class ViewsListDataPrivate 0022 { 0023 public: 0024 QList<ViewParameters> mViewsParameters = {{{i18nc("@title:window Title of the view of the playlist", "Now Playing")}, 0025 QUrl{QStringLiteral("image://icon/view-media-lyrics")}, 0026 ViewManager::ContextView}, 0027 {{i18nc("@title:window Title of the view of recently played tracks", "Recently Played")}, 0028 QUrl{QStringLiteral("image://icon/media-playlist-play")}, 0029 ViewManager::ListView, 0030 ViewManager::GenericDataModel, 0031 ElisaUtils::FilterByRecentlyPlayed, 0032 ElisaUtils::Track, 0033 DataTypes::LastPlayDate, 0034 {DataTypes::LastPlayDate}, 0035 {i18nc("@title:menu", "Last Played Date")}, 0036 Qt::DescendingOrder, 0037 {i18nc("@item:inmenu", "Least Recently Played First"), i18nc("@item:inmenu", "Most Recently Played First")}, 0038 ViewManager::MultipleAlbum, 0039 ViewManager::NoDiscHeaders, 0040 ViewManager::IsTrack}, 0041 {{i18nc("@title:window Title of the view of frequently played tracks", "Frequently Played")}, 0042 QUrl{QStringLiteral("image://icon/view-media-playcount")}, 0043 ViewManager::ListView, 0044 ViewManager::GenericDataModel, 0045 ElisaUtils::FilterByFrequentlyPlayed, 0046 ElisaUtils::Track, 0047 DataTypes::PlayCounter, 0048 {DataTypes::PlayCounter}, 0049 {i18nc("@title:menu", "Play Frequency")}, 0050 Qt::DescendingOrder, 0051 {i18nc("@item:inmenu", "Least Frequently Played First"), i18nc("@item:inmenu", "Most Frequently Played First")}, 0052 ViewManager::MultipleAlbum, 0053 ViewManager::NoDiscHeaders, 0054 ViewManager::IsTrack}, 0055 {{i18nc("@title:window Title of the view of all albums", "Albums")}, 0056 QUrl{QStringLiteral("image://icon/view-media-album-cover")}, 0057 ViewManager::GridView, 0058 ViewManager::GenericDataModel, 0059 ElisaUtils::NoFilter, 0060 ElisaUtils::Album, 0061 DataTypes::TitleRole, 0062 {DataTypes::TitleRole, DataTypes::ArtistRole, DataTypes::GenreRole, DataTypes::YearRole}, 0063 {i18nc("@title:menu", "Title"), i18nc("@title:menu", "Artist"), i18nc("@title:menu", "Genre"), i18nc("@title:menu", "Year")}, 0064 Qt::AscendingOrder, 0065 {i18nc("@item:inmenu", "A-Z"), i18nc("@item:inmenu", "Z-A"), i18nc("@item:inmenu", "A-Z"), i18nc("@item:inmenu", "Z-A"), i18nc("@item:inmenu", "A-Z"), i18nc("@item:inmenu", "Z-A"), i18nc("@item:inmenu", "Oldest First"), i18nc("@item:inmenu", "Newest First")}, 0066 QUrl{QStringLiteral("image://icon/media-default-album")}, 0067 ViewManager::DelegateWithSecondaryText, 0068 ViewManager::ViewShowRating}, 0069 {{i18nc("@title:window Title of the view of all artists", "Artists")}, 0070 QUrl{QStringLiteral("image://icon/view-media-artist")}, 0071 ViewManager::GridView, 0072 ViewManager::GenericDataModel, 0073 ElisaUtils::NoFilter, 0074 ElisaUtils::Artist, 0075 Qt::DisplayRole, 0076 {Qt::DisplayRole}, 0077 {i18nc("@title:menu", "Name")}, 0078 Qt::AscendingOrder, 0079 {i18nc("@item:inmenu", "A-Z"), i18nc("@item:inmenu", "Z-A")}, 0080 QUrl{QStringLiteral("image://icon/view-media-artist")}, 0081 ViewManager::DelegateWithoutSecondaryText, 0082 ViewManager::ViewHideRating}, 0083 {{i18nc("@title:window Title of the view of all tracks", "Tracks")}, 0084 QUrl{QStringLiteral("image://icon/view-media-track")}, 0085 ViewManager::ListView, 0086 ViewManager::GenericDataModel, 0087 ElisaUtils::NoFilter, 0088 ElisaUtils::Track, 0089 DataTypes::TitleRole, 0090 {DataTypes::TitleRole, DataTypes::AlbumRole, DataTypes::ArtistRole, 0091 DataTypes::GenreRole, DataTypes::YearRole, DataTypes::DurationRole, 0092 DataTypes::ComposerRole, DataTypes::LyricistRole, 0093 DataTypes::FileModificationTime}, 0094 {i18nc("@title:menu", "Title"), i18nc("@title:menu", "Album"), i18nc("@title:menu", "Artist"), i18nc("@title:menu", "Genre"), 0095 i18nc("@title:menu", "Year"), i18nc("@title:menu", "Duration"), i18nc("@title:menu", "Composer"), i18nc("@title:menu", "Lyricist"), 0096 i18nc("@title:menu", "Last Modified")}, 0097 Qt::AscendingOrder, 0098 {i18nc("@item:inmenu", "A-Z"), i18nc("@item:inmenu", "Z-A"), i18nc("@item:inmenu", "A-Z"), i18nc("@item:inmenu", "Z-A"), i18nc("@item:inmenu", "A-Z"), i18nc("@item:inmenu", "Z-A"), i18nc("@item:inmenu", "A-Z"), i18nc("@item:inmenu", "Z-A"), 0099 i18nc("@item:inmenu", "Oldest First"), i18nc("@item:inmenu", "Newest First"), i18nc("@item:inmenu", "Shortest First"), i18nc("@item:inmenu", "Longest First"), i18nc("@item:inmenu", "A-Z"), i18nc("@item:inmenu", "Z-A"), i18nc("@item:inmenu", "A-Z"), i18nc("@item:inmenu", "Z-A"), 0100 i18nc("@item:inmenu", "Oldest First"), i18nc("@item:inmenu", "Newest First")}, 0101 ViewManager::MultipleAlbum, 0102 ViewManager::NoDiscHeaders, 0103 ViewManager::IsTrack}, 0104 {{i18nc("@title:window Title of the view of all genres", "Genres")}, 0105 QUrl{QStringLiteral("image://icon/view-media-genre")}, 0106 ViewManager::GridView, 0107 ViewManager::GenericDataModel, 0108 ElisaUtils::NoFilter, 0109 ElisaUtils::Genre, 0110 Qt::DisplayRole, 0111 {Qt::DisplayRole}, 0112 {i18nc("@title:menu", "Genre")}, 0113 Qt::AscendingOrder, 0114 {i18nc("@item:inmenu", "A-Z"), i18nc("@item:inmenu", "Z-A")}, 0115 QUrl{QStringLiteral("image://icon/view-media-genre")}, 0116 ViewManager::DelegateWithoutSecondaryText, 0117 ViewManager::ViewHideRating}, 0118 {{i18nc("@title:window Title of the file browser view", "Files")}, 0119 QUrl{QStringLiteral("image://icon/document-open-folder")}, 0120 ViewManager::GridView, 0121 ViewManager::FileBrowserModel, 0122 ElisaUtils::NoFilter, 0123 ElisaUtils::FileName, 0124 QUrl{QStringLiteral("image://icon/document-open-folder")}, 0125 ViewManager::DelegateWithoutSecondaryText, 0126 ViewManager::ViewHideRating, 0127 QUrl::fromLocalFile(QDir::rootPath()) 0128 }, 0129 {{i18nc("@title:window Title of the file radios browser view", "Radio Stations")}, 0130 QUrl{QStringLiteral("image://icon/radio")}, 0131 ViewManager::ListView, 0132 ViewManager::GenericDataModel, 0133 ElisaUtils::NoFilter, 0134 ElisaUtils::Radio, 0135 Qt::DisplayRole, 0136 {Qt::DisplayRole}, 0137 {i18nc("@title:menu", "Name")}, 0138 Qt::AscendingOrder, 0139 {i18nc("@item:inmenu", "A-Z"), i18nc("@item:inmenu", "Z-A")}, 0140 ViewManager::MultipleAlbum, 0141 ViewManager::NoDiscHeaders, 0142 ViewManager::IsRadio}}; 0143 0144 const int mNumOfBaseViews = mViewsParameters.count(); 0145 0146 QMap<ElisaUtils::PlayListEntryType, QUrl> mDefaultIcons = {{ElisaUtils::Album, QUrl{QStringLiteral("image://icon/view-media-album-cover")}}, 0147 {ElisaUtils::Artist, QUrl{QStringLiteral("image://icon/view-media-artist")}}, 0148 {ElisaUtils::Genre, QUrl{QStringLiteral("image://icon/view-media-genre")}},}; 0149 0150 ElisaUtils::PlayListEntryType mEmbeddedCategory = ElisaUtils::Unknown; 0151 0152 ModelDataLoader *mDataLoader = nullptr; 0153 0154 MusicListenersManager *mManager = nullptr; 0155 0156 DatabaseInterface *mDatabase = nullptr; 0157 }; 0158 0159 ViewsListData::ViewsListData(QObject *parent) 0160 : QObject(parent) 0161 , d(std::make_unique<ViewsListDataPrivate>()) 0162 { 0163 d->mDataLoader = new ModelDataLoader; 0164 connect(this, &ViewsListData::destroyed, d->mDataLoader, &ModelDataLoader::deleteLater); 0165 } 0166 0167 ViewsListData::~ViewsListData() = default; 0168 0169 int ViewsListData::count() const 0170 { 0171 return d->mViewsParameters.count(); 0172 } 0173 0174 bool ViewsListData::isEmpty() const 0175 { 0176 return d->mViewsParameters.isEmpty(); 0177 } 0178 0179 const ViewParameters &ViewsListData::viewParameters(int index) const 0180 { 0181 return d->mViewsParameters[index]; 0182 } 0183 0184 const QString &ViewsListData::title(int index) const 0185 { 0186 return d->mViewsParameters[index].mMainTitle; 0187 } 0188 0189 const QString &ViewsListData::secondTitle(int index) const 0190 { 0191 return d->mViewsParameters[index].mSecondaryTitle; 0192 } 0193 0194 bool ViewsListData::useSecondTitle(int index) const 0195 { 0196 return d->mViewsParameters[index].mUseSecondTitle; 0197 } 0198 0199 const QUrl &ViewsListData::iconUrl(int index) const 0200 { 0201 return d->mViewsParameters[index].mMainImage; 0202 } 0203 0204 qulonglong ViewsListData::databaseId(int index) const 0205 { 0206 return d->mViewsParameters[index].mDataFilter.databaseId(); 0207 } 0208 0209 bool ViewsListData::defaultEntry(int index) const 0210 { 0211 return d->mEmbeddedCategory == ElisaUtils::Unknown || d->mViewsParameters[index].mEntryType != d->mEmbeddedCategory; 0212 } 0213 0214 ElisaUtils::PlayListEntryType ViewsListData::dataType(int index) const 0215 { 0216 return d->mViewsParameters[index].mDataType; 0217 } 0218 0219 ElisaUtils::PlayListEntryType ViewsListData::embeddedCategory() const 0220 { 0221 return d->mEmbeddedCategory; 0222 } 0223 0224 void ViewsListData::setEmbeddedCategory(ElisaUtils::PlayListEntryType aEmbeddedView) 0225 { 0226 if (d->mEmbeddedCategory != aEmbeddedView) { 0227 d->mEmbeddedCategory = aEmbeddedView; 0228 0229 Q_EMIT embeddedCategoryChanged(); 0230 0231 refreshEmbeddedCategory(); 0232 } 0233 } 0234 0235 void ViewsListData::genresAdded(const DataTypes::ListGenreDataType &newData) 0236 { 0237 if (d->mEmbeddedCategory != ElisaUtils::Genre) { 0238 return; 0239 } 0240 0241 if (!newData.size()) { 0242 return; 0243 } 0244 0245 Q_EMIT dataAboutToBeAdded(d->mViewsParameters.size(), d->mViewsParameters.size() + newData.size() - 1); 0246 for (const auto &oneGenre : newData) { 0247 d->mViewsParameters.push_back({oneGenre.title(), 0248 QUrl{QStringLiteral("image://icon/view-media-genre")}, 0249 ViewManager::GridView, 0250 ViewManager::GenericDataModel, 0251 ElisaUtils::FilterByGenre, 0252 oneGenre.databaseId(), 0253 ElisaUtils::Artist, 0254 ElisaUtils::Genre, 0255 QUrl{QStringLiteral("image://icon/view-media-artist")}, 0256 ViewManager::DelegateWithoutSecondaryText, 0257 ViewManager::ViewHideRating}); 0258 } 0259 Q_EMIT dataAdded(); 0260 } 0261 0262 void ViewsListData::artistsAdded(const DataTypes::ListArtistDataType &newData) 0263 { 0264 if (d->mEmbeddedCategory != ElisaUtils::Artist) { 0265 return; 0266 } 0267 0268 if (!newData.size()) { 0269 return; 0270 } 0271 0272 Q_EMIT dataAboutToBeAdded(d->mViewsParameters.size(), d->mViewsParameters.size() + newData.size() - 1); 0273 for (const auto &oneArtist : newData) { 0274 d->mViewsParameters.push_back({oneArtist.name(), 0275 oneArtist.artistArtURI(), 0276 ViewManager::GridView, 0277 ViewManager::GenericDataModel, 0278 ElisaUtils::FilterByArtist, 0279 oneArtist.databaseId(), 0280 ElisaUtils::Album, 0281 ElisaUtils::Artist, 0282 QUrl{QStringLiteral("image://icon/media-default-album")}, 0283 ViewManager::DelegateWithSecondaryText, 0284 ViewManager::ViewShowRating}); 0285 } 0286 Q_EMIT dataAdded(); 0287 } 0288 0289 void ViewsListData::artistRemoved(qulonglong removedDatabaseId) 0290 { 0291 if (d->mEmbeddedCategory != ElisaUtils::Artist) { 0292 return; 0293 } 0294 0295 for (int i = 0; i < d->mViewsParameters.count(); ++i) { 0296 const auto &data = d->mViewsParameters[i]; 0297 0298 if (data.mDataFilter.databaseId() == removedDatabaseId) { 0299 Q_EMIT dataAboutToBeRemoved(i, i); 0300 d->mViewsParameters.removeAt(i); 0301 Q_EMIT dataRemoved(); 0302 break; 0303 } 0304 } 0305 } 0306 0307 void ViewsListData::albumsAdded(const DataTypes::ListAlbumDataType &newData) 0308 { 0309 if (d->mEmbeddedCategory != ElisaUtils::Album) { 0310 return; 0311 } 0312 0313 if (!newData.size()) { 0314 return; 0315 } 0316 0317 Q_EMIT dataAboutToBeAdded(d->mViewsParameters.size(), d->mViewsParameters.size() + newData.size() - 1); 0318 for (const auto &oneAlbum : newData) { 0319 auto coverImage = oneAlbum.albumArtURI(); 0320 if (!coverImage.isValid()) { 0321 coverImage = d->mDefaultIcons[d->mEmbeddedCategory]; 0322 } 0323 0324 d->mViewsParameters.push_back({oneAlbum.title(), 0325 coverImage, 0326 ViewManager::ListView, 0327 ViewManager::GenericDataModel, 0328 ElisaUtils::FilterById, 0329 oneAlbum.databaseId(), 0330 ElisaUtils::Track, 0331 ElisaUtils::Album, 0332 Qt::DisplayRole, 0333 {Qt::DisplayRole}, 0334 {QStringLiteral("Title")}, 0335 Qt::AscendingOrder, 0336 {QStringLiteral("A-Z"), QStringLiteral("Z-A")}, 0337 ViewManager::SingleAlbum, 0338 ViewManager::DiscHeaders, 0339 ViewManager::IsTrack}); 0340 } 0341 Q_EMIT dataAdded(); 0342 } 0343 0344 void ViewsListData::albumRemoved(qulonglong removedDatabaseId) 0345 { 0346 if (d->mEmbeddedCategory != ElisaUtils::Album) { 0347 return; 0348 } 0349 0350 for (int i = 0; i < d->mViewsParameters.count(); ++i) { 0351 const auto &data = d->mViewsParameters[i]; 0352 0353 if (data.mDataFilter.databaseId() == removedDatabaseId) { 0354 Q_EMIT dataAboutToBeRemoved(i, i); 0355 d->mViewsParameters.removeAt(i); 0356 Q_EMIT dataRemoved(); 0357 break; 0358 } 0359 } 0360 } 0361 0362 void ViewsListData::albumModified(const DataTypes::AlbumDataType &modifiedAlbum) 0363 { 0364 if (d->mEmbeddedCategory != ElisaUtils::Album) { 0365 return; 0366 } 0367 0368 for (int i = 0; i < d->mViewsParameters.count(); ++i) { 0369 auto &data = d->mViewsParameters[i]; 0370 if (data.mDataFilter.databaseId() == modifiedAlbum.databaseId()) { 0371 data.mMainTitle = modifiedAlbum.title(); 0372 if (modifiedAlbum.albumArtURI().isValid()) { 0373 data.mMainImage = modifiedAlbum.albumArtURI(); 0374 } else { 0375 data.mMainImage = d->mDefaultIcons[d->mEmbeddedCategory]; 0376 } 0377 data.mSecondaryTitle = modifiedAlbum.artist(); 0378 0379 Q_EMIT dataModified(i); 0380 0381 break; 0382 } 0383 } 0384 } 0385 0386 void ViewsListData::clearEmbeddedItems() 0387 { 0388 if (d->mViewsParameters.count() > d->mNumOfBaseViews) { 0389 const int startIndex = d->mNumOfBaseViews; 0390 const int numToRemove = d->mViewsParameters.count() - startIndex; 0391 Q_EMIT dataAboutToBeRemoved(startIndex, d->mViewsParameters.count() - 1); 0392 d->mViewsParameters.remove(startIndex, numToRemove); 0393 Q_EMIT dataRemoved(); 0394 } 0395 } 0396 0397 void ViewsListData::cleanedDatabase() 0398 { 0399 qCDebug(orgKdeElisaViews) << "ViewsListData::cleanedDatabase" << d->mEmbeddedCategory; 0400 clearEmbeddedItems(); 0401 } 0402 0403 void ViewsListData::refreshEmbeddedCategory() 0404 { 0405 clearEmbeddedItems(); 0406 0407 switch (d->mEmbeddedCategory) 0408 { 0409 case ElisaUtils::Album: 0410 case ElisaUtils::Artist: 0411 case ElisaUtils::Genre: 0412 Q_EMIT needData(d->mEmbeddedCategory); 0413 break; 0414 case ElisaUtils::Radio: 0415 case ElisaUtils::Track: 0416 case ElisaUtils::Unknown: 0417 case ElisaUtils::Composer: 0418 case ElisaUtils::FileName: 0419 case ElisaUtils::Lyricist: 0420 case ElisaUtils::Container: 0421 case ElisaUtils::PlayList: 0422 break; 0423 } 0424 } 0425 0426 MusicListenersManager* ViewsListData::manager() const 0427 { 0428 return d->mManager; 0429 } 0430 0431 void ViewsListData::setManager(MusicListenersManager *aManager) 0432 { 0433 if (d->mManager != aManager) { 0434 d->mManager = aManager; 0435 Q_EMIT managerChanged(); 0436 d->mManager->connectModel(d->mDataLoader); 0437 setDatabase(d->mManager->viewDatabase()); 0438 } 0439 } 0440 0441 DatabaseInterface* ViewsListData::database() const 0442 { 0443 return d->mDatabase; 0444 } 0445 0446 void ViewsListData::setDatabase(DatabaseInterface *aDatabase) 0447 { 0448 if (d->mDatabase != aDatabase) { 0449 d->mDatabase = aDatabase; 0450 Q_EMIT databaseChanged(); 0451 0452 d->mDataLoader->setDatabase(aDatabase); 0453 0454 connect(d->mDataLoader, &ModelDataLoader::allAlbumsData, 0455 this, &ViewsListData::albumsAdded); 0456 connect(d->mDataLoader, &ModelDataLoader::allArtistsData, 0457 this, &ViewsListData::artistsAdded); 0458 connect(d->mDataLoader, &ModelDataLoader::allGenresData, 0459 this, &ViewsListData::genresAdded); 0460 connect(d->mDatabase, &DatabaseInterface::genresAdded, 0461 this, &ViewsListData::genresAdded); 0462 connect(d->mDatabase, &DatabaseInterface::artistsAdded, 0463 this, &ViewsListData::artistsAdded); 0464 connect(d->mDatabase, &DatabaseInterface::artistRemoved, 0465 this, &ViewsListData::artistRemoved); 0466 connect(d->mDatabase, &DatabaseInterface::albumsAdded, 0467 this, &ViewsListData::albumsAdded); 0468 connect(d->mDatabase, &DatabaseInterface::albumRemoved, 0469 this, &ViewsListData::albumRemoved); 0470 connect(d->mDatabase, &DatabaseInterface::albumModified, 0471 this, &ViewsListData::albumModified); 0472 connect(d->mDatabase, &DatabaseInterface::cleanedDatabase, 0473 this, &ViewsListData::cleanedDatabase); 0474 0475 connect(this, &ViewsListData::needData, 0476 d->mDataLoader, &ModelDataLoader::loadData); 0477 0478 refreshEmbeddedCategory(); 0479 } 0480 } 0481 0482 0483 #include "moc_viewslistdata.cpp"