diff --git a/app/model.py b/app/model.py
index 5608e4e..b591391 100644
--- a/app/model.py
+++ b/app/model.py
@@ -200,16 +200,29 @@ class Playlists(Base):
return (
session.query(Playlists)
- .filter(Playlists.loaded == True)
+ .filter(Playlists.loaded == True) # noqa E712
.order_by(Playlists.last_used.desc())
).all()
@staticmethod
def get_all_playlists():
- "Returns a list of (id, name) of all playlists"
+ "Returns a list of all playlists"
return session.query(Playlists).all()
+ @staticmethod
+ def get_all_closed_playlists():
+ "Returns a list of all playlists not currently open"
+
+ return (
+ session.query(Playlists)
+ .filter(
+ (Playlists.loaded == False) | # noqa E712
+ (Playlists.loaded == None)
+ )
+ .order_by(Playlists.last_used.desc())
+ ).all()
+
@staticmethod
def get_name(plid):
"""
@@ -271,6 +284,24 @@ class PlaylistTracks(Base):
session.add(plt)
session.commit()
+ @staticmethod
+ def move_track(from_playlist_id, row, to_playlist_id):
+ DEBUG(
+ f"PlaylistTracks.move_tracks({from_playlist_id=}, {row=}, "
+ f"{to_playlist_id=})"
+ )
+ new_row = (
+ session.query(func.max(PlaylistTracks.row)).filter(
+ PlaylistTracks.playlist_id == to_playlist_id).scalar()
+ ) + 1
+ record = session.query(PlaylistTracks).filter(
+ PlaylistTracks.playlist_id == from_playlist_id,
+ PlaylistTracks.row == row
+ ).one()
+ record.playlist_id = to_playlist_id
+ record.row = new_row
+ session.commit()
+
@staticmethod
def remove_track(playlist_id, row):
DEBUG(
diff --git a/app/musicmuster.py b/app/musicmuster.py
index 3dca2f3..10d0df2 100755
--- a/app/musicmuster.py
+++ b/app/musicmuster.py
@@ -25,7 +25,7 @@ import helpers
import music
from config import Config
-from model import Playdates, Playlists, Settings, Tracks
+from model import Playdates, Playlists, PlaylistTracks, Settings, Tracks
from playlists import Playlist
from songdb import add_path_to_db
from ui.dlg_search_database_ui import Ui_Dialog
@@ -214,7 +214,42 @@ class Window(QMainWindow, Ui_MainWindow):
playlist_table = Playlist()
playlist_table.db = playlist_db
playlist_table.populate()
- self.tabPlaylist.addTab(playlist_table, playlist_db.name)
+ idx = self.tabPlaylist.addTab(playlist_table, playlist_db.name)
+ self.tabPlaylist.setCurrentIndex(idx)
+
+ def move_selected(self):
+ "Move selected rows to another playlist"
+
+ playlists = list(
+ set(Playlists.get_all_playlists()) - {self.visible_playlist().db}
+ )
+ dlg = SelectPlaylistDialog(self, playlists=playlists)
+ dlg.exec()
+ if not dlg.plid:
+ return
+
+ # If destination playlist is visible, we need to add the moved
+ # tracks to it. If not, they will be automatically loaded when
+ # the playlistis opened.
+ destination_playlist = None
+ for tab in range(self.tabPlaylist.count()):
+ if self.tabPlaylist.widget(tab).db.id == dlg.plid:
+ destination_playlist = self.tabPlaylist.widget(tab)
+ break
+
+ rows = []
+ for (row, track_id) in (
+ self.visible_playlist().get_selected_rows_and_tracks()):
+ rows.append(row)
+ # Update database
+ PlaylistTracks.move_track(
+ self.visible_playlist().db.id, row, dlg.plid)
+ # Update destination playlist if visible
+ if destination_playlist:
+ destination_playlist.add_track(Tracks.track_from_id(track_id))
+
+ # Update source playlist
+ self.visible_playlist().remove_rows(rows)
def play_next(self):
"""
@@ -293,12 +328,13 @@ class Window(QMainWindow, Ui_MainWindow):
dlg = DbDialog(self)
dlg.exec()
- def select_playlist(self):
- # TODO don't show those that are currently open
- dlg = SelectPlaylistDialog(self)
+ def open_playlist(self):
+ playlists = Playlists.get_all_closed_playlists()
+ dlg = SelectPlaylistDialog(self, playlists=playlists)
dlg.exec()
- playlist = Playlists.get_playlist_by_id(dlg.plid)
- self.load_playlist(playlist)
+ if dlg.plid:
+ playlist = Playlists.open(dlg.plid)
+ self.load_playlist(playlist)
def set_next_track(self):
"Set selected track as next"
@@ -353,7 +389,7 @@ class Window(QMainWindow, Ui_MainWindow):
self.update_headers()
def tab_change(self):
- "User has changed tabs, so refresh next track"
+ "User has changed tabs"
pass
@@ -566,13 +602,17 @@ class DbDialog(QDialog):
class SelectPlaylistDialog(QDialog):
- def __init__(self, parent=None):
+ def __init__(self, parent=None, playlists=None):
super().__init__(parent)
+
+ if playlists is None:
+ return
self.ui = Ui_dlgSelectPlaylist()
self.ui.setupUi(self)
self.ui.lstPlaylists.itemDoubleClicked.connect(self.list_doubleclick)
self.ui.buttonBox.accepted.connect(self.open)
self.ui.buttonBox.rejected.connect(self.close)
+ self.plid = None
record = Settings.get_int("select_playlist_dialog_width")
width = record.f_int or 800
@@ -580,9 +620,7 @@ class SelectPlaylistDialog(QDialog):
height = record.f_int or 600
self.resize(width, height)
- for (plid, plname) in [
- (a.id, a.name) for a in Playlists.get_all_playlists()
- ]:
+ for (plid, plname) in [(a.id, a.name) for a in playlists]:
p = QListWidgetItem()
p.setText(plname)
p.setData(Qt.UserRole, plid)
diff --git a/app/playlists.py b/app/playlists.py
index dcda704..0798b79 100644
--- a/app/playlists.py
+++ b/app/playlists.py
@@ -266,6 +266,32 @@ class Playlist(QTableWidget):
next_row = self._meta_get_next()
return self._get_row_id(next_row)
+ def get_selected_rows_and_tracks(self):
+ "Return a list of selected (rows, track_id) tuples"
+
+ if not self.selectionModel().hasSelection():
+ return None
+
+ result = []
+
+ for row in [r.row() for r in self.selectionModel().selectedRows()]:
+ track_id = self._get_row_id(row)
+ result.append((row, track_id))
+
+ return result
+
+ def remove_rows(self, rows):
+ "Remove rows passed in rows list"
+
+ # Row number will change as we delete rows. We could use
+ # QPersistentModelIndex, but easier just to remove them lowest
+ # row first
+
+ for row in sorted(rows, reverse=True):
+ self.removeRow(row)
+
+ self._repaint(save_playlist=False)
+
def get_selected_title(self):
"Return title of selected row or None"
@@ -322,6 +348,10 @@ class Playlist(QTableWidget):
self._repaint()
+ def repaint(self):
+ # Called when we change tabs
+ self._repaint(save_playlist=False)
+
def set_selected_as_next(self):
"""
Sets the selected track as the next track.
diff --git a/app/ui/main_window.ui b/app/ui/main_window.ui
index 4f51f97..1e8e4ca 100644
--- a/app/ui/main_window.ui
+++ b/app/ui/main_window.ui
@@ -6,7 +6,7 @@
0
0
- 1114
+ 1164
857
@@ -750,8 +750,8 @@ border: 1px solid rgb(85, 87, 83);
0
0
- 1114
- 18
+ 1164
+ 29