File indexing completed on 2024-04-28 08:41:12

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"