File indexing completed on 2024-05-05 04:50:33

0001 /*
0002    SPDX-FileCopyrightText: 2015 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
0003 
0004    SPDX-License-Identifier: LGPL-3.0-or-later
0005  */
0006 
0007 #include "datamodel.h"
0008 
0009 #include "modeldataloader.h"
0010 #include "musiclistenersmanager.h"
0011 
0012 #include "models/modelLogging.h"
0013 
0014 #include <algorithm>
0015 
0016 class DataModelPrivate
0017 {
0018 public:
0019 
0020     DataModel::ListTrackDataType mAllTrackData;
0021 
0022     DataModel::ListRadioDataType mAllRadiosData;
0023 
0024     DataModel::ListAlbumDataType mAllAlbumData;
0025 
0026     DataModel::ListArtistDataType mAllArtistData;
0027 
0028     DataModel::ListGenreDataType mAllGenreData;
0029 
0030     ModelDataLoader *mDataLoader = nullptr;
0031 
0032     ElisaUtils::PlayListEntryType mModelType = ElisaUtils::Unknown;
0033 
0034     ElisaUtils::FilterType mFilterType = ElisaUtils::UnknownFilter;
0035 
0036     QString mArtist;
0037 
0038     QString mAlbumTitle;
0039 
0040     QString mAlbumArtist;
0041 
0042     QString mGenre;
0043 
0044     qulonglong mDatabaseId = 0;
0045 
0046     bool mIsBusy = false;
0047 
0048 };
0049 
0050 DataModel::DataModel(QObject *parent) : QAbstractListModel(parent), d(std::make_unique<DataModelPrivate>())
0051 {
0052     d->mDataLoader = new ModelDataLoader;
0053     connect(this, &DataModel::destroyed, d->mDataLoader, &ModelDataLoader::deleteLater);
0054 }
0055 
0056 DataModel::~DataModel()
0057 = default;
0058 
0059 int DataModel::rowCount(const QModelIndex &parent) const
0060 {
0061     auto dataCount = 0;
0062 
0063     if (parent.isValid()) {
0064         return dataCount;
0065     }
0066 
0067     dataCount = d->mAllTrackData.size() + d->mAllAlbumData.size() + d->mAllArtistData.size() + d->mAllGenreData.size();
0068 
0069     return dataCount;
0070 }
0071 
0072 QHash<int, QByteArray> DataModel::roleNames() const
0073 {
0074     auto roles = QAbstractListModel::roleNames();
0075 
0076     roles[static_cast<int>(DataTypes::ColumnsRoles::TitleRole)] = "title";
0077     roles[static_cast<int>(DataTypes::ColumnsRoles::SecondaryTextRole)] = "secondaryText";
0078     roles[static_cast<int>(DataTypes::ColumnsRoles::ImageUrlRole)] = "imageUrl";
0079     roles[static_cast<int>(DataTypes::ColumnsRoles::MultipleImageUrlsRole)] = "multipleImageUrls";
0080     roles[static_cast<int>(DataTypes::ColumnsRoles::DatabaseIdRole)] = "databaseId";
0081     roles[static_cast<int>(DataTypes::ColumnsRoles::ElementTypeRole)] = "dataType";
0082     roles[static_cast<int>(DataTypes::ColumnsRoles::ResourceRole)] = "url";
0083 
0084     roles[static_cast<int>(DataTypes::ColumnsRoles::ArtistRole)] = "artist";
0085     roles[static_cast<int>(DataTypes::ColumnsRoles::AllArtistsRole)] = "allArtists";
0086     roles[static_cast<int>(DataTypes::ColumnsRoles::HighestTrackRating)] = "highestTrackRating";
0087     roles[static_cast<int>(DataTypes::ColumnsRoles::GenreRole)] = "genre";
0088 
0089     roles[static_cast<int>(DataTypes::ColumnsRoles::AlbumRole)] = "album";
0090     roles[static_cast<int>(DataTypes::ColumnsRoles::AlbumArtistRole)] = "albumArtist";
0091     roles[static_cast<int>(DataTypes::ColumnsRoles::StringDurationRole)] = "duration";
0092     roles[static_cast<int>(DataTypes::ColumnsRoles::TrackNumberRole)] = "trackNumber";
0093     roles[static_cast<int>(DataTypes::ColumnsRoles::DiscNumberRole)] = "discNumber";
0094     roles[static_cast<int>(DataTypes::ColumnsRoles::RatingRole)] = "rating";
0095     roles[static_cast<int>(DataTypes::ColumnsRoles::YearRole)] = "year";
0096     roles[static_cast<int>(DataTypes::ColumnsRoles::IsSingleDiscAlbumRole)] = "isSingleDiscAlbum";
0097     roles[static_cast<int>(DataTypes::ColumnsRoles::FullDataRole)] = "fullData";
0098     roles[static_cast<int>(DataTypes::ColumnsRoles::HasChildrenRole)] = "hasChildren";
0099 
0100     return roles;
0101 }
0102 
0103 Qt::ItemFlags DataModel::flags(const QModelIndex &index) const
0104 {
0105     if (!index.isValid()) {
0106         return Qt::NoItemFlags;
0107     }
0108 
0109     return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
0110 }
0111 
0112 QVariant DataModel::data(const QModelIndex &index, int role) const
0113 {
0114     auto result = QVariant();
0115 
0116     if (!index.isValid()) {
0117         return result;
0118     }
0119 
0120     const auto dataCount = d->mModelType == ElisaUtils::Radio ? d->mAllRadiosData.size() : d->mAllTrackData.size() + d->mAllAlbumData.size() + d->mAllArtistData.size() + d->mAllGenreData.size();
0121 
0122     Q_ASSERT(index.isValid());
0123     Q_ASSERT(index.column() == 0);
0124     Q_ASSERT(!index.parent().isValid());
0125     Q_ASSERT(index.model() == this);
0126     Q_ASSERT(index.internalId() == 0);
0127     Q_ASSERT(index.row() >= 0 && index.row() < dataCount);
0128 
0129     switch(role)
0130     {
0131     case Qt::DisplayRole:
0132         switch(d->mModelType)
0133         {
0134         case ElisaUtils::Track:
0135             result = d->mAllTrackData[index.row()][TrackDataType::key_type::TitleRole];
0136             if (result.toString().isEmpty()) {
0137                 result = d->mAllTrackData[index.row()][TrackDataType::key_type::ResourceRole].toUrl().fileName();
0138             }
0139             break;
0140         case ElisaUtils::Album:
0141             result = d->mAllAlbumData[index.row()][AlbumDataType::key_type::TitleRole];
0142             break;
0143         case ElisaUtils::Artist:
0144             result = d->mAllArtistData[index.row()][ArtistDataType::key_type::TitleRole];
0145             break;
0146         case ElisaUtils::Genre:
0147             result = d->mAllGenreData[index.row()][GenreDataType::key_type::TitleRole];
0148             break;
0149         case ElisaUtils::Radio:
0150             result = d->mAllRadiosData[index.row()][GenreDataType::key_type::TitleRole];
0151             break;
0152         case ElisaUtils::Lyricist:
0153         case ElisaUtils::Composer:
0154         case ElisaUtils::FileName:
0155         case ElisaUtils::Container:
0156         case ElisaUtils::Unknown:
0157         case ElisaUtils::PlayList:
0158             break;
0159         }
0160         break;
0161     case DataTypes::ColumnsRoles::StringDurationRole:
0162     {
0163         switch (d->mModelType)
0164         {
0165         case ElisaUtils::Track:
0166         {
0167             auto trackDuration = d->mAllTrackData[index.row()][TrackDataType::key_type::DurationRole].toTime();
0168             if (trackDuration.hour() == 0) {
0169                 result = trackDuration.toString(QStringLiteral("mm:ss"));
0170             } else {
0171                 result = trackDuration.toString();
0172             }
0173             break;
0174         }
0175         case ElisaUtils::Album:
0176         case ElisaUtils::Artist:
0177         case ElisaUtils::Genre:
0178         case ElisaUtils::Lyricist:
0179         case ElisaUtils::Composer:
0180         case ElisaUtils::FileName:
0181         case ElisaUtils::Radio:
0182         case ElisaUtils::Container:
0183         case ElisaUtils::Unknown:
0184         case ElisaUtils::PlayList:
0185             break;
0186         }
0187         break;
0188     }
0189     case DataTypes::ColumnsRoles::IsSingleDiscAlbumRole:
0190     {
0191         switch (d->mModelType)
0192         {
0193         case ElisaUtils::Track:
0194             result = d->mAllTrackData[index.row()][TrackDataType::key_type::IsSingleDiscAlbumRole];
0195             break;
0196         case ElisaUtils::Radio:
0197             result = false;
0198             break;
0199         case ElisaUtils::Album:
0200             result = d->mAllAlbumData[index.row()][AlbumDataType::key_type::IsSingleDiscAlbumRole];
0201             break;
0202         case ElisaUtils::Artist:
0203         case ElisaUtils::Genre:
0204         case ElisaUtils::Lyricist:
0205         case ElisaUtils::Composer:
0206         case ElisaUtils::FileName:
0207         case ElisaUtils::Container:
0208         case ElisaUtils::Unknown:
0209         case ElisaUtils::PlayList:
0210             break;
0211         }
0212         break;
0213     }
0214     case DataTypes::ColumnsRoles::ArtistRole:
0215     {
0216         switch (d->mModelType)
0217         {
0218         case ElisaUtils::Track:
0219         {
0220             auto itArtist = d->mAllTrackData[index.row()].find(TrackDataType::key_type::ArtistRole);
0221             if (itArtist != d->mAllTrackData[index.row()].end()) {
0222                 result = d->mAllTrackData[index.row()][TrackDataType::key_type::ArtistRole];
0223             } else {
0224                 result = d->mAllTrackData[index.row()][TrackDataType::key_type::AlbumArtistRole];
0225             }
0226             break;
0227         }
0228         case ElisaUtils::Album:
0229             result = d->mAllAlbumData[index.row()][static_cast<AlbumDataType::key_type>(role)];
0230             break;
0231         case ElisaUtils::Artist:
0232             result = d->mAllArtistData[index.row()][static_cast<ArtistDataType::key_type>(role)];
0233             break;
0234         case ElisaUtils::Genre:
0235             result = d->mAllGenreData[index.row()][static_cast<GenreDataType::key_type>(role)];
0236             break;
0237         case ElisaUtils::Radio:
0238             result = d->mAllRadiosData[index.row()][static_cast<TrackDataType::key_type>(role)];
0239             break;
0240         case ElisaUtils::Lyricist:
0241         case ElisaUtils::Composer:
0242         case ElisaUtils::FileName:
0243         case ElisaUtils::Container:
0244         case ElisaUtils::Unknown:
0245         case ElisaUtils::PlayList:
0246             break;
0247         }
0248         break;
0249     }
0250     case DataTypes::ColumnsRoles::FullDataRole:
0251         switch (d->mModelType)
0252         {
0253         case ElisaUtils::Track:
0254             result = QVariant::fromValue(static_cast<DataTypes::MusicDataType>(d->mAllTrackData[index.row()]));
0255             break;
0256         case ElisaUtils::Radio:
0257             result = QVariant::fromValue(static_cast<DataTypes::MusicDataType>(d->mAllRadiosData[index.row()]));
0258             break;
0259         case ElisaUtils::Album:
0260             result = QVariant::fromValue(static_cast<DataTypes::MusicDataType>(d->mAllAlbumData[index.row()]));
0261             break;
0262         case ElisaUtils::Artist:
0263             result = QVariant::fromValue(static_cast<DataTypes::MusicDataType>(d->mAllArtistData[index.row()]));
0264             break;
0265         case ElisaUtils::Genre:
0266             result = QVariant::fromValue(static_cast<DataTypes::MusicDataType>(d->mAllGenreData[index.row()]));
0267             break;
0268         case ElisaUtils::Lyricist:
0269         case ElisaUtils::Composer:
0270         case ElisaUtils::FileName:
0271         case ElisaUtils::Container:
0272         case ElisaUtils::Unknown:
0273         case ElisaUtils::PlayList:
0274             break;
0275         }
0276         break;
0277     case DataTypes::ColumnsRoles::ResourceRole:
0278     {
0279         switch (d->mModelType)
0280         {
0281         case ElisaUtils::Track:
0282         case ElisaUtils::FileName:
0283             result = d->mAllTrackData[index.row()][TrackDataType::key_type::ResourceRole];
0284             break;
0285         case ElisaUtils::Radio:
0286             result = d->mAllRadiosData[index.row()][TrackDataType::key_type::ResourceRole];
0287             break;
0288         case ElisaUtils::Album:
0289         case ElisaUtils::Artist:
0290         case ElisaUtils::Genre:
0291         case ElisaUtils::Lyricist:
0292         case ElisaUtils::Composer:
0293         case ElisaUtils::Container:
0294         case ElisaUtils::Unknown:
0295         case ElisaUtils::PlayList:
0296             result = QUrl{};
0297             break;
0298         }
0299         break;
0300     }
0301     case DataTypes::ColumnsRoles::HasChildrenRole:
0302     {
0303         switch (d->mModelType)
0304         {
0305         case ElisaUtils::Track:
0306         case ElisaUtils::FileName:
0307         case ElisaUtils::Radio:
0308         case ElisaUtils::Unknown:
0309             result = false;
0310             break;
0311         case ElisaUtils::Album:
0312         case ElisaUtils::Artist:
0313         case ElisaUtils::Genre:
0314         case ElisaUtils::Lyricist:
0315         case ElisaUtils::Composer:
0316         case ElisaUtils::Container:
0317         case ElisaUtils::PlayList:
0318             result = true;
0319             break;
0320         }
0321         break;
0322     }
0323     default:
0324         switch(d->mModelType)
0325         {
0326         case ElisaUtils::Track:
0327             result = d->mAllTrackData[index.row()][static_cast<TrackDataType::key_type>(role)];
0328             break;
0329         case ElisaUtils::Album:
0330             result = d->mAllAlbumData[index.row()][static_cast<AlbumDataType::key_type>(role)];
0331             break;
0332         case ElisaUtils::Artist:
0333             result = d->mAllArtistData[index.row()][static_cast<ArtistDataType::key_type>(role)];
0334             break;
0335         case ElisaUtils::Genre:
0336             result = d->mAllGenreData[index.row()][static_cast<GenreDataType::key_type>(role)];
0337             break;
0338         case ElisaUtils::Radio:
0339             result = d->mAllRadiosData[index.row()][static_cast<TrackDataType::key_type>(role)];
0340             break;
0341         case ElisaUtils::Lyricist:
0342         case ElisaUtils::Composer:
0343         case ElisaUtils::FileName:
0344         case ElisaUtils::Container:
0345         case ElisaUtils::Unknown:
0346         case ElisaUtils::PlayList:
0347             break;
0348         }
0349     }
0350 
0351     return result;
0352 }
0353 
0354 QModelIndex DataModel::index(int row, int column, const QModelIndex &parent) const
0355 {
0356     auto result = QModelIndex();
0357 
0358     if (column != 0) {
0359         return result;
0360     }
0361 
0362     if (parent.isValid()) {
0363         return result;
0364     }
0365 
0366     result = createIndex(row, column);
0367 
0368     return result;
0369 }
0370 
0371 QModelIndex DataModel::parent(const QModelIndex &child) const
0372 {
0373     Q_UNUSED(child)
0374 
0375     auto result = QModelIndex();
0376 
0377     return result;
0378 }
0379 
0380 QString DataModel::title() const
0381 {
0382     return d->mAlbumTitle;
0383 }
0384 
0385 QString DataModel::author() const
0386 {
0387     return d->mAlbumArtist;
0388 }
0389 
0390 bool DataModel::isBusy() const
0391 {
0392     return d->mIsBusy;
0393 }
0394 
0395 void DataModel::initializeByData(MusicListenersManager *manager, DatabaseInterface *database,
0396                                  ElisaUtils::PlayListEntryType modelType, ElisaUtils::FilterType filter,
0397                                  const DataTypes::DataType &dataFilter)
0398 {
0399     qCDebug(orgKdeElisaModel()) << "DataModel::initialize" << modelType << filter << dataFilter;
0400 
0401     d->mDatabaseId = dataFilter[DataTypes::DatabaseIdRole].toULongLong();
0402     d->mGenre = dataFilter[DataTypes::GenreRole].toString();
0403     d->mArtist = dataFilter[DataTypes::ArtistRole].toString();
0404 
0405     initializeModel(manager, database, modelType, filter);
0406 }
0407 
0408 void DataModel::setBusy(bool value)
0409 {
0410     if (d->mIsBusy == value) {
0411         return;
0412     }
0413 
0414     d->mIsBusy = value;
0415     Q_EMIT isBusyChanged();
0416 }
0417 
0418 void DataModel::initializeModel(MusicListenersManager *manager, DatabaseInterface *database,
0419                                 ElisaUtils::PlayListEntryType modelType, DataModel::FilterType type)
0420 {
0421     d->mModelType = modelType;
0422     d->mFilterType = type;
0423 
0424     if (manager) {
0425         manager->connectModel(d->mDataLoader);
0426     }
0427 
0428     if (manager) {
0429         connectModel(manager->viewDatabase());
0430     } else if (database) {
0431         connectModel(database);
0432     } else {
0433         return;
0434     }
0435 
0436     switch(d->mFilterType)
0437     {
0438     case ElisaUtils::NoFilter:
0439         connect(this, &DataModel::needData,
0440                 d->mDataLoader, &ModelDataLoader::loadData);
0441         break;
0442     case ElisaUtils::FilterById:
0443         connect(this, &DataModel::needDataById,
0444                 d->mDataLoader, &ModelDataLoader::loadDataByAlbumId);
0445         break;
0446     case ElisaUtils::FilterByGenre:
0447         connect(this, &DataModel::needDataByGenre,
0448                 d->mDataLoader, &ModelDataLoader::loadDataByGenre);
0449         break;
0450     case ElisaUtils::FilterByArtist:
0451         connect(this, &DataModel::needDataByArtist,
0452                 d->mDataLoader, &ModelDataLoader::loadDataByArtist);
0453         break;
0454     case ElisaUtils::FilterByGenreAndArtist:
0455         connect(this, &DataModel::needDataByGenreAndArtist,
0456                 d->mDataLoader, &ModelDataLoader::loadDataByGenreAndArtist);
0457         break;
0458     case ElisaUtils::FilterByRecentlyPlayed:
0459         connect(this, &DataModel::needRecentlyPlayedData,
0460                 d->mDataLoader, &ModelDataLoader::loadRecentlyPlayedData);
0461         break;
0462     case ElisaUtils::FilterByFrequentlyPlayed:
0463         connect(this, &DataModel::needFrequentlyPlayedData,
0464                 d->mDataLoader, &ModelDataLoader::loadFrequentlyPlayedData);
0465         break;
0466     case ElisaUtils::FilterByPath:
0467     case ElisaUtils::UnknownFilter:
0468         break;
0469     }
0470 
0471     setBusy(true);
0472 
0473     askModelData();
0474 }
0475 
0476 void DataModel::askModelData()
0477 {
0478     switch(d->mFilterType)
0479     {
0480     case ElisaUtils::NoFilter:
0481         Q_EMIT needData(d->mModelType);
0482         break;
0483     case ElisaUtils::FilterById:
0484         Q_EMIT needDataById(d->mModelType, d->mDatabaseId);
0485         break;
0486     case ElisaUtils::FilterByGenre:
0487         Q_EMIT needDataByGenre(d->mModelType, d->mGenre);
0488         break;
0489     case ElisaUtils::FilterByArtist:
0490         Q_EMIT needDataByArtist(d->mModelType, d->mArtist);
0491         break;
0492     case ElisaUtils::FilterByGenreAndArtist:
0493         Q_EMIT needDataByGenreAndArtist(d->mModelType, d->mGenre, d->mArtist);
0494         break;
0495     case ElisaUtils::FilterByRecentlyPlayed:
0496         Q_EMIT needRecentlyPlayedData(d->mModelType);
0497         break;
0498     case ElisaUtils::FilterByFrequentlyPlayed:
0499         Q_EMIT needFrequentlyPlayedData(d->mModelType);
0500         break;
0501     case ElisaUtils::FilterByPath:
0502     case ElisaUtils::UnknownFilter:
0503         break;
0504     }
0505 }
0506 
0507 int DataModel::indexFromId(qulonglong id) const
0508 {
0509     int result;
0510     DataModel::ListTrackDataType mAllData = d->mModelType == ElisaUtils::Radio ? d->mAllRadiosData: d->mAllTrackData;
0511 
0512     for (result = 0; result < mAllData.size(); ++result) {
0513         if (mAllData[result].databaseId() == id) {
0514             return result;
0515         }
0516     }
0517 
0518     result = -1;
0519 
0520     return result;
0521 }
0522 
0523 void DataModel::connectModel(DatabaseInterface *database)
0524 {
0525     d->mDataLoader->setDatabase(database);
0526 
0527     connect(d->mDataLoader, &ModelDataLoader::allTracksData,
0528             this, &DataModel::tracksAdded);
0529     connect(d->mDataLoader, &ModelDataLoader::allRadiosData,
0530             this, &DataModel::radiosAdded);
0531     connect(d->mDataLoader, &ModelDataLoader::allAlbumsData,
0532             this, &DataModel::albumsAdded);
0533     connect(d->mDataLoader, &ModelDataLoader::allArtistsData,
0534             this, &DataModel::artistsAdded);
0535     connect(d->mDataLoader, &ModelDataLoader::allGenresData,
0536             this, &DataModel::genresAdded);
0537     connect(d->mDataLoader, &ModelDataLoader::genresAdded,
0538             this, &DataModel::genresAdded);
0539     connect(d->mDataLoader, &ModelDataLoader::albumsAdded,
0540             this, &DataModel::albumsAdded);
0541     connect(d->mDataLoader, &ModelDataLoader::albumModified,
0542             this, &DataModel::albumModified);
0543     connect(d->mDataLoader, &ModelDataLoader::albumRemoved,
0544             this, &DataModel::albumRemoved);
0545     connect(d->mDataLoader, &ModelDataLoader::tracksAdded,
0546             this, &DataModel::tracksAdded);
0547     connect(d->mDataLoader, &ModelDataLoader::trackModified,
0548             this, &DataModel::trackModified);
0549     connect(d->mDataLoader, &ModelDataLoader::trackRemoved,
0550             this, &DataModel::trackRemoved);
0551     connect(d->mDataLoader, &ModelDataLoader::artistsAdded,
0552             this, &DataModel::artistsAdded);
0553     connect(d->mDataLoader, &ModelDataLoader::artistRemoved,
0554             this, &DataModel::artistRemoved);
0555     connect(d->mDataLoader, &ModelDataLoader::radioAdded,
0556             this, &DataModel::radioAdded);
0557     connect(d->mDataLoader, &ModelDataLoader::radioModified,
0558             this, &DataModel::radioModified);
0559     connect(d->mDataLoader, &ModelDataLoader::radioRemoved,
0560             this, &DataModel::radioRemoved);
0561     connect(d->mDataLoader, &ModelDataLoader::clearedDatabase,
0562             this, &DataModel::cleanedDatabase);
0563 }
0564 
0565 void DataModel::tracksAdded(ListTrackDataType newData)
0566 {
0567     if (newData.isEmpty() && d->mModelType == ElisaUtils::Track) {
0568         setBusy(false);
0569     }
0570 
0571     if (newData.isEmpty() || d->mModelType != ElisaUtils::Track) {
0572         return;
0573     }
0574 
0575     if (d->mFilterType == ElisaUtils::FilterById && !d->mAllTrackData.isEmpty()) {
0576         for (const auto &newTrack : newData) {
0577             auto trackIndex = indexFromId(newTrack.databaseId());
0578 
0579             if (trackIndex != -1) {
0580                 continue;
0581             }
0582 
0583             bool trackInserted = false;
0584             for (int trackIndex = 0; trackIndex < d->mAllTrackData.count(); ++trackIndex) {
0585                 const auto &oneTrack = d->mAllTrackData[trackIndex];
0586 
0587                 if (oneTrack.discNumber() >= newTrack.discNumber() && oneTrack.trackNumber() > newTrack.trackNumber()) {
0588                     beginInsertRows({}, trackIndex, trackIndex);
0589                     d->mAllTrackData.insert(trackIndex, newTrack);
0590                     endInsertRows();
0591 
0592                     if (d->mAllTrackData.size() == 1) {
0593                         setBusy(false);
0594                     }
0595 
0596                     trackInserted = true;
0597                     break;
0598                 }
0599             }
0600 
0601             if (!trackInserted) {
0602                 beginInsertRows({}, d->mAllTrackData.count(), d->mAllTrackData.count());
0603                 d->mAllTrackData.insert(d->mAllTrackData.count(), newTrack);
0604                 endInsertRows();
0605 
0606                 if (d->mAllTrackData.size() == 1) {
0607                     setBusy(false);
0608                 }
0609             }
0610         }
0611     } else {
0612         if (d->mAllTrackData.isEmpty()) {
0613             beginInsertRows({}, 0, newData.size() - 1);
0614             d->mAllTrackData.swap(newData);
0615             endInsertRows();
0616 
0617             setBusy(false);
0618         } else {
0619             beginInsertRows({}, d->mAllTrackData.size(), d->mAllTrackData.size() + newData.size() - 1);
0620             d->mAllTrackData.append(newData);
0621             endInsertRows();
0622         }
0623     }
0624 }
0625 
0626 void DataModel::radiosAdded(ListRadioDataType newData)
0627 {
0628     if (newData.isEmpty() && d->mModelType == ElisaUtils::Radio) {
0629         setBusy(false);
0630     }
0631 
0632     if (newData.isEmpty() || d->mModelType != ElisaUtils::Radio) {
0633         return;
0634     }
0635 
0636     if (d->mFilterType == ElisaUtils::FilterById && !d->mAllRadiosData.isEmpty()) {
0637         for (const auto &newTrack : newData) {
0638             auto trackIndex = indexFromId(newTrack.databaseId());
0639 
0640             if (trackIndex != -1) {
0641                 continue;
0642             }
0643 
0644             bool trackInserted = false;
0645             for (int trackIndex = 0; trackIndex < d->mAllRadiosData.count(); ++trackIndex) {
0646                 const auto &oneTrack = d->mAllRadiosData[trackIndex];
0647 
0648                 if (oneTrack.trackNumber() > newTrack.trackNumber()) {
0649                     beginInsertRows({}, trackIndex, trackIndex);
0650                     d->mAllRadiosData.insert(trackIndex, newTrack);
0651                     endInsertRows();
0652 
0653                     if (d->mAllRadiosData.size() == 1) {
0654                         setBusy(false);
0655                     }
0656 
0657                     trackInserted = true;
0658                     break;
0659                 }
0660             }
0661 
0662             if (!trackInserted) {
0663                 beginInsertRows({}, d->mAllRadiosData.count(), d->mAllRadiosData.count());
0664                 d->mAllRadiosData.insert(d->mAllRadiosData.count(), newTrack);
0665                 endInsertRows();
0666 
0667                 if (d->mAllRadiosData.size() == 1) {
0668                     setBusy(false);
0669                 }
0670             }
0671         }
0672     } else {
0673         if (d->mAllRadiosData.isEmpty()) {
0674             beginInsertRows({}, 0, newData.size() - 1);
0675             d->mAllRadiosData.swap(newData);
0676             endInsertRows();
0677 
0678             setBusy(false);
0679         } else {
0680             beginInsertRows({}, d->mAllRadiosData.size(), d->mAllRadiosData.size() + newData.size() - 1);
0681             d->mAllRadiosData.append(newData);
0682             endInsertRows();
0683         }
0684     }
0685 }
0686 
0687 void DataModel::trackModified(const TrackDataType &modifiedTrack)
0688 {
0689     if (d->mModelType != ElisaUtils::Track) {
0690         return;
0691     }
0692 
0693     if (!d->mAlbumTitle.isEmpty() && !d->mAlbumArtist.isEmpty()) {
0694         if (modifiedTrack.album() != d->mAlbumTitle) {
0695             return;
0696         }
0697 
0698         auto trackIndex = indexFromId(modifiedTrack.databaseId());
0699 
0700         if (trackIndex == -1) {
0701             return;
0702         }
0703 
0704         d->mAllTrackData[trackIndex] = modifiedTrack;
0705         Q_EMIT dataChanged(index(trackIndex, 0), index(trackIndex, 0));
0706     } else {
0707         auto itTrack = std::find_if(d->mAllTrackData.begin(), d->mAllTrackData.end(),
0708                                     [modifiedTrack](auto track) {
0709             return track.databaseId() == modifiedTrack.databaseId();
0710         });
0711 
0712         if (itTrack == d->mAllTrackData.end()) {
0713             return;
0714         }
0715 
0716         auto position = itTrack - d->mAllTrackData.begin();
0717 
0718         d->mAllTrackData[position] = modifiedTrack;
0719 
0720         Q_EMIT dataChanged(index(position, 0), index(position, 0));
0721     }
0722 }
0723 
0724 void DataModel::radioModified(const TrackDataType &modifiedRadio)
0725 {
0726     if (d->mModelType != ElisaUtils::Radio) {
0727         return;
0728     }
0729 
0730     auto trackIndex = indexFromId(modifiedRadio.databaseId());
0731 
0732     if (trackIndex == -1) {
0733         return;
0734     }
0735 
0736     d->mAllRadiosData[trackIndex] = modifiedRadio;
0737     Q_EMIT dataChanged(index(trackIndex, 0), index(trackIndex, 0));
0738 }
0739 
0740 void DataModel::trackRemoved(qulonglong removedTrackId)
0741 {
0742     if (d->mModelType != ElisaUtils::Track) {
0743         return;
0744     }
0745 
0746     if (!d->mAlbumTitle.isEmpty() && !d->mAlbumArtist.isEmpty()) {
0747         auto trackIndex = indexFromId(removedTrackId);
0748 
0749         if (trackIndex == -1) {
0750             return;
0751         }
0752 
0753         beginRemoveRows({}, trackIndex, trackIndex);
0754         d->mAllTrackData.removeAt(trackIndex);
0755         endRemoveRows();
0756     } else {
0757         const auto itTrack = std::find_if(d->mAllTrackData.cbegin(), d->mAllTrackData.cend(),
0758                                          [removedTrackId](auto track) {return track.databaseId() == removedTrackId;});
0759 
0760         if (itTrack == d->mAllTrackData.cend()) {
0761             return;
0762         }
0763 
0764         auto position = itTrack - d->mAllTrackData.cbegin();
0765 
0766         beginRemoveRows({}, position, position);
0767         d->mAllTrackData.erase(itTrack);
0768         endRemoveRows();
0769     }
0770 }
0771 
0772 void DataModel::radioRemoved(qulonglong removedRadioId)
0773 {
0774     if (d->mModelType != ElisaUtils::Radio) {
0775         return;
0776     }
0777 
0778 
0779     const auto itRadio = std::find_if(d->mAllRadiosData.cbegin(), d->mAllRadiosData.cend(),
0780                                       [removedRadioId](auto track) {return track.databaseId() == removedRadioId;});
0781 
0782     if (itRadio == d->mAllRadiosData.cend()) {
0783         return;
0784     }
0785 
0786     auto position = itRadio - d->mAllRadiosData.cbegin();
0787 
0788     beginRemoveRows({}, position, position);
0789     d->mAllRadiosData.erase(itRadio);
0790     endRemoveRows();
0791 }
0792 
0793 void DataModel::radioAdded(const DataModel::TrackDataType &radioData)
0794 {
0795     if (d->mModelType != ElisaUtils::Radio) {
0796         return;
0797     }
0798 
0799     ListRadioDataType list;
0800     list.append(radioData);
0801     radiosAdded(list);
0802 }
0803 
0804 void DataModel::removeRadios()
0805 {
0806     if (d->mModelType != ElisaUtils::Radio) {
0807         return;
0808     }
0809 
0810     beginRemoveRows({}, 0, d->mAllRadiosData.size());
0811     d->mAllRadiosData.clear();
0812     endRemoveRows();
0813 }
0814 
0815 void DataModel::genresAdded(DataModel::ListGenreDataType newData)
0816 {
0817     if (newData.isEmpty() && d->mModelType == ElisaUtils::Genre) {
0818         setBusy(false);
0819     }
0820 
0821     if (newData.isEmpty() || d->mModelType != ElisaUtils::Genre) {
0822         return;
0823     }
0824 
0825     if (d->mAllGenreData.isEmpty()) {
0826         beginInsertRows({}, d->mAllGenreData.size(), newData.size() - 1);
0827         d->mAllGenreData.swap(newData);
0828         endInsertRows();
0829 
0830         setBusy(false);
0831     } else {
0832         beginInsertRows({}, d->mAllGenreData.size(), d->mAllGenreData.size() + newData.size() - 1);
0833         d->mAllGenreData.append(newData);
0834         endInsertRows();
0835     }
0836 }
0837 
0838 void DataModel::artistsAdded(DataModel::ListArtistDataType newData)
0839 {
0840     if (newData.isEmpty() && d->mModelType == ElisaUtils::Artist) {
0841         setBusy(false);
0842     }
0843 
0844     if (newData.isEmpty() || d->mModelType != ElisaUtils::Artist) {
0845         return;
0846     }
0847 
0848     if (d->mAllArtistData.isEmpty()) {
0849         beginInsertRows({}, d->mAllArtistData.size(), newData.size() - 1);
0850         d->mAllArtistData.swap(newData);
0851         endInsertRows();
0852 
0853         setBusy(false);
0854     } else {
0855         beginInsertRows({}, d->mAllArtistData.size(), d->mAllArtistData.size() + newData.size() - 1);
0856         d->mAllArtistData.append(newData);
0857         endInsertRows();
0858     }
0859 }
0860 
0861 void DataModel::artistRemoved(qulonglong removedDatabaseId)
0862 {
0863     if (d->mModelType != ElisaUtils::Artist) {
0864         return;
0865     }
0866 
0867     const auto removedDataIterator = std::find_if(d->mAllArtistData.cbegin(), d->mAllArtistData.cend(),
0868                                                   [removedDatabaseId](auto album) {return album.databaseId() == removedDatabaseId;});
0869 
0870     if (removedDataIterator == d->mAllArtistData.cend()) {
0871         return;
0872     }
0873 
0874     int dataIndex = removedDataIterator - d->mAllArtistData.cbegin();
0875 
0876     beginRemoveRows({}, dataIndex, dataIndex);
0877 
0878     d->mAllArtistData.erase(removedDataIterator);
0879 
0880     endRemoveRows();
0881 }
0882 
0883 void DataModel::albumsAdded(DataModel::ListAlbumDataType newData)
0884 {
0885     if (newData.isEmpty() && d->mModelType == ElisaUtils::Album) {
0886         setBusy(false);
0887     }
0888 
0889     if (newData.isEmpty() || d->mModelType != ElisaUtils::Album) {
0890         return;
0891     }
0892 
0893     if (d->mAllAlbumData.isEmpty()) {
0894         beginInsertRows({}, d->mAllAlbumData.size(), newData.size() - 1);
0895         d->mAllAlbumData.swap(newData);
0896         endInsertRows();
0897 
0898         setBusy(false);
0899     } else {
0900         beginInsertRows({}, d->mAllAlbumData.size(), d->mAllAlbumData.size() + newData.size() - 1);
0901         d->mAllAlbumData.append(newData);
0902         endInsertRows();
0903     }
0904 }
0905 
0906 void DataModel::albumRemoved(qulonglong removedDatabaseId)
0907 {
0908     if (d->mModelType != ElisaUtils::Album) {
0909         return;
0910     }
0911 
0912     auto removedDataIterator = d->mAllAlbumData.cend();
0913 
0914     removedDataIterator = std::find_if(d->mAllAlbumData.cbegin(), d->mAllAlbumData.cend(),
0915                                        [removedDatabaseId](auto album) {return album.databaseId() == removedDatabaseId;});
0916 
0917     if (removedDataIterator == d->mAllAlbumData.cend()) {
0918         return;
0919     }
0920 
0921     int dataIndex = removedDataIterator - d->mAllAlbumData.cbegin();
0922 
0923     beginRemoveRows({}, dataIndex, dataIndex);
0924 
0925     d->mAllAlbumData.erase(removedDataIterator);
0926 
0927     endRemoveRows();
0928 }
0929 
0930 void DataModel::albumModified(const DataModel::AlbumDataType &modifiedAlbum)
0931 {
0932     if (d->mModelType != ElisaUtils::Album) {
0933         return;
0934     }
0935 
0936     auto modifiedAlbumIterator = std::find_if(d->mAllAlbumData.begin(), d->mAllAlbumData.end(),
0937                                               [modifiedAlbum](auto album) {
0938         return album.databaseId() == modifiedAlbum.databaseId();
0939     });
0940 
0941     if (modifiedAlbumIterator == d->mAllAlbumData.end()) {
0942         return;
0943     }
0944 
0945     auto albumIndex = modifiedAlbumIterator - d->mAllAlbumData.begin();
0946 
0947     Q_EMIT dataChanged(index(albumIndex, 0), index(albumIndex, 0));
0948 }
0949 
0950 void DataModel::initialize(MusicListenersManager *manager, DatabaseInterface *database,
0951                            ElisaUtils::PlayListEntryType modelType, ElisaUtils::FilterType filter,
0952                            const QString &genre, const QString &artist, qulonglong databaseId,
0953                            const QUrl &pathFilter)
0954 {
0955     Q_UNUSED(pathFilter)
0956 
0957     qCDebug(orgKdeElisaModel()) << "DataModel::initialize" << modelType << filter << databaseId << genre << artist;
0958 
0959     d->mDatabaseId = databaseId;
0960     d->mGenre = genre;
0961     d->mArtist = artist;
0962 
0963     initializeModel(manager, database, modelType, filter);
0964 }
0965 
0966 void DataModel::cleanedDatabase()
0967 {
0968     beginResetModel();
0969     d->mAllAlbumData.clear();
0970     d->mAllGenreData.clear();
0971     d->mAllTrackData.clear();
0972     d->mAllArtistData.clear();
0973     endResetModel();
0974 }
0975 
0976 #include "moc_datamodel.cpp"