diff --git a/autotests/mediaplaylisttest.h b/autotests/mediaplaylisttest.h --- a/autotests/mediaplaylisttest.h +++ b/autotests/mediaplaylisttest.h @@ -137,6 +137,10 @@ void clearPlayListCase(); + void undoClearPlayListCase(); + + void undoReplacePlayListCase(); + }; class MediaPlayList; diff --git a/autotests/mediaplaylisttest.cpp b/autotests/mediaplaylisttest.cpp --- a/autotests/mediaplaylisttest.cpp +++ b/autotests/mediaplaylisttest.cpp @@ -396,6 +396,441 @@ QCOMPARE(myPlayList.currentTrack().isValid(), false); } +void MediaPlayListTest::undoClearPlayListCase() +{ + MediaPlayList myPlayList; + QAbstractItemModelTester testModel(&myPlayList); + DatabaseInterface myDatabaseContent; + TracksListener myListener(&myDatabaseContent); + + QSignalSpy rowsAboutToBeMovedSpy(&myPlayList, &MediaPlayList::rowsAboutToBeMoved); + QSignalSpy rowsAboutToBeRemovedSpy(&myPlayList, &MediaPlayList::rowsAboutToBeRemoved); + QSignalSpy rowsAboutToBeInsertedSpy(&myPlayList, &MediaPlayList::rowsAboutToBeInserted); + QSignalSpy rowsMovedSpy(&myPlayList, &MediaPlayList::rowsMoved); + QSignalSpy rowsRemovedSpy(&myPlayList, &MediaPlayList::rowsRemoved); + QSignalSpy rowsInsertedSpy(&myPlayList, &MediaPlayList::rowsInserted); + QSignalSpy tracksCountChangedSpy(&myPlayList, &MediaPlayList::tracksCountChanged); + QSignalSpy persistentStateChangedSpy(&myPlayList, &MediaPlayList::persistentStateChanged); + QSignalSpy dataChangedSpy(&myPlayList, &MediaPlayList::dataChanged); + QSignalSpy newTrackByNameInListSpy(&myPlayList, &MediaPlayList::newTrackByNameInList); + QSignalSpy newEntryInListSpy(&myPlayList, &MediaPlayList::newEntryInList); + QSignalSpy currentTrackChangedSpy(&myPlayList, &MediaPlayList::currentTrackChanged); + QSignalSpy displayUndoInlineSpy(&myPlayList, &MediaPlayList::displayUndoInline); + + QCOMPARE(rowsAboutToBeRemovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeMovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeInsertedSpy.count(), 0); + QCOMPARE(rowsRemovedSpy.count(), 0); + QCOMPARE(rowsMovedSpy.count(), 0); + QCOMPARE(rowsInsertedSpy.count(), 0); + QCOMPARE(tracksCountChangedSpy.count(), 0); + QCOMPARE(persistentStateChangedSpy.count(), 0); + QCOMPARE(dataChangedSpy.count(), 0); + QCOMPARE(newTrackByNameInListSpy.count(), 0); + QCOMPARE(newEntryInListSpy.count(), 0); + QCOMPARE(currentTrackChangedSpy.count(), 0); + + myDatabaseContent.init(QStringLiteral("testDbDirectContent")); + + connect(&myListener, &TracksListener::trackHasChanged, + &myPlayList, &MediaPlayList::trackChanged, + Qt::QueuedConnection); + connect(&myListener, &TracksListener::tracksListAdded, + &myPlayList, &MediaPlayList::tracksListAdded, + Qt::QueuedConnection); + connect(&myPlayList, &MediaPlayList::newTrackByNameInList, + &myListener, &TracksListener::trackByNameInList, + Qt::QueuedConnection); + connect(&myPlayList, &MediaPlayList::newEntryInList, + &myListener, &TracksListener::newEntryInList, + Qt::QueuedConnection); + connect(&myDatabaseContent, &DatabaseInterface::tracksAdded, + &myListener, &TracksListener::tracksAdded); + + myDatabaseContent.insertTracksList(mNewTracks, mNewCovers); + + QCOMPARE(rowsAboutToBeRemovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeMovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeInsertedSpy.count(), 0); + QCOMPARE(rowsRemovedSpy.count(), 0); + QCOMPARE(rowsMovedSpy.count(), 0); + QCOMPARE(rowsInsertedSpy.count(), 0); + QCOMPARE(tracksCountChangedSpy.count(), 0); + QCOMPARE(persistentStateChangedSpy.count(), 0); + QCOMPARE(dataChangedSpy.count(), 0); + QCOMPARE(newTrackByNameInListSpy.count(), 0); + QCOMPARE(newEntryInListSpy.count(), 0); + QCOMPARE(currentTrackChangedSpy.count(), 0); + + myPlayList.enqueue({myDatabaseContent.albumIdFromTitleAndArtist(QStringLiteral("album2"), QStringLiteral("artist1")), + QStringLiteral("album2")}, + ElisaUtils::Album); + + QVERIFY(dataChangedSpy.wait()); + + QCOMPARE(rowsAboutToBeRemovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeMovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeInsertedSpy.count(), 2); + QCOMPARE(rowsRemovedSpy.count(), 0); + QCOMPARE(rowsMovedSpy.count(), 0); + QCOMPARE(rowsInsertedSpy.count(), 2); + QCOMPARE(tracksCountChangedSpy.count(), 2); + QCOMPARE(persistentStateChangedSpy.count(), 2); + QCOMPARE(dataChangedSpy.count(), 1); + QCOMPARE(newTrackByNameInListSpy.count(), 0); + QCOMPARE(newEntryInListSpy.count(), 1); + QCOMPARE(currentTrackChangedSpy.count(), 1); + + QCOMPARE(myPlayList.rowCount(), 6); + + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track1")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::TrackNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 5); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track2")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::TrackNumberRole).toInt(), 2); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 6); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track3")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::TrackNumberRole).toInt(), 3); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 7); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track4")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::TrackNumberRole).toInt(), 4); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 8); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track5")); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::TrackNumberRole).toInt(), 5); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 9); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track6")); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1 and artist2")); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::TrackNumberRole).toInt(), 6); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 10); + + QCOMPARE(myPlayList.currentTrack(), QPersistentModelIndex(myPlayList.index(0, 0))); + + myPlayList.clearPlayList(); + + QCOMPARE(rowsAboutToBeRemovedSpy.count(), 1); + QCOMPARE(rowsAboutToBeMovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeInsertedSpy.count(), 2); + QCOMPARE(rowsRemovedSpy.count(), 1); + QCOMPARE(rowsMovedSpy.count(), 0); + QCOMPARE(rowsInsertedSpy.count(), 2); + QCOMPARE(tracksCountChangedSpy.count(), 3); + QCOMPARE(persistentStateChangedSpy.count(), 3); + QCOMPARE(dataChangedSpy.count(), 1); + QCOMPARE(newTrackByNameInListSpy.count(), 0); + QCOMPARE(newEntryInListSpy.count(), 1); + QCOMPARE(currentTrackChangedSpy.count(), 2); + + QCOMPARE(myPlayList.rowCount(), 0); + + QCOMPARE(myPlayList.currentTrack().isValid(), false); + + myPlayList.undoClearPlayList(); + + QVERIFY(dataChangedSpy.wait()); + + QCOMPARE(rowsAboutToBeRemovedSpy.count(), 1); + QCOMPARE(rowsAboutToBeMovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeInsertedSpy.count(), 3); + QCOMPARE(rowsRemovedSpy.count(), 1); + QCOMPARE(rowsMovedSpy.count(), 0); + QCOMPARE(rowsInsertedSpy.count(), 3); + QCOMPARE(tracksCountChangedSpy.count(), 4); + QCOMPARE(persistentStateChangedSpy.count(), 4); + QCOMPARE(dataChangedSpy.count(), 8); + QCOMPARE(newTrackByNameInListSpy.count(), 0); + QCOMPARE(newEntryInListSpy.count(), 7); + QCOMPARE(currentTrackChangedSpy.count(), 3); + QCOMPARE(displayUndoInlineSpy.count(), 1); + + QCOMPARE(myPlayList.rowCount(), 6); + + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track1")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::TrackNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 5); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track2")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::TrackNumberRole).toInt(), 2); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 6); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track3")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::TrackNumberRole).toInt(), 3); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 7); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track4")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::TrackNumberRole).toInt(), 4); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 8); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track5")); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::TrackNumberRole).toInt(), 5); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 9); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track6")); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1 and artist2")); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::TrackNumberRole).toInt(), 6); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 10); + + QCOMPARE(myPlayList.currentTrack(), QPersistentModelIndex(myPlayList.index(0, 0))); +} + +void MediaPlayListTest::undoReplacePlayListCase() +{ + MediaPlayList myPlayList; + QAbstractItemModelTester testModel(&myPlayList); + DatabaseInterface myDatabaseContent; + TracksListener myListener(&myDatabaseContent); + + QSignalSpy rowsAboutToBeMovedSpy(&myPlayList, &MediaPlayList::rowsAboutToBeMoved); + QSignalSpy rowsAboutToBeRemovedSpy(&myPlayList, &MediaPlayList::rowsAboutToBeRemoved); + QSignalSpy rowsAboutToBeInsertedSpy(&myPlayList, &MediaPlayList::rowsAboutToBeInserted); + QSignalSpy rowsMovedSpy(&myPlayList, &MediaPlayList::rowsMoved); + QSignalSpy rowsRemovedSpy(&myPlayList, &MediaPlayList::rowsRemoved); + QSignalSpy rowsInsertedSpy(&myPlayList, &MediaPlayList::rowsInserted); + QSignalSpy tracksCountChangedSpy(&myPlayList, &MediaPlayList::tracksCountChanged); + QSignalSpy persistentStateChangedSpy(&myPlayList, &MediaPlayList::persistentStateChanged); + QSignalSpy dataChangedSpy(&myPlayList, &MediaPlayList::dataChanged); + QSignalSpy newTrackByNameInListSpy(&myPlayList, &MediaPlayList::newTrackByNameInList); + QSignalSpy newEntryInListSpy(&myPlayList, &MediaPlayList::newEntryInList); + QSignalSpy currentTrackChangedSpy(&myPlayList, &MediaPlayList::currentTrackChanged); + QSignalSpy displayUndoInlineSpy(&myPlayList, &MediaPlayList::displayUndoInline); + + QCOMPARE(rowsAboutToBeRemovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeMovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeInsertedSpy.count(), 0); + QCOMPARE(rowsRemovedSpy.count(), 0); + QCOMPARE(rowsMovedSpy.count(), 0); + QCOMPARE(rowsInsertedSpy.count(), 0); + QCOMPARE(tracksCountChangedSpy.count(), 0); + QCOMPARE(persistentStateChangedSpy.count(), 0); + QCOMPARE(dataChangedSpy.count(), 0); + QCOMPARE(newTrackByNameInListSpy.count(), 0); + QCOMPARE(newEntryInListSpy.count(), 0); + QCOMPARE(currentTrackChangedSpy.count(), 0); + + myDatabaseContent.init(QStringLiteral("testDbDirectContent")); + + connect(&myListener, &TracksListener::trackHasChanged, + &myPlayList, &MediaPlayList::trackChanged, + Qt::QueuedConnection); + connect(&myListener, &TracksListener::tracksListAdded, + &myPlayList, &MediaPlayList::tracksListAdded, + Qt::QueuedConnection); + connect(&myPlayList, &MediaPlayList::newTrackByNameInList, + &myListener, &TracksListener::trackByNameInList, + Qt::QueuedConnection); + connect(&myPlayList, &MediaPlayList::newEntryInList, + &myListener, &TracksListener::newEntryInList, + Qt::QueuedConnection); + connect(&myDatabaseContent, &DatabaseInterface::tracksAdded, + &myListener, &TracksListener::tracksAdded); + + myDatabaseContent.insertTracksList(mNewTracks, mNewCovers); + + QCOMPARE(rowsAboutToBeRemovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeMovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeInsertedSpy.count(), 0); + QCOMPARE(rowsRemovedSpy.count(), 0); + QCOMPARE(rowsMovedSpy.count(), 0); + QCOMPARE(rowsInsertedSpy.count(), 0); + QCOMPARE(tracksCountChangedSpy.count(), 0); + QCOMPARE(persistentStateChangedSpy.count(), 0); + QCOMPARE(dataChangedSpy.count(), 0); + QCOMPARE(newTrackByNameInListSpy.count(), 0); + QCOMPARE(newEntryInListSpy.count(), 0); + QCOMPARE(currentTrackChangedSpy.count(), 0); + + myPlayList.enqueue({myDatabaseContent.albumIdFromTitleAndArtist(QStringLiteral("album2"), QStringLiteral("artist1")), + QStringLiteral("album2")}, + ElisaUtils::Album); + + QVERIFY(dataChangedSpy.wait()); + + QCOMPARE(rowsAboutToBeRemovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeMovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeInsertedSpy.count(), 2); + QCOMPARE(rowsRemovedSpy.count(), 0); + QCOMPARE(rowsMovedSpy.count(), 0); + QCOMPARE(rowsInsertedSpy.count(), 2); + QCOMPARE(tracksCountChangedSpy.count(), 2); + QCOMPARE(persistentStateChangedSpy.count(), 2); + QCOMPARE(dataChangedSpy.count(), 1); + QCOMPARE(newTrackByNameInListSpy.count(), 0); + QCOMPARE(newEntryInListSpy.count(), 1); + QCOMPARE(currentTrackChangedSpy.count(), 1); + + QCOMPARE(myPlayList.rowCount(), 6); + + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track1")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::TrackNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 5); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track2")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::TrackNumberRole).toInt(), 2); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 6); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track3")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::TrackNumberRole).toInt(), 3); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 7); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track4")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::TrackNumberRole).toInt(), 4); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 8); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track5")); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::TrackNumberRole).toInt(), 5); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 9); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track6")); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1 and artist2")); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::TrackNumberRole).toInt(), 6); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 10); + + QCOMPARE(myPlayList.currentTrack(), QPersistentModelIndex(myPlayList.index(0, 0))); + + myPlayList.enqueue({myDatabaseContent.albumIdFromTitleAndArtist(QStringLiteral("album1"), QStringLiteral("Various Artists")), + QStringLiteral("album1")}, + ElisaUtils::Album, + ElisaUtils::ReplacePlayList, + ElisaUtils::TriggerPlay); + + QVERIFY(dataChangedSpy.wait()); + + QCOMPARE(rowsAboutToBeRemovedSpy.count(), 1); + QCOMPARE(rowsAboutToBeMovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeInsertedSpy.count(), 4); + QCOMPARE(rowsRemovedSpy.count(), 1); + QCOMPARE(rowsMovedSpy.count(), 0); + QCOMPARE(rowsInsertedSpy.count(), 4); + QCOMPARE(persistentStateChangedSpy.count(), 5); + QCOMPARE(dataChangedSpy.count(), 2); + QCOMPARE(newTrackByNameInListSpy.count(), 0); + QCOMPARE(newEntryInListSpy.count(), 2); + + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track1")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album1")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::TrackNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track2")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album1")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist2")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::TrackNumberRole).toInt(), 2); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::DiscNumberRole).toInt(), 2); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 2); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track3")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album1")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist3")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::TrackNumberRole).toInt(), 3); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::DiscNumberRole).toInt(), 3); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 3); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track4")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album1")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist4")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::TrackNumberRole).toInt(), 4); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::DiscNumberRole).toInt(), 4); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 4); + + myPlayList.undoClearPlayList(); + + QVERIFY(dataChangedSpy.wait()); + + QCOMPARE(rowsAboutToBeRemovedSpy.count(), 2); + QCOMPARE(rowsAboutToBeMovedSpy.count(), 0); + QCOMPARE(rowsAboutToBeInsertedSpy.count(), 5); + QCOMPARE(rowsRemovedSpy.count(), 2); + QCOMPARE(rowsMovedSpy.count(), 0); + QCOMPARE(rowsInsertedSpy.count(), 5); + QCOMPARE(tracksCountChangedSpy.count(), 7); + QCOMPARE(persistentStateChangedSpy.count(), 7); + QCOMPARE(dataChangedSpy.count(), 9); + QCOMPARE(newTrackByNameInListSpy.count(), 0); + QCOMPARE(newEntryInListSpy.count(), 8); + QCOMPARE(currentTrackChangedSpy.count(), 5); + QCOMPARE(displayUndoInlineSpy.count(), 2); + + QCOMPARE(myPlayList.rowCount(), 6); + + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track1")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::TrackNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(0, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 5); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track2")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::TrackNumberRole).toInt(), 2); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(1, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 6); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track3")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::TrackNumberRole).toInt(), 3); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(2, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 7); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track4")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::TrackNumberRole).toInt(), 4); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(3, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 8); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track5")); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1")); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::TrackNumberRole).toInt(), 5); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(4, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 9); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::TitleRole).toString(), QStringLiteral("track6")); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::AlbumRole).toString(), QStringLiteral("album2")); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::ArtistRole).toString(), QStringLiteral("artist1 and artist2")); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::TrackNumberRole).toInt(), 6); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::DiscNumberRole).toInt(), 1); + QCOMPARE(myPlayList.data(myPlayList.index(5, 0), MediaPlayList::MilliSecondsDurationRole).toInt(), 10); + + QCOMPARE(myPlayList.currentTrack(), QPersistentModelIndex(myPlayList.index(0, 0))); +} + void MediaPlayListTest::enqueueArtistCase() { MediaPlayList myPlayList; diff --git a/src/audiowrapper.h b/src/audiowrapper.h --- a/src/audiowrapper.h +++ b/src/audiowrapper.h @@ -142,6 +142,10 @@ void setPosition(qint64 position); + void saveUndoPosition(qint64 position); + + void restoreUndoPosition(); + void play(); void pause(); @@ -163,6 +167,7 @@ void playerVolumeChanged(); private: + void savePosition(qint64 position); void playerStateSignalChanges(QMediaPlayer::State newState); diff --git a/src/audiowrapper_libvlc.cpp b/src/audiowrapper_libvlc.cpp --- a/src/audiowrapper_libvlc.cpp +++ b/src/audiowrapper_libvlc.cpp @@ -59,6 +59,8 @@ qint64 mSavedPosition = 0.0; + qint64 mUndoSavedPosition = 0.0; + qint64 mPreviousPosition = 0; QMediaPlayer::Error mError = QMediaPlayer::NoError; @@ -261,17 +263,33 @@ } if (d->mMediaDuration == -1 || d->mMediaDuration == 0) { - if (!d->mHasSavedPosition) { - d->mHasSavedPosition = true; - d->mSavedPosition = position; - qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapper::setPosition" << "restore old position" << d->mSavedPosition; - } + savePosition(position); return; } libvlc_media_player_set_position(d->mPlayer, static_cast(position) / d->mMediaDuration); } +void AudioWrapper::savePosition(qint64 position) +{ + if (!d->mHasSavedPosition) { + d->mHasSavedPosition = true; + d->mSavedPosition = position; + qCDebug(orgKdeElisaPlayerVlc) << "AudioWrapper::savePosition" << "restore old position" << d->mSavedPosition; + } +} + +void AudioWrapper::saveUndoPosition(qint64 position) +{ + d->mUndoSavedPosition = position; +} + +void AudioWrapper::restoreUndoPosition() +{ + d->mHasSavedPosition = true; + d->mSavedPosition = d->mUndoSavedPosition; +} + void AudioWrapper::play() { if (!d->mPlayer) { diff --git a/src/elisaapplication.cpp b/src/elisaapplication.cpp --- a/src/elisaapplication.cpp +++ b/src/elisaapplication.cpp @@ -353,6 +353,8 @@ QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::playerPause, d->mAudioWrapper.get(), &AudioWrapper::pause); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::playerStop, d->mAudioWrapper.get(), &AudioWrapper::stop); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::seek, d->mAudioWrapper.get(), &AudioWrapper::seek); + QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::saveUndoPositionInAudioWrapper, d->mAudioWrapper.get(), &AudioWrapper::saveUndoPosition); + QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::restoreUndoPositionInAudioWrapper, d->mAudioWrapper.get(), &AudioWrapper::restoreUndoPosition); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::skipNextTrack, d->mMediaPlayList.get(), &MediaPlayList::skipNextTrack); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::sourceInError, d->mMediaPlayList.get(), &MediaPlayList::trackInError); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::sourceInError, d->mMusicManager.get(), &MusicListenersManager::playBackError); @@ -363,6 +365,9 @@ QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::ensurePlay, d->mAudioControl.get(), &ManageAudioPlayer::ensurePlay); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::playListFinished, d->mAudioControl.get(), &ManageAudioPlayer::playListFinished); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::currentTrackChanged, d->mAudioControl.get(), &ManageAudioPlayer::setCurrentTrack); + QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::clearPlayListPlayer, d->mAudioControl.get(), &ManageAudioPlayer::saveForUndoClearPlaylist); + QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::undoClearPlayListPlayer, d->mAudioControl.get(), &ManageAudioPlayer::restoreForUndoClearPlaylist); + QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::playbackStateChanged, d->mAudioControl.get(), &ManageAudioPlayer::setPlayerPlaybackState); diff --git a/src/manageaudioplayer.h b/src/manageaudioplayer.h --- a/src/manageaudioplayer.h +++ b/src/manageaudioplayer.h @@ -187,6 +187,10 @@ void seek(qint64 position); + void saveUndoPositionInAudioWrapper(qint64 position); + + void restoreUndoPositionInAudioWrapper(); + void titleRoleChanged(); void artistNameRoleChanged(); @@ -203,6 +207,10 @@ void setCurrentTrack(const QPersistentModelIndex ¤tTrack); + void saveForUndoClearPlaylist(); + + void restoreForUndoClearPlaylist(); + void setPlayListModel(QAbstractItemModel* aPlayListModel); void setUrlRole(int value); @@ -295,6 +303,10 @@ QVariantMap mPersistentState; + bool mUndoPlayingState = false; + + qint64 mUndoPlayerPosition = 0; + }; #endif // MANAGEAUDIOPLAYER_H diff --git a/src/manageaudioplayer.cpp b/src/manageaudioplayer.cpp --- a/src/manageaudioplayer.cpp +++ b/src/manageaudioplayer.cpp @@ -166,6 +166,21 @@ } } +void ManageAudioPlayer::saveForUndoClearPlaylist(){ + mUndoPlayingState = mPlayingState; + + mUndoPlayerPosition = mPlayerPosition; + Q_EMIT saveUndoPositionInAudioWrapper(mUndoPlayerPosition); +} + +void ManageAudioPlayer::restoreForUndoClearPlaylist(){ + mPlayerPosition = mUndoPlayerPosition; + Q_EMIT seek(mPlayerPosition); + + mPlayingState = mUndoPlayingState; + Q_EMIT restoreUndoPositionInAudioWrapper(); +} + void ManageAudioPlayer::setPlayListModel(QAbstractItemModel *aPlayListModel) { if (mPlayListModel == aPlayListModel) { diff --git a/src/mediaplaylist.h b/src/mediaplaylist.h --- a/src/mediaplaylist.h +++ b/src/mediaplaylist.h @@ -171,6 +171,9 @@ bool repeatPlay() const; Q_SIGNALS: + void displayUndoInline(); + + void hideUndoInline(); void newTrackByNameInList(const QString &title, const QString &artist, const QString &album, int trackNumber, int discNumber); @@ -186,6 +189,10 @@ void currentTrackChanged(QPersistentModelIndex currentTrack); + void clearPlayListPlayer(); + + void undoClearPlayListPlayer(); + void currentTrackRowChanged(); void randomPlayChanged(); @@ -256,13 +263,18 @@ void trackInError(const QUrl &sourceInError, QMediaPlayer::Error playerError); + void undoClearPlayList(); + private Q_SLOTS: void loadPlayListLoaded(); void loadPlayListLoadFailed(); private: + void displayOrHideUndoInline(bool value); + + void clearPlayList(bool prepareUndo); void resetCurrentTrack(); @@ -284,8 +296,13 @@ void enqueueMultipleEntries(const ElisaUtils::EntryDataList &entriesData, ElisaUtils::PlayListEntryType type); + void enqueueCommon(); + + void copyD(); + std::unique_ptr d; + std::unique_ptr dOld; }; class MediaPlayListEntry @@ -297,9 +314,9 @@ explicit MediaPlayListEntry(qulonglong id) : mId(id), mIsValid(true) { } - MediaPlayListEntry(QString title, QString artist, QString album, int trackNumber, int discNumber) + MediaPlayListEntry(QString title, QString artist, QString album, int trackNumber, int discNumber, ElisaUtils::PlayListEntryType entryType = ElisaUtils::Unknown) : mTitle(std::move(title)), mAlbum(std::move(album)), mArtist(std::move(artist)), - mTrackNumber(trackNumber), mDiscNumber(discNumber) { + mTrackNumber(trackNumber), mDiscNumber(discNumber), mEntryType(entryType) { } explicit MediaPlayListEntry(const MusicAudioTrack &track) diff --git a/src/mediaplaylist.cpp b/src/mediaplaylist.cpp --- a/src/mediaplaylist.cpp +++ b/src/mediaplaylist.cpp @@ -53,9 +53,11 @@ bool mRepeatPlay = false; + bool mForceUndo = false; + }; -MediaPlayList::MediaPlayList(QObject *parent) : QAbstractListModel(parent), d(new MediaPlayListPrivate) +MediaPlayList::MediaPlayList(QObject *parent) : QAbstractListModel(parent), d(new MediaPlayListPrivate), dOld(new MediaPlayListPrivate) { connect(&d->mLoadPlaylist, &QMediaPlaylist::loaded, this, &MediaPlayList::loadPlayListLoaded); connect(&d->mLoadPlaylist, &QMediaPlaylist::loadFailed, this, &MediaPlayList::loadPlayListLoadFailed); @@ -309,6 +311,8 @@ void MediaPlayList::enqueueRestoredEntry(const MediaPlayListEntry &newEntry) { + enqueueCommon(); + beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size()); d->mData.push_back(newEntry); d->mTrackData.push_back({}); @@ -355,8 +359,13 @@ void MediaPlayList::enqueueArtist(const QString &artistName) { + enqueueCommon(); + + auto newEntry = MediaPlayListEntry{artistName}; + newEntry.mEntryType = ElisaUtils::Artist; + beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size()); - d->mData.push_back(MediaPlayListEntry{artistName}); + d->mData.push_back(newEntry); d->mTrackData.push_back({}); endInsertRows(); @@ -366,15 +375,18 @@ } Q_EMIT tracksCountChanged(); - Q_EMIT newEntryInList(0, artistName, ElisaUtils::Artist); + Q_EMIT newEntryInList(0, artistName, newEntry.mEntryType); Q_EMIT persistentStateChanged(); } void MediaPlayList::enqueueFilesList(const ElisaUtils::EntryDataList &newEntries) { + enqueueCommon(); + beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size() + newEntries.size() - 1); for (const auto &oneTrackUrl : newEntries) { auto newEntry = MediaPlayListEntry(QUrl::fromLocalFile(std::get<1>(oneTrackUrl))); + newEntry.mEntryType = ElisaUtils::FileName; d->mData.push_back(newEntry); d->mTrackData.push_back({}); if (newEntry.mTrackUrl.isValid()) { @@ -385,7 +397,7 @@ if (newTrackFile.exists()) { d->mData.last().mIsValid = true; } - Q_EMIT newEntryInList(0, entryString, ElisaUtils::FileName); + Q_EMIT newEntryInList(0, entryString, newEntry.mEntryType); } } } @@ -404,11 +416,14 @@ void MediaPlayList::enqueueTracksListById(const ElisaUtils::EntryDataList &newEntries) { + enqueueCommon(); + beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size() + newEntries.size() - 1); for (const auto &newTrack : newEntries) { - d->mData.push_back(MediaPlayListEntry{std::get<0>(newTrack)}); + auto newMediaPlayListEntry = MediaPlayListEntry{std::get<0>(newTrack), std::get<1>(newTrack), ElisaUtils::Track}; + d->mData.push_back(newMediaPlayListEntry); d->mTrackData.push_back({}); - Q_EMIT newEntryInList(std::get<0>(newTrack), std::get<1>(newTrack), ElisaUtils::Track); + Q_EMIT newEntryInList(newMediaPlayListEntry.mId, newMediaPlayListEntry.mTitle.toString(), newMediaPlayListEntry.mEntryType); } endInsertRows(); @@ -425,6 +440,8 @@ void MediaPlayList::enqueueOneEntry(const ElisaUtils::EntryData &entryData, ElisaUtils::PlayListEntryType type) { + enqueueCommon(); + beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size()); d->mData.push_back(MediaPlayListEntry{std::get<0>(entryData), std::get<1>(entryData), type}); d->mTrackData.push_back({}); @@ -437,6 +454,8 @@ void MediaPlayList::enqueueMultipleEntries(const ElisaUtils::EntryDataList &entriesData, ElisaUtils::PlayListEntryType type) { + enqueueCommon(); + beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size() + entriesData.size() - 1); for (const auto &entryData : entriesData) { d->mData.push_back(MediaPlayListEntry{std::get<0>(entryData), std::get<1>(entryData), type}); @@ -455,12 +474,17 @@ enqueue(newEntry, databaseIdType, ElisaUtils::PlayListEnqueueMode::ReplacePlayList, ElisaUtils::PlayListEnqueueTriggerPlay::TriggerPlay); } -void MediaPlayList::clearPlayList() +void MediaPlayList::clearPlayList(bool prepareUndo) { if (d->mData.isEmpty()) { return; } + if(prepareUndo){ + Q_EMIT clearPlayListPlayer(); + this->copyD(); + } + beginRemoveRows({}, 0, d->mData.count() - 1); d->mData.clear(); d->mTrackData.clear(); @@ -470,8 +494,81 @@ d->mCurrentTrack = QPersistentModelIndex{}; notifyCurrentTrackChanged(); + displayOrHideUndoInline(true); + Q_EMIT tracksCountChanged(); + Q_EMIT persistentStateChanged(); +} + +void MediaPlayList::clearPlayList() +{ + this->clearPlayList(true); +} + +void MediaPlayList::undoClearPlayList() +{ + clearPlayList(false); + + beginInsertRows(QModelIndex(), d->mData.size(), d->mData.size() + dOld->mData.size() - 1); + for (auto &newTrack : dOld->mData) { + d->mData.push_back(newTrack); + d->mTrackData.push_back({}); + + if (ElisaUtils::FileName == newTrack.mEntryType && newTrack.mTrackUrl.isValid()) { + auto entryURL = newTrack.mTrackUrl.toUrl(); + if (entryURL.isLocalFile()) { + auto entryString = entryURL.toLocalFile(); + QFileInfo newTrackFile(entryString); + if (newTrackFile.exists()) { + d->mData.last().mIsValid = true; + } + Q_EMIT newEntryInList(0, entryString, newTrack.mEntryType); + } + } + else if(ElisaUtils::Artist == newTrack.mEntryType){ + Q_EMIT newEntryInList(0, newTrack.mArtist.toString(), newTrack.mEntryType); + } + else{ + Q_EMIT newEntryInList(newTrack.mId, newTrack.mTitle.toString(), newTrack.mEntryType); + } + } + endInsertRows(); + + d->mMusicListenersManager = dOld->mMusicListenersManager; + d->mPersistentState = dOld->mPersistentState; + d->mCurrentPlayListPosition = dOld->mCurrentPlayListPosition; + d->mRandomPlay = dOld->mRandomPlay; + d->mRepeatPlay = dOld->mRepeatPlay; + + auto candidateTrack = index(dOld->mCurrentPlayListPosition, 0); + + if (candidateTrack.isValid() && candidateTrack.data(ColumnsRoles::IsValidRole).toBool()) { + d->mCurrentTrack = candidateTrack; + notifyCurrentTrackChanged(); + } + Q_EMIT tracksCountChanged(); Q_EMIT persistentStateChanged(); + + Q_EMIT dataChanged(index(rowCount() - 1, 0), index(rowCount() - 1, 0), {MediaPlayList::IsPlayingRole}); + displayOrHideUndoInline(false); + Q_EMIT undoClearPlayListPlayer(); +} + +void MediaPlayList::enqueueCommon() +{ + displayOrHideUndoInline(false); +} + +void MediaPlayList::copyD() +{ + dOld->mData = d->mData; + dOld->mTrackData = d->mTrackData; + dOld->mMusicListenersManager = d->mMusicListenersManager; + dOld->mCurrentTrack = d->mCurrentTrack; + dOld->mPersistentState = d->mPersistentState; + dOld->mCurrentPlayListPosition = d->mCurrentPlayListPosition; + dOld->mRandomPlay = d->mRandomPlay; + dOld->mRepeatPlay = d->mRepeatPlay; } void MediaPlayList::loadPlaylist(const QUrl &fileName) @@ -505,9 +602,14 @@ ElisaUtils::PlayListEnqueueTriggerPlay triggerPlay) { if (enqueueMode == ElisaUtils::ReplacePlayList) { + if(d->mData.size()>0){ + d->mForceUndo = true; + } clearPlayList(); } + enqueueCommon(); + switch (databaseIdType) { case ElisaUtils::Album: @@ -528,6 +630,10 @@ if (triggerPlay == ElisaUtils::TriggerPlay) { Q_EMIT ensurePlay(); } + + if (enqueueMode == ElisaUtils::ReplacePlayList) { + d->mForceUndo = false; + } } void MediaPlayList::enqueue(const ElisaUtils::EntryDataList &newEntries, @@ -540,9 +646,14 @@ } if (enqueueMode == ElisaUtils::ReplacePlayList) { + if(d->mData.size()>0){ + d->mForceUndo = true; + } clearPlayList(); } + enqueueCommon(); + switch (databaseIdType) { case ElisaUtils::Track: @@ -565,6 +676,10 @@ if (triggerPlay == ElisaUtils::TriggerPlay) { Q_EMIT ensurePlay(); } + + if (enqueueMode == ElisaUtils::ReplacePlayList) { + d->mForceUndo = false; + } } bool MediaPlayList::savePlaylist(const QUrl &fileName) @@ -598,6 +713,7 @@ oneData.push_back(oneTrack.album()); oneData.push_back(QString::number(oneTrack.trackNumber())); oneData.push_back(QString::number(oneTrack.discNumber())); + oneData.push_back(QString::number(oneEntry.mEntryType)); result.push_back(QVariant(oneData)); } @@ -655,7 +771,7 @@ for (auto &oneData : persistentState) { auto trackData = oneData.toStringList(); - if (trackData.size() != 5) { + if (trackData.size() != 6) { continue; } @@ -665,7 +781,9 @@ auto restoredTrackNumber = trackData[3].toInt(); auto restoredDiscNumber = trackData[4].toInt(); - enqueueRestoredEntry({restoredTitle, restoredArtist, restoredAlbum, restoredTrackNumber, restoredDiscNumber}); + ElisaUtils::PlayListEntryType mEntryType = static_cast(trackData[5].toInt()); + + enqueueRestoredEntry({restoredTitle, restoredArtist, restoredAlbum, restoredTrackNumber, restoredDiscNumber, mEntryType}); } restorePlayListPosition(); @@ -717,7 +835,9 @@ if (tracks.size() > 1) { beginInsertRows(QModelIndex(), playListIndex + 1, playListIndex - 1 + tracks.size()); for (int trackIndex = 1; trackIndex < tracks.size(); ++trackIndex) { - d->mData.push_back(MediaPlayListEntry{tracks[trackIndex].databaseId()}); + auto newEntry = MediaPlayListEntry{tracks[trackIndex]}; + newEntry.mEntryType = ElisaUtils::Track; + d->mData.push_back(newEntry); d->mTrackData.push_back(tracks[trackIndex]); } endInsertRows(); @@ -875,6 +995,17 @@ Q_EMIT repeatPlayChanged(); } +void MediaPlayList::displayOrHideUndoInline(bool value) +{ + if(value){ + Q_EMIT displayUndoInline(); + }else { + if(!d->mForceUndo){ + Q_EMIT hideUndoInline(); + } + } +} + void MediaPlayList::skipNextTrack() { if (!d->mCurrentTrack.isValid()) { diff --git a/src/qml/MediaPlayListView.qml b/src/qml/MediaPlayListView.qml --- a/src/qml/MediaPlayListView.qml +++ b/src/qml/MediaPlayListView.qml @@ -21,6 +21,7 @@ import QtQuick.Layouts 1.1 import QtQuick.Window 2.2 import Qt.labs.platform 1.0 as PlatformDialog +import org.kde.kirigami 2.5 as Kirigami import org.kde.elisa 1.0 FocusScope { @@ -161,14 +162,20 @@ ColumnLayout { id: emptyPlaylistText spacing: 0 - visible: elisa.mediaPlayList ? elisa.mediaPlayList.tracksCount === 0 : true + visible: true Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Layout.fillHeight: true Layout.fillWidth: true - Item { Layout.fillHeight: true } + Item { + id: emptyVisible + visible: elisa.mediaPlayList ? elisa.mediaPlayList.tracksCount === 0 : true + Layout.preferredHeight: (emptyPlaylistText.height-emptyImage.height-emptyLabel0.height-emptyLabel1.height)/2 + } Image { + id: emptyImage + visible: emptyVisible.visible Layout.alignment: Qt.AlignHCenter width: elisaTheme.gridDelegateWidth * 5 @@ -184,6 +191,8 @@ } Label { + id: emptyLabel0 + visible: emptyVisible.visible Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter Layout.rightMargin: elisaTheme.layoutHorizontalMargin @@ -197,6 +206,8 @@ } Label { + id: emptyLabel1 + visible: emptyVisible.visible Layout.topMargin: 5 Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter @@ -209,26 +220,61 @@ text: i18nc("Text shown when play list is empty", "Add some songs to get started. You can browse your music using the views on the left.") } - Item { Layout.fillHeight: true } + Item { + visible: emptyVisible.visible + Layout.fillHeight: true + } - } + PlayListBasicView { + id: playListView - PlayListBasicView { - id: playListView + visible: !emptyVisible.visible - Layout.fillWidth: true - Layout.fillHeight: true + Layout.fillWidth: true + Layout.fillHeight: true + + playListModel: elisa.mediaPlayList + + focus: true + + onStartPlayback: topItem.startPlayback() + + onPausePlayback: topItem.pausePlayback() - playListModel: elisa.mediaPlayList + onDisplayError: topItem.displayError(errorText) - focus: true + } + + Kirigami.InlineMessage { - onStartPlayback: topItem.startPlayback() + Connections { + target: elisa.mediaPlayList + onDisplayUndoInline: undoClear.visible = true + } + + Connections { + target: elisa.mediaPlayList + onHideUndoInline: undoClear.visible = false + } - onPausePlayback: topItem.pausePlayback() + id: undoClear - onDisplayError: topItem.displayError(errorText) + text: i18nc("Playlist cleared", "Playlist cleared") + type: Kirigami.MessageType.Information + showCloseButton: true + Layout.topMargin: 5 + Layout.fillWidth: true + Layout.rightMargin: elisaTheme.layoutHorizontalMargin + Layout.leftMargin: elisaTheme.layoutHorizontalMargin + actions: [ + Kirigami.Action { + text: i18nc("Undo", "Undo") + icon.name: "dialog-cancel" + onTriggered: elisa.mediaPlayList.undoClearPlayList() + } + ] + } } } }