Skip to content

Commit 1818b1c

Browse files
ronso0Swiftb0y
andcommitted
Playlists: allow to adopt current order (sorted) as playlist order
Co-authored-by: Swiftb0y <[email protected]>
1 parent 6326891 commit 1818b1c

File tree

6 files changed

+96
-5
lines changed

6 files changed

+96
-5
lines changed

src/library/dao/playlistdao.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,44 @@ int PlaylistDAO::tracksInPlaylist(const int playlistId) const {
11161116
return count;
11171117
}
11181118

1119+
void PlaylistDAO::orderTracksByCurrPos(const int playlistId,
1120+
QList<std::pair<TrackId, int>>& newOrder) {
1121+
if (newOrder.isEmpty() || playlistId == kInvalidPlaylistId) {
1122+
return;
1123+
}
1124+
if (newOrder.size() != tracksInPlaylist(playlistId)) {
1125+
return;
1126+
}
1127+
ScopedTransaction transaction(m_database);
1128+
QSqlQuery query(m_database);
1129+
query.prepare(QStringLiteral(
1130+
"UPDATE PlaylistTracks "
1131+
"SET position=:new_pos "
1132+
"WHERE position=:old_pos AND "
1133+
"track_id=:track_id AND "
1134+
"playlist_id=:pl_id"));
1135+
int newPos = 1;
1136+
for (auto [trackId, oldPos] : newOrder) {
1137+
VERIFY_OR_DEBUG_ASSERT(trackId.isValid()) {
1138+
return;
1139+
}
1140+
query.bindValue(":new_pos", newPos++);
1141+
query.bindValue(":old_pos", oldPos);
1142+
query.bindValue(":track_id", trackId.toVariant());
1143+
query.bindValue(":pl_id", playlistId);
1144+
if (!query.exec()) {
1145+
// We temporarily have duplicate positions, so abort the entire operation
1146+
// to not leave the playlist with an invalid state.
1147+
LOG_FAILED_QUERY(query);
1148+
return;
1149+
}
1150+
}
1151+
1152+
transaction.commit();
1153+
1154+
emit tracksMoved(QSet<int>{playlistId});
1155+
}
1156+
11191157
void PlaylistDAO::moveTrack(const int playlistId, const int oldPosition, const int newPosition) {
11201158
ScopedTransaction transaction(m_database);
11211159
QSqlQuery query(m_database);

src/library/dao/playlistdao.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ class PlaylistDAO : public QObject, public virtual DAO {
110110
bool copyPlaylistTracks(const int sourcePlaylistID, const int targetPlaylistID);
111111
// Returns the number of tracks in the given playlist.
112112
int tracksInPlaylist(const int playlistId) const;
113+
// This receives a track list that represents the current order (sorted by BPM for example)
114+
// and adopts this order for `position` in the playlist.
115+
// Returns true on success.
116+
void orderTracksByCurrPos(const int playlistId, QList<std::pair<TrackId, int>>& newOrder);
113117
// moved Track to a new position
114118
void moveTrack(const int playlistId,
115119
const int oldPosition, const int newPosition);

src/library/playlisttablemodel.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ void PlaylistTableModel::shuffleTracks(const QModelIndexList& shuffle, const QMo
315315
int numOfTracks = rowCount();
316316
if (shuffle.count() > 1) {
317317
// if there is more then one track selected, shuffle selection only
318-
foreach (QModelIndex shuffleIndex, shuffle) {
318+
for (const QModelIndex& shuffleIndex : std::as_const(shuffle)) {
319319
int oldPosition = shuffleIndex.sibling(shuffleIndex.row(), positionColumn).data().toInt();
320320
if (oldPosition != excludePos) {
321321
positions.append(oldPosition);
@@ -339,6 +339,23 @@ void PlaylistTableModel::shuffleTracks(const QModelIndexList& shuffle, const QMo
339339
m_pTrackCollectionManager->internalCollection()->getPlaylistDAO().shuffleTracks(m_iPlaylistId, positions, allIds);
340340
}
341341

342+
void PlaylistTableModel::orderTracksByCurrPos() {
343+
QList<std::pair<TrackId, int>> idPosList;
344+
int numOfTracks = rowCount();
345+
idPosList.reserve(numOfTracks);
346+
const int positionColumn = fieldIndex(ColumnCache::COLUMN_PLAYLISTTRACKSTABLE_POSITION);
347+
const int idColumn = fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_ID);
348+
// Set up list of all IDs
349+
for (int i = 0; i < numOfTracks; i++) {
350+
TrackId trackId(index(i, idColumn).data());
351+
int oldPosition = index(i, positionColumn).data().toInt();
352+
idPosList.append(std::make_pair(trackId, oldPosition));
353+
}
354+
m_pTrackCollectionManager->internalCollection()
355+
->getPlaylistDAO()
356+
.orderTracksByCurrPos(m_iPlaylistId, idPosList);
357+
}
358+
342359
const QList<int> PlaylistTableModel::getSelectedPositions(const QModelIndexList& indices) const {
343360
if (indices.isEmpty()) {
344361
return {};

src/library/playlisttablemodel.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ class PlaylistTableModel final : public TrackSetTableModel {
2121
bool appendTrack(TrackId trackId);
2222
void moveTrack(const QModelIndex& sourceIndex, const QModelIndex& destIndex) override;
2323
void removeTrack(const QModelIndex& index);
24-
void shuffleTracks(const QModelIndexList& shuffle, const QModelIndex& exclude);
24+
void shuffleTracks(const QModelIndexList& shuffle = QModelIndexList(),
25+
const QModelIndex& exclude = QModelIndex());
26+
void orderTracksByCurrPos();
2527

2628
bool isColumnInternal(int column) final;
2729
bool isColumnHiddenByDefault(int column) final;

src/library/trackset/playlistfeature.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ PlaylistFeature::PlaylistFeature(Library* pLibrary, UserSettingsPointer pConfig)
3939
this,
4040
&PlaylistFeature::slotShufflePlaylist);
4141

42+
m_pOrderByCurrentPosAction = make_parented<QAction>(tr("Adopt current order"), this);
43+
connect(m_pOrderByCurrentPosAction,
44+
&QAction::triggered,
45+
this,
46+
&PlaylistFeature::slotOrderTracksByCurrentPosition);
47+
4248
m_pUnlockPlaylistsAction =
4349
make_parented<QAction>(tr("Unlock all playlists"), this);
4450
connect(m_pUnlockPlaylistsAction,
@@ -81,6 +87,8 @@ void PlaylistFeature::onRightClickChild(
8187
int playlistId = playlistIdFromIndex(index);
8288

8389
bool locked = m_playlistDao.isPlaylistLocked(playlistId);
90+
m_pShufflePlaylistAction->setEnabled(!locked);
91+
m_pOrderByCurrentPosAction->setEnabled(!locked && isChildIndexSelectedInSidebar(index));
8492
m_pDeletePlaylistAction->setEnabled(!locked);
8593
m_pRenamePlaylistAction->setEnabled(!locked);
8694

@@ -92,6 +100,7 @@ void PlaylistFeature::onRightClickChild(
92100
// TODO If playlist is selected and has more than one track selected
93101
// show "Shuffle selected tracks", else show "Shuffle playlist"?
94102
menu.addAction(m_pShufflePlaylistAction);
103+
menu.addAction(m_pOrderByCurrentPosAction);
95104
menu.addSeparator();
96105
menu.addAction(m_pRenamePlaylistAction);
97106
menu.addAction(m_pDuplicatePlaylistAction);
@@ -228,17 +237,17 @@ void PlaylistFeature::slotShufflePlaylist() {
228237

229238
// Shuffle all tracks
230239
// If the playlist is loaded/visible shuffle only selected tracks
231-
QModelIndexList selection;
232240
if (isChildIndexSelectedInSidebar(m_lastRightClickedIndex) &&
233241
m_pPlaylistTableModel->getPlaylist() == playlistId) {
242+
QModelIndexList selection;
234243
if (m_pLibraryWidget) {
235244
WTrackTableView* view = dynamic_cast<WTrackTableView*>(
236245
m_pLibraryWidget->getActiveView());
237246
if (view != nullptr) {
238247
selection = view->selectionModel()->selectedIndexes();
239248
}
240249
}
241-
m_pPlaylistTableModel->shuffleTracks(selection, QModelIndex());
250+
m_pPlaylistTableModel->shuffleTracks(selection);
242251
} else {
243252
// Create a temp model so we don't need to select the playlist
244253
// in the persistent model in order to shuffle it
@@ -253,8 +262,27 @@ void PlaylistFeature::slotShufflePlaylist() {
253262
Qt::AscendingOrder);
254263
pPlaylistTableModel->select();
255264

256-
pPlaylistTableModel->shuffleTracks(selection, QModelIndex());
265+
pPlaylistTableModel->shuffleTracks();
266+
}
267+
}
268+
269+
void PlaylistFeature::slotOrderTracksByCurrentPosition() {
270+
int playlistId = playlistIdFromIndex(m_lastRightClickedIndex);
271+
if (playlistId == kInvalidPlaylistId) {
272+
return;
273+
}
274+
275+
if (m_playlistDao.isPlaylistLocked(playlistId)) {
276+
qDebug() << "Can't adopt current sorting for locked playlist" << playlistId
277+
<< m_playlistDao.getPlaylistName(playlistId);
278+
return;
279+
}
280+
// Note(ronso0) I propose to proceed only if the playlist is selected and loaded.
281+
// without playlist content visible we don't have a preview.
282+
if (!isChildIndexSelectedInSidebar(m_lastRightClickedIndex)) {
283+
return;
257284
}
285+
m_pPlaylistTableModel->orderTracksByCurrPos();
258286
}
259287

260288
void PlaylistFeature::slotUnlockAllPlaylists() {

src/library/trackset/playlistfeature.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class PlaylistFeature : public BasePlaylistFeature {
3737
void slotPlaylistContentOrLockChanged(const QSet<int>& playlistIds) override;
3838
void slotPlaylistTableRenamed(int playlistId, const QString& newName) override;
3939
void slotShufflePlaylist();
40+
void slotOrderTracksByCurrentPosition();
4041
void slotUnlockAllPlaylists();
4142
void slotDeleteAllUnlockedPlaylists();
4243

@@ -49,6 +50,7 @@ class PlaylistFeature : public BasePlaylistFeature {
4950
QString getRootViewHtml() const override;
5051

5152
parented_ptr<QAction> m_pShufflePlaylistAction;
53+
parented_ptr<QAction> m_pOrderByCurrentPosAction;
5254
parented_ptr<QAction> m_pUnlockPlaylistsAction;
5355
parented_ptr<QAction> m_pDeleteAllUnlockedPlaylistsAction;
5456
};

0 commit comments

Comments
 (0)