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

0001 /*
0002    SPDX-FileCopyrightText: 2016 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
0003    SPDX-FileCopyrightText: 2017 (c) Alexander Stippich <a.stippich@gmx.net>
0004 
0005    SPDX-License-Identifier: LGPL-3.0-or-later
0006  */
0007 
0008 #include "abstractmediaproxymodel.h"
0009 
0010 #include "mediaplaylistproxymodel.h"
0011 
0012 #include <QWriteLocker>
0013 #include <QReadLocker>
0014 #include <QtConcurrentRun>
0015 
0016 AbstractMediaProxyModel::AbstractMediaProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
0017 {
0018     setFilterCaseSensitivity(Qt::CaseInsensitive);
0019     mThreadPool.setMaxThreadCount(1);
0020 
0021     connect(&mEnqueueWatcher, &QFutureWatcher<void>::finished, this, &AbstractMediaProxyModel::afterPlaylistEnqueue);
0022 }
0023 
0024 AbstractMediaProxyModel::~AbstractMediaProxyModel()
0025 {
0026     disconnect(&mEnqueueWatcher, &QFutureWatcher<void>::finished, this, &AbstractMediaProxyModel::afterPlaylistEnqueue);
0027 };
0028 
0029 QString AbstractMediaProxyModel::filterText() const
0030 {
0031     return mFilterText;
0032 }
0033 
0034 int AbstractMediaProxyModel::filterRating() const
0035 {
0036     return mFilterRating;
0037 }
0038 
0039 void AbstractMediaProxyModel::setFilterText(const QString &filterText)
0040 {
0041     QWriteLocker writeLocker(&mDataLock);
0042 
0043     if (mFilterText == filterText)
0044         return;
0045 
0046     mFilterText = filterText;
0047 
0048     mFilterExpression.setPattern(mFilterText.normalized(QString::NormalizationForm_KC));
0049     mFilterExpression.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
0050     mFilterExpression.optimize();
0051 
0052     invalidate();
0053 
0054     Q_EMIT filterTextChanged(mFilterText);
0055 }
0056 
0057 void AbstractMediaProxyModel::setFilterRating(int filterRating)
0058 {
0059     QWriteLocker writeLocker(&mDataLock);
0060 
0061     if (mFilterRating == filterRating) {
0062         return;
0063     }
0064 
0065     mFilterRating = filterRating;
0066 
0067     invalidate();
0068 
0069     Q_EMIT filterRatingChanged(filterRating);
0070 }
0071 
0072 bool AbstractMediaProxyModel::sortedAscending() const
0073 {
0074     return sortOrder() ? false : true;
0075 }
0076 
0077 MediaPlayListProxyModel *AbstractMediaProxyModel::playList() const
0078 {
0079     return mPlayList;
0080 }
0081 
0082 void AbstractMediaProxyModel::sortModel(Qt::SortOrder order)
0083 {
0084     sort(0, order);
0085     Q_EMIT sortedAscendingChanged();
0086 }
0087 
0088 void AbstractMediaProxyModel::setPlayList(MediaPlayListProxyModel *playList)
0089 {
0090     if (mPlayList == playList) {
0091         return;
0092     }
0093 
0094     disconnectPlayList();
0095 
0096     mPlayList = playList;
0097     Q_EMIT playListChanged();
0098 
0099     connectPlayList();
0100 }
0101 
0102 void AbstractMediaProxyModel::disconnectPlayList()
0103 {
0104     if (mPlayList) {
0105         disconnect(this, &AbstractMediaProxyModel::entriesToEnqueue,
0106                    mPlayList, static_cast<void(MediaPlayListProxyModel::*)(const DataTypes::EntryDataList&, ElisaUtils::PlayListEnqueueMode, ElisaUtils::PlayListEnqueueTriggerPlay)>(&MediaPlayListProxyModel::enqueue));
0107         disconnect(this, &AbstractMediaProxyModel::switchToTrackUrl,
0108                    mPlayList, static_cast<void(MediaPlayListProxyModel::*)(const QUrl &url, ElisaUtils::PlayListEnqueueTriggerPlay)>(&MediaPlayListProxyModel::switchToTrackUrl));
0109     }
0110 }
0111 
0112 void AbstractMediaProxyModel::connectPlayList()
0113 {
0114     if (mPlayList) {
0115         connect(this, &AbstractMediaProxyModel::entriesToEnqueue,
0116                 mPlayList, static_cast<void(MediaPlayListProxyModel::*)(const DataTypes::EntryDataList&, ElisaUtils::PlayListEnqueueMode, ElisaUtils::PlayListEnqueueTriggerPlay)>(&MediaPlayListProxyModel::enqueue));
0117         connect(this, &AbstractMediaProxyModel::switchToTrackUrl,
0118                 mPlayList, static_cast<void(MediaPlayListProxyModel::*)(const QUrl &url, ElisaUtils::PlayListEnqueueTriggerPlay)>(&MediaPlayListProxyModel::switchToTrackUrl));
0119     }
0120 }
0121 
0122 QFuture<void> AbstractMediaProxyModel::genericEnqueueToPlayList(const QModelIndex &rootIndex,
0123                                                        ElisaUtils::PlayListEnqueueMode enqueueMode,
0124                                                        ElisaUtils::PlayListEnqueueTriggerPlay triggerPlay)
0125 {
0126     return QtConcurrent::run(&mThreadPool, [=] () {
0127         QReadLocker locker(&mDataLock);
0128         auto allData = DataTypes::EntryDataList{};
0129         allData.reserve(rowCount());
0130         for (int rowIndex = 0, maxRowCount = rowCount(); rowIndex < maxRowCount; ++rowIndex) {
0131             auto currentIndex = index(rowIndex, 0, rootIndex);
0132 
0133             allData.push_back(DataTypes::EntryData{data(currentIndex, DataTypes::FullDataRole).value<DataTypes::MusicDataType>(),
0134                                                    data(currentIndex, Qt::DisplayRole).toString(), {}});
0135         }
0136         Q_EMIT entriesToEnqueue(allData, enqueueMode, triggerPlay);
0137     });
0138 }
0139 
0140 void AbstractMediaProxyModel::enqueueToPlayList(const QModelIndex &rootIndex)
0141 {
0142     genericEnqueueToPlayList(rootIndex, ElisaUtils::AppendPlayList, ElisaUtils::DoNotTriggerPlay);
0143 }
0144 
0145 void AbstractMediaProxyModel::replaceAndPlayOfPlayList(const QModelIndex &rootIndex)
0146 {
0147     genericEnqueueToPlayList(rootIndex, ElisaUtils::ReplacePlayList, ElisaUtils::TriggerPlay);
0148 }
0149 
0150 void AbstractMediaProxyModel::replaceAndPlayOfPlayListFromTrackUrl(const QModelIndex &rootIndex, const QUrl &switchTrackUrl)
0151 {
0152     auto future = genericEnqueueToPlayList(rootIndex, ElisaUtils::ReplacePlayList, ElisaUtils::DoNotTriggerPlay);
0153 
0154     // Wait until the future is finished before switching tracks
0155     mEnqueueWatcher.setFuture(future);
0156     mEnqueueWatcherTrackUrl = switchTrackUrl;
0157 }
0158 
0159 void AbstractMediaProxyModel::afterPlaylistEnqueue()
0160 {
0161     if (mEnqueueWatcherTrackUrl.isEmpty()) {
0162         return;
0163     }
0164 
0165     Q_EMIT switchToTrackUrl(mEnqueueWatcherTrackUrl, ElisaUtils::TriggerPlay);
0166 
0167     // Reset
0168     mEnqueueWatcherTrackUrl = QUrl();
0169 }
0170 
0171 void AbstractMediaProxyModel::enqueue(const DataTypes::MusicDataType &newEntry, const QString &newEntryTitle, ElisaUtils::PlayListEnqueueMode enqueueMode, ElisaUtils::PlayListEnqueueTriggerPlay triggerPlay)
0172 {
0173     auto allData = DataTypes::EntryDataList{};
0174 
0175     allData.push_back(DataTypes::EntryData{newEntry, newEntryTitle, {}});
0176 
0177     Q_EMIT entriesToEnqueue(allData, enqueueMode, triggerPlay);
0178 }
0179 
0180 
0181 #include "moc_abstractmediaproxymodel.cpp"