mediaplaylist.h 11.7 KB
Newer Older
1
/*
2
 * Copyright 2015-2017 Matthieu Gallien <matthieu_gallien@yahoo.fr>
3
 *
4 5
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
6 7 8
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
9
 * This program is distributed in the hope that it will be useful,
10 11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
13
 *
14 15
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16 17 18 19 20
 */

#ifndef MEDIAPLAYLIST_H
#define MEDIAPLAYLIST_H

21 22
#include "elisaLib_export.h"

23
#include "musicaudiotrack.h"
24
#include "elisautils.h"
25
#include "databaseinterface.h"
26

27 28
#include <QAbstractListModel>
#include <QVector>
29
#include <QMediaPlayer>
30

31 32 33
#include <utility>
#include <tuple>

34
class MediaPlayListPrivate;
35
class MusicListenersManager;
36
class MediaPlayListEntry;
37
class QDebug;
38

39
class ELISALIB_EXPORT MediaPlayList : public QAbstractListModel
40 41 42
{
    Q_OBJECT

43
    Q_PROPERTY(QVariantMap persistentState
44 45 46 47
               READ persistentState
               WRITE setPersistentState
               NOTIFY persistentStateChanged)

48 49 50 51 52
    Q_PROPERTY(MusicListenersManager* musicListenersManager
               READ musicListenersManager
               WRITE setMusicListenersManager
               NOTIFY musicListenersManagerChanged)

53 54 55 56
    Q_PROPERTY(int tracksCount
               READ tracksCount
               NOTIFY tracksCountChanged)

57 58 59 60
    Q_PROPERTY(QPersistentModelIndex previousTrack
               READ previousTrack
               NOTIFY previousTrackChanged)

61 62 63 64
    Q_PROPERTY(QPersistentModelIndex currentTrack
               READ currentTrack
               NOTIFY currentTrackChanged)

65 66 67 68
    Q_PROPERTY(QPersistentModelIndex nextTrack
               READ nextTrack
               NOTIFY nextTrackChanged)

69 70 71 72 73 74 75 76 77 78 79 80 81 82
    Q_PROPERTY(int currentTrackRow
               READ currentTrackRow
               NOTIFY currentTrackRowChanged)

    Q_PROPERTY(bool randomPlay
               READ randomPlay
               WRITE setRandomPlay
               NOTIFY randomPlayChanged)

    Q_PROPERTY(bool repeatPlay
               READ repeatPlay
               WRITE setRepeatPlay
               NOTIFY repeatPlayChanged)

83 84 85 86
    Q_PROPERTY(int remainingTracks
               READ remainingTracks
               NOTIFY remainingTracksChanged)

87 88 89
public:

    enum ColumnsRoles {
90 91 92 93 94
        TitleRole = DatabaseInterface::TitleRole,
        SecondaryTextRole,
        ImageUrlRole,
        ShadowForImageRole,
        ChildModelRole,
95
        DurationRole,
96
        StringDurationRole,
97 98
        MilliSecondsDurationRole,
        ArtistRole,
99 100
        AllArtistsRole,
        HighestTrackRating,
101
        AlbumRole,
102
        AlbumArtistRole,
103
        IsValidAlbumArtistRole,
104 105 106
        TrackNumberRole,
        DiscNumberRole,
        RatingRole,
107 108 109 110 111 112 113 114
        GenreRole,
        LyricistRole,
        ComposerRole,
        CommentRole,
        YearRole,
        ChannelsRole,
        BitRateRole,
        SampleRateRole,
115
        ResourceRole,
116 117 118 119 120
        IdRole,
        DatabaseIdRole,
        IsSingleDiscAlbumRole,
        ContainerDataRole,
        IsPartialDataRole,
Matthieu Gallien's avatar
Matthieu Gallien committed
121
        AlbumIdRole,
122 123
        HasEmbeddedCover,
        FileModificationTime,
124 125 126 127
        FirstPlayDate,
        LastPlayDate,
        PlayCounter,
        PlayFrequency,
128
        ElementTypeRole,
129
        LyricsRole,
130 131
        IsValidRole,
        TrackDataRole,
132 133
        CountRole,
        IsPlayingRole,
134
        AlbumSectionRole,
135
    };
136

137 138
    Q_ENUM(ColumnsRoles)

139 140 141 142 143 144 145 146
    enum PlayState {
        NotPlaying,
        IsPlaying,
        IsPaused,
    };

    Q_ENUM(PlayState)

147
    using ListTrackDataType = DatabaseInterface::ListTrackDataType;
148

149
    using TrackDataType = DatabaseInterface::TrackDataType;
150

151
    explicit MediaPlayList(QObject *parent = nullptr);
152

153
    ~MediaPlayList() override;
154 155 156 157 158 159 160 161 162 163 164

    int rowCount(const QModelIndex &parent = QModelIndex()) const override;

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;

    QHash<int, QByteArray> roleNames() const override;

    Q_INVOKABLE bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;

165 166 167 168
    Q_INVOKABLE bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override;

    Q_INVOKABLE void move(int from, int to, int n);

169 170
    Q_INVOKABLE void clearPlayList();

171 172
    Q_INVOKABLE bool savePlaylist(const QUrl &fileName);

173
    QVariantMap persistentState() const;
174

175 176
    MusicListenersManager* musicListenersManager() const;

177 178
    int tracksCount() const;

179 180
    QPersistentModelIndex previousTrack() const;

181 182
    QPersistentModelIndex currentTrack() const;

183 184
    QPersistentModelIndex nextTrack() const;

185 186 187 188 189 190
    int currentTrackRow() const;

    bool randomPlay() const;

    bool repeatPlay() const;

191 192
    int remainingTracks() const;

193
Q_SIGNALS:
194 195 196
    void displayUndoInline();

    void hideUndoInline();
197

198
    void newTrackByNameInList(const QVariant &title, const QVariant &artist, const QVariant &album, const QVariant &trackNumber, const QVariant &discNumber);
199

200 201
    void newEntryInList(qulonglong newDatabaseId,
                        const QString &entryTitle,
202
                        ElisaUtils::PlayListEntryType databaseIdType);
203

204 205
    void persistentStateChanged();

206
    void musicListenersManagerChanged();
207

208 209
    void tracksCountChanged();

210
    void previousTrackChanged(const QPersistentModelIndex &previousTrack);
211

212
    void currentTrackChanged(const QPersistentModelIndex &currentTrack);
213

214
    void nextTrackChanged(const QPersistentModelIndex &nextTrack);
215

216 217 218 219
    void clearPlayListPlayer();

    void undoClearPlayListPlayer();

220 221 222 223 224 225 226 227
    void currentTrackRowChanged();

    void randomPlayChanged();

    void repeatPlayChanged();

    void playListFinished();

228 229 230 231
    void playListLoaded();

    void playListLoadFailed();

Alexander Stippich's avatar
Alexander Stippich committed
232 233
    void ensurePlay();

234 235
    void remainingTracksChanged();

236
public Q_SLOTS:
237

238
    void setPersistentState(const QVariantMap &persistentState);
239

240 241
    void removeSelection(QList<int> selection);

242 243 244
    void tracksListAdded(qulonglong newDatabaseId,
                         const QString &entryTitle,
                         ElisaUtils::PlayListEntryType databaseIdType,
245
                         const MediaPlayList::ListTrackDataType &tracks);
246

247
    void trackChanged(const MediaPlayList::TrackDataType &track);
248

249
    void trackRemoved(qulonglong trackId);
250

251 252
    void setMusicListenersManager(MusicListenersManager* musicListenersManager);

253 254 255 256 257 258 259 260 261 262
    void setRandomPlay(bool value);

    void setRepeatPlay(bool value);

    void skipNextTrack();

    void skipPreviousTrack();

    void switchTo(int row);

263 264
    void loadPlaylist(const QString &localFileName);

265 266
    void loadPlaylist(const QUrl &fileName);

267 268 269 270 271 272 273 274
    void enqueue(const ElisaUtils::EntryData &newEntry, ElisaUtils::PlayListEntryType databaseIdType);

    void enqueue(const ElisaUtils::EntryDataList &newEntries, ElisaUtils::PlayListEntryType databaseIdType);

    void enqueue(qulonglong newEntryDatabaseId, const QString &newEntryTitle,
                 ElisaUtils::PlayListEntryType databaseIdType,
                 ElisaUtils::PlayListEnqueueMode enqueueMode,
                 ElisaUtils::PlayListEnqueueTriggerPlay triggerPlay);
275

276
    void enqueue(const ElisaUtils::EntryData &newEntry,
277 278 279
                 ElisaUtils::PlayListEntryType databaseIdType,
                 ElisaUtils::PlayListEnqueueMode enqueueMode,
                 ElisaUtils::PlayListEnqueueTriggerPlay triggerPlay);
280

281 282 283 284
    void enqueue(const ElisaUtils::EntryDataList &newEntries,
                 ElisaUtils::PlayListEntryType databaseIdType,
                 ElisaUtils::PlayListEnqueueMode enqueueMode,
                 ElisaUtils::PlayListEnqueueTriggerPlay triggerPlay);
285

286
    void replaceAndPlay(const ElisaUtils::EntryData &newEntry, ElisaUtils::PlayListEntryType databaseIdType);
287

288
    void enqueueRestoredEntry(const MediaPlayListEntry &newEntry);
289

290
    void trackInError(const QUrl &sourceInError, QMediaPlayer::Error playerError);
291

292 293
    void undoClearPlayList();

Jerome Guidon's avatar
Jerome Guidon committed
294 295
    void updateRadioData(const QVariant &value, int role);

296
private Q_SLOTS:
297

298 299 300 301
    void loadPlayListLoaded();

    void loadPlayListLoadFailed();

302
private:
303 304 305
    void displayOrHideUndoInline(bool value);

    void clearPlayList(bool prepareUndo);
306

307 308 309 310 311 312 313 314
    void resetCurrentTrack();

    void notifyCurrentTrackChanged();

    void restorePlayListPosition();

    void restoreRandomPlay();

Alexander Stippich's avatar
Alexander Stippich committed
315 316
    void createRandomList();

317 318
    void restoreRepeatPlay();

319 320
    void notifyPreviousAndNextTracks();

321
    void enqueueArtist(const QString &artistName);
322

323 324
    void enqueueFilesList(const ElisaUtils::EntryDataList &newEntries);

Jerome Guidon's avatar
Jerome Guidon committed
325
    void enqueueTracksListById(const ElisaUtils::EntryDataList &newEntries, ElisaUtils::PlayListEntryType type);
326

327
    void enqueueOneEntry(const ElisaUtils::EntryData &entryData, ElisaUtils::PlayListEntryType type);
328

329
    void enqueueMultipleEntries(const ElisaUtils::EntryDataList &entriesData, ElisaUtils::PlayListEntryType type);
330

331 332 333 334
    void enqueueCommon();

    void copyD();

335
    std::unique_ptr<MediaPlayListPrivate> d;
336

337
    std::unique_ptr<MediaPlayListPrivate> dOld;
338 339
};

340 341 342 343
class MediaPlayListEntry
{
public:

Matthieu Gallien's avatar
Matthieu Gallien committed
344
    MediaPlayListEntry() = default;
345 346 347 348

    explicit MediaPlayListEntry(qulonglong id) : mId(id), mIsValid(true) {
    }

349
    MediaPlayListEntry(QString title, QString artist, QString album, int trackNumber, int discNumber, ElisaUtils::PlayListEntryType entryType = ElisaUtils::Unknown)
350
        : mTitle(std::move(title)), mAlbum(std::move(album)), mArtist(std::move(artist)),
351
          mTrackNumber(trackNumber), mDiscNumber(discNumber), mEntryType(entryType) {
352 353
    }

Jerome Guidon's avatar
Jerome Guidon committed
354
    MediaPlayListEntry(qulonglong id, QVariant title, QVariant artist, QVariant album, QVariant trackNumber, QVariant discNumber, ElisaUtils::PlayListEntryType entryType = ElisaUtils::Unknown)
355
        : mTitle(std::move(title)), mAlbum(std::move(album)), mArtist(std::move(artist)),
Jerome Guidon's avatar
Jerome Guidon committed
356
          mTrackNumber(trackNumber), mDiscNumber(discNumber), mId(id), mEntryType(entryType) {
357 358
    }

359
    explicit MediaPlayListEntry(const MusicAudioTrack &track)
360 361
        : mTitle(track.title()), mAlbum(track.albumName()), mTrackNumber(track.trackNumber()),
          mDiscNumber(track.discNumber()), mId(track.databaseId()), mIsValid(true) {
362 363
    }

364
    explicit MediaPlayListEntry(const MediaPlayList::TrackDataType &track)
365 366 367 368 369 370 371 372
        : mTitle(track[DatabaseInterface::TitleRole]),
          mAlbum(track[DatabaseInterface::AlbumRole]),
          mTrackNumber(track[DatabaseInterface::TrackNumberRole]),
          mDiscNumber(track[DatabaseInterface::DiscNumberRole]),
          mId(track[DatabaseInterface::DatabaseIdRole].toULongLong()),
          mIsValid(true) {
    }

373
    explicit MediaPlayListEntry(QString artist) : mArtist(std::move(artist)), mEntryType(ElisaUtils::Artist) {
374 375
    }

376 377 378
    explicit MediaPlayListEntry(QUrl fileName) : mTrackUrl(std::move(fileName)) {
    }

379 380
    explicit MediaPlayListEntry(qulonglong id,
                                const QString &entryTitle,
381 382
                                ElisaUtils::PlayListEntryType type)
        : mTitle(entryTitle), mId(id), mIsValid(type == ElisaUtils::Track), mEntryType(type) {
383 384
    }

385
    QVariant mTitle;
386

387
    QVariant mAlbum;
388

389
    QVariant mArtist;
390

391
    QVariant mTrackUrl;
392

393
    QVariant mTrackNumber;
394

395
    QVariant mDiscNumber;
396

397 398 399 400
    qulonglong mId = 0;

    bool mIsValid = false;

401
    ElisaUtils::PlayListEntryType mEntryType = ElisaUtils::PlayListEntryType::Unknown;
402 403 404 405 406

    MediaPlayList::PlayState mIsPlaying = MediaPlayList::NotPlaying;

};

407
QDebug operator<<(const QDebug &stream, const MediaPlayListEntry &data);
408

409 410


411
#endif // MEDIAPLAYLIST_H