[gnome-music/wip/jfelder/core-playlists-view: 1/3] playlistsview: Restore playlist deletion
- From: Jean Felder <jfelder src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-music/wip/jfelder/core-playlists-view: 1/3] playlistsview: Restore playlist deletion
- Date: Tue, 9 Jul 2019 14:21:04 +0000 (UTC)
commit 8aac521497c73f9e8011e6e0114080e4007be027
Author: Jean Felder <jfelder src gnome org>
Date: Tue Jul 9 10:23:26 2019 +0200
playlistsview: Restore playlist deletion
gnomemusic/coregrilo.py | 21 ++++++++
gnomemusic/coremodel.py | 29 +++++++++++
gnomemusic/grilowrappers/grltrackerplaylists.py | 65 +++++++++++++++++++++++--
gnomemusic/grilowrappers/grltrackersource.py | 26 +++++++++-
gnomemusic/views/playlistsview.py | 33 ++++++++++---
gnomemusic/widgets/notificationspopup.py | 40 +++++++++------
6 files changed, 187 insertions(+), 27 deletions(-)
---
diff --git a/gnomemusic/coregrilo.py b/gnomemusic/coregrilo.py
index 14145d87..92e567aa 100644
--- a/gnomemusic/coregrilo.py
+++ b/gnomemusic/coregrilo.py
@@ -85,3 +85,24 @@ class CoreGrilo(GObject.GObject):
def search(self, text):
for wrapper in self._wrappers:
wrapper.search(text)
+
+ def stage_playlist_deletion(self, playlist):
+ """Prepares playlist deletion.
+
+ :param Playlist playlist: playlist
+ """
+ for wrapper in self._wrappers:
+ if wrapper.source.props.source_id == "grl-tracker-source":
+ wrapper.stage_playlist_deletion(playlist)
+ break
+
+ def finish_playlist_deletion(self, playlist, deleted):
+ """Finishes playlist deletion.
+
+ :param Playlist playlist: playlist
+ :param bool deleted: indicates if the playlist has been deleted
+ """
+ for wrapper in self._wrappers:
+ if wrapper.source.props.source_id == "grl-tracker-source":
+ wrapper.finish_playlist_deletion(playlist, deleted)
+ break
diff --git a/gnomemusic/coremodel.py b/gnomemusic/coremodel.py
index 48b01e97..39b9cbc2 100644
--- a/gnomemusic/coremodel.py
+++ b/gnomemusic/coremodel.py
@@ -270,6 +270,29 @@ class CoreModel(GObject.GObject):
self.emit("playlist-loaded")
+ def stage_playlist_deletion(self, playlist):
+ """Prepares playlist deletion.
+
+ :param Playlist playlist: playlist
+ """
+ self._grilo.stage_playlist_deletion(playlist)
+
+ def finish_playlist_deletion(self, playlist, deleted):
+ """Finishes playlist deletion.
+
+ :param Playlist playlist: playlist
+ :param bool deleted: indicates if the playlist has been deleted
+ """
+ self._grilo.finish_playlist_deletion(playlist, deleted)
+
+ def create_playlist(self, playlist_title, callback):
+ """Creates a new user playlist.
+
+ :param str playlist_title: playlist title
+ :param callback: function to perform once, the playlist is created
+ """
+ self._grilo.create_playlist(playlist_title, callback)
+
def search(self, text):
self._grilo.search(text)
@@ -344,3 +367,9 @@ class CoreModel(GObject.GObject):
flags=GObject.ParamFlags.READABLE)
def playlists_sort(self):
return self._playlists_model_sort
+
+ @GObject.Property(
+ type=Gfm.SortListModel, default=None,
+ flags=GObject.ParamFlags.READABLE)
+ def playlists_filter(self):
+ return self._playlists_model_filter
diff --git a/gnomemusic/grilowrappers/grltrackerplaylists.py b/gnomemusic/grilowrappers/grltrackerplaylists.py
index 62940d2e..78c30620 100644
--- a/gnomemusic/grilowrappers/grltrackerplaylists.py
+++ b/gnomemusic/grilowrappers/grltrackerplaylists.py
@@ -41,6 +41,9 @@ class GrlTrackerPlaylists(GObject.GObject):
self._grilo = grilo
self._source = source
self._model = self._coremodel.props.playlists
+ self._model_filter = self._coremodel.props.playlists_filter
+ self._pls_todelete = []
+ self._tracker = TrackerWrapper().props.tracker
self._fast_options = Grl.OperationOptions()
self._fast_options.set_resolution_flags(
@@ -105,6 +108,60 @@ class GrlTrackerPlaylists(GObject.GObject):
self._model.append(playlist)
+ def _playlists_filter(self, playlist):
+ return playlist not in self._pls_todelete
+
+ def stage_playlist_deletion(self, playlist):
+ """Adds playlist to the list of playlists to delete
+
+ :param Playlist playlist: playlist
+ """
+ self._pls_todelete.append(playlist)
+ self._model_filter.set_filter_func(self._playlists_filter)
+
+ def finish_playlist_deletion(self, playlist, deleted):
+ """Removes playlist from the list of playlists to delete
+
+ :param Playlist playlist: playlist
+ :param bool deleted: indicates if the playlist has been deleted
+ """
+ self._pls_todelete.remove(playlist)
+ if deleted is False:
+ self._model_filter.set_filter_func(self._playlists_filter)
+ return
+
+ def _delete_cb(conn, res, data):
+ # FIXME: Check for failure.
+ conn.update_finish(res)
+ for idx, playlist_model in enumerate(self._model):
+ if playlist_model is playlist:
+ self._model.remove(idx)
+ break
+
+ self._model_filter.set_filter_func(self._playlists_filter)
+
+ query = """
+ DELETE {
+ ?playlist a rdfs:Resource .
+ ?entry a rdfs:Resource .
+
+ }
+ WHERE {
+ ?playlist a nmm:Playlist ;
+ a nfo:MediaList .
+ OPTIONAL {
+ ?playlist nfo:hasMediaFileListEntry ?entry .
+ }
+ FILTER (
+ tracker:id(?playlist) = %(playlist_id)s
+ )
+ }
+ """.replace("\n", " ").strip() % {
+ "playlist_id": playlist.props.pl_id
+ }
+ self._tracker.update_async(
+ query, GLib.PRIORITY_LOW, None, _delete_cb, None)
+
class Playlist(GObject.GObject):
""" Base class of all playlists """
@@ -265,7 +322,7 @@ class Playlist(GObject.GObject):
self._tracker.update_async(
query, GLib.PRIORITY_LOW, None, update_cb, None)
- def stage_deletion(self, coresong, index):
+ def stage_song_deletion(self, coresong, index):
"""Adds a song to the list of songs to delete
:param CoreSong coresong: song to delete
@@ -275,8 +332,8 @@ class Playlist(GObject.GObject):
self._model.remove(index)
self.props.count -= 1
- def undo_pending_deletion(self, coresong, position):
- """Adds a song to the list of songs to delete
+ def undo_pending_song_deletion(self, coresong, position):
+ """Removes song from the list of songs to delete
:param CoreSong coresong: song to delete
:param int position: Song position in the playlist
@@ -285,7 +342,7 @@ class Playlist(GObject.GObject):
self._model.insert(position, coresong)
self.props.count += 1
- def finish_deletion(self, coresong):
+ def finish_song_deletion(self, coresong):
"""Removes a song from the playlist
:param CoreSong coresong: song to remove
diff --git a/gnomemusic/grilowrappers/grltrackersource.py b/gnomemusic/grilowrappers/grltrackersource.py
index 46e9b131..19ddfdb7 100644
--- a/gnomemusic/grilowrappers/grltrackersource.py
+++ b/gnomemusic/grilowrappers/grltrackersource.py
@@ -55,7 +55,8 @@ class GrlTrackerSource(GObject.GObject):
self._initial_albums_fill(self._source)
self._initial_artists_fill(self._source)
- GrlTrackerPlaylists(source, coremodel, coreselection, grilo)
+ self._tracker_playlists = GrlTrackerPlaylists(
+ source, coremodel, coreselection, grilo)
self._source.connect("content-changed", self._on_content_changed)
@@ -640,3 +641,26 @@ class GrlTrackerSource(GObject.GObject):
self._source.query(
query, self.METADATA_KEYS, options, artist_search_cb)
+
+ def stage_playlist_deletion(self, playlist):
+ """Prepares playlist deletion.
+
+ :param Playlist playlist: playlist
+ """
+ self._tracker_playlists.stage_playlist_deletion(playlist)
+
+ def finish_playlist_deletion(self, playlist, deleted):
+ """Finishes playlist deletion.
+
+ :param Playlist playlist: playlist
+ :param bool deleted: indicates if the playlist has been deleted
+ """
+ self._tracker_playlists.finish_playlist_deletion(playlist, deleted)
+
+ def create_playlist(self, playlist_title, callback):
+ """Creates a new user playlist.
+
+ :param str playlist_title: playlist title
+ :param callback: function to perform once, the playlist is created
+ """
+ self._tracker_playlists.create_playlist(playlist_title, callback)
diff --git a/gnomemusic/views/playlistsview.py b/gnomemusic/views/playlistsview.py
index 083a9302..a493cdae 100644
--- a/gnomemusic/views/playlistsview.py
+++ b/gnomemusic/views/playlistsview.py
@@ -90,11 +90,12 @@ class PlaylistsView(BaseView):
'activate', self._on_play_playlist)
self._window.add_action(playlist_play_action)
- # self._playlist_delete_action = Gio.SimpleAction.new(
- # 'playlist_delete', None)
- # self._playlist_delete_action.connect(
- # 'activate', self._stage_playlist_for_deletion)
- # self._window.add_action(self._playlist_delete_action)
+ self._playlist_delete_action = Gio.SimpleAction.new(
+ 'playlist_delete', None)
+ self._playlist_delete_action.connect(
+ 'activate', self._stage_playlist_for_deletion)
+ self._window.add_action(self._playlist_delete_action)
+
self._playlist_rename_action = Gio.SimpleAction.new(
'playlist_rename', None)
self._playlist_rename_action.connect(
@@ -207,8 +208,9 @@ class PlaylistsView(BaseView):
selected_playlist = self._sidebar.get_selected_row().playlist
notification = PlaylistNotification( # noqa: F841
- self._window.notifications_popup, PlaylistNotification.Type.SONG,
- selected_playlist, coresong, position)
+ self._window.notifications_popup, self._coremodel,
+ PlaylistNotification.Type.SONG, selected_playlist, position,
+ coresong)
@log
def _on_playlist_activated(self, sidebar, row, data=None):
@@ -227,6 +229,7 @@ class PlaylistsView(BaseView):
playlist.connect("notify::count", self._on_song_count_changed)
self._playlist_rename_action.set_enabled(not playlist.props.is_smart)
+ self._playlist_delete_action.set_enabled(not playlist.props.is_smart)
def _on_song_count_changed(self, playlist, value):
self._update_songs_count(playlist.props.count)
@@ -271,6 +274,22 @@ class PlaylistsView(BaseView):
pl_torename = selection.playlist
pl_torename.rename(new_name)
+ @log
+ def _stage_playlist_for_deletion(self, menutime, data=None):
+ selected_row = self._sidebar.get_selected_row()
+ selected_playlist = selected_row.playlist
+
+ notification = PlaylistNotification( # noqa: F841
+ self._window.notifications_popup, self._coremodel,
+ PlaylistNotification.Type.PLAYLIST, selected_playlist)
+
+ # FIXME: Should Check that the playlist is not playing
+ # playlist_id = selection.playlist.props.pl_id
+ # if self.player.playing_playlist(
+ # PlayerPlaylist.Type.PLAYLIST, playlist_id):
+ # self.player.stop()
+ # self._window.set_player_visible(False)
+
@log
def _populate(self, data=None):
"""Populate sidebar.
diff --git a/gnomemusic/widgets/notificationspopup.py b/gnomemusic/widgets/notificationspopup.py
index 061a811e..b9befcdd 100644
--- a/gnomemusic/widgets/notificationspopup.py
+++ b/gnomemusic/widgets/notificationspopup.py
@@ -213,21 +213,25 @@ class PlaylistNotification(Gtk.Grid):
return '<PlaylistNotification>'
@log
- def __init__(self, notifications_popup, type_, playlist, data, position):
+ def __init__(
+ self, notifications_popup, coremodel, type_, playlist,
+ position=None, coresong=None):
"""Creates a playlist deletion notification popup (song or playlist)
- :param GtkRevealer notifications_popup: the popup object
+ :param GtkRevealer: notifications_popup: the popup object
+ :param CoreModel: core model
:param type_: NotificationType (song or playlist)
:param Playlist playlist: playlist
- :param object data: Data associated with the deletion
:param int position: position of the object to delete
+ :param object coresong: CoreSong for song deletion
"""
super().__init__(column_spacing=18)
self._notifications_popup = notifications_popup
+ self._coremodel = coremodel
self.type_ = type_
self._playlist = playlist
- self.data = data
self._position = position
+ self._coresong = coresong
message = self._create_notification_message()
self._label = Gtk.Label(
@@ -239,25 +243,24 @@ class PlaylistNotification(Gtk.Grid):
self.add(undo_button)
self.show_all()
- if self.type_ == PlaylistNotification.Type.SONG:
- playlist.stage_deletion(self.data, position)
+ if self.type_ == PlaylistNotification.Type.PLAYLIST:
+ self._coremodel.stage_playlist_deletion(self._playlist)
+ else:
+ playlist.stage_song_deletion(self._coresong, position)
self._timeout_id = GLib.timeout_add_seconds(5, self._finish_deletion)
self._notifications_popup.add_notification(self)
def _create_notification_message(self):
if self.type_ == PlaylistNotification.Type.PLAYLIST:
- return None
- # pl_todelete = data
- # msg = _("Playlist {} removed".format(pl_todelete.props.title))
-
+ msg = _("Playlist {} removed".format(self._playlist.props.title))
else:
playlist_title = self._playlist.props.title
- coresong = self.data
- song_title = coresong.props.title
+ song_title = self._coresong.props.title
msg = _("{} removed from {}".format(
song_title, playlist_title))
- return msg
+
+ return msg
@log
def _undo_deletion(self, widget_):
@@ -267,8 +270,15 @@ class PlaylistNotification(Gtk.Grid):
self._timeout_id = 0
self._notifications_popup.remove_notification(self)
- self._playlist.undo_pending_deletion(self.data, self._position)
+ if self.type_ == PlaylistNotification.Type.PLAYLIST:
+ self._coremodel.finish_playlist_deletion(self._playlist, False)
+ else:
+ self._playlist.undo_pending_song_deletion(
+ self._coresong, self._position)
def _finish_deletion(self):
self._notifications_popup.remove_notification(self)
- self._playlist.finish_deletion(self.data)
+ if self.type_ == PlaylistNotification.Type.PLAYLIST:
+ self._coremodel.finish_playlist_deletion(self._playlist, True)
+ else:
+ self._playlist.finish_song_deletion(self._coresong)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]