[gnome-music/wip/mschraal/renamepl] playlist: Add the possibility to rename a playlist



commit db01286aa9d7c437705212474040e568046e7c61
Author: Jean Felder <jean felder gmail com>
Date:   Tue Dec 19 00:10:50 2017 +0100

    playlist: Add the possibility to rename a playlist
    
    https://bugzilla.gnome.org/show_bug.cgi?id=744822

 data/PlaylistControls.ui         | 68 +++++++++++++++++++++++++++++++++-------
 gnomemusic/playlists.py          | 22 +++++++++++++
 gnomemusic/query.py              | 25 +++++++++++++++
 gnomemusic/views/playlistview.py | 67 ++++++++++++++++++++++++++++++++++++++-
 gnomemusic/window.py             |  9 +++++-
 5 files changed, 178 insertions(+), 13 deletions(-)
---
diff --git a/data/PlaylistControls.ui b/data/PlaylistControls.ui
index 8f064fc..6d09bd4 100644
--- a/data/PlaylistControls.ui
+++ b/data/PlaylistControls.ui
@@ -10,6 +10,10 @@
       <attribute name="label" translatable="yes">_Delete</attribute>
       <attribute name="action">win.playlist_delete</attribute>
     </item>
+    <item>
+      <attribute name="label" translatable="yes">_Rename...</attribute>
+      <attribute name="action">win.playlist_rename</attribute>
+    </item>
   </menu>
   <object class="GtkGrid" id="grid">
     <property name="visible">True</property>
@@ -19,17 +23,59 @@
     <property name="margin_top">18</property>
     <property name="margin_bottom">18</property>
     <child>
-      <object class="GtkLabel" id="playlist_name">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="hexpand">True</property>
-        <property name="xalign">0</property>
-        <property name="label" translatable="yes">Playlist Name</property>
-        <property name="ellipsize">middle</property>
-        <attributes>
-          <attribute name="weight" value="bold"/>
-          <attribute name="scale" value="1.5"/>
-        </attributes>
+      <object class="GtkStack" id="stack">
+       <child>
+         <object class="GtkLabel" id="playlist_name">
+           <property name="visible">True</property>
+           <property name="can_focus">False</property>
+           <property name="hexpand">True</property>
+           <property name="xalign">0</property>
+           <property name="label" translatable="yes">Playlist Name</property>
+           <property name="ellipsize">middle</property>
+           <attributes>
+             <attribute name="weight" value="bold"/>
+             <attribute name="scale" value="1.5"/>
+           </attributes>
+         </object>
+       </child>
+       <child>
+         <object class="GtkBox">
+           <property name="visible">True</property>
+           <property name="can_focus">False</property>
+           <property name="orientation">horizontal</property>
+           <style>
+             <class name="linked"/>
+           </style>
+           <child>
+             <object class="GtkEntry" id="playlist_rename_entry">
+               <property name="visible">True</property>
+               <property name="can_focus">True</property>
+               <property name="is_focus">True</property>
+               <property name="has_focus">True</property>
+               <property name="receives_default">True</property>
+             </object>
+           </child>
+           <child>
+             <object class="GtkButton" id="playlist_rename_done_button">
+               <property name="visible">True</property>
+               <property name="no_show_all">True</property>
+               <property name="can_focus">True</property>
+               <property name="has_focus">True</property>
+               <property name="receives_default">True</property>
+               <property name="label" translatable="yes">_Done</property>
+               <property name="use_underline">True</property>
+               <property name="valign">center</property>
+               <property name="sensitive">True</property>
+               <style>
+                 <class name="suggested-action"/>
+               </style>
+             </object>
+           </child>
+         </object>
+         <packing>
+           <property name="name">renaming_dialog</property>
+         </packing>
+       </child>
       </object>
       <packing>
         <property name="left_attach">0</property>
diff --git a/gnomemusic/playlists.py b/gnomemusic/playlists.py
index d39011b..3952255 100644
--- a/gnomemusic/playlists.py
+++ b/gnomemusic/playlists.py
@@ -117,6 +117,9 @@ class Playlists(GObject.GObject):
         'playlist-updated': (
             GObject.SignalFlags.RUN_FIRST, None, (int,)
         ),
+        'playlist-renamed': (
+            GObject.SignalFlags.RUN_FIRST, None, (Grl.Media,)
+        ),
         'song-added-to-playlist': (
             GObject.SignalFlags.RUN_FIRST, None, (Grl.Media, Grl.Media)
         ),
@@ -348,6 +351,25 @@ class Playlists(GObject.GObject):
         )
 
     @log
+    def rename(self, item, new_name):
+        """Rename a playlist
+
+        :param item: playlist to rename
+        :param new_name: new playlist name
+        :type item: Grl.Media
+        :type new_name: str
+        :return: None
+        :rtype: None
+        """
+        def update_callback(conn, res, data):
+            conn.update_finish(res)
+            self.emit('playlist-renamed', item)
+
+        self.tracker.update_async(
+            Query.rename_playlist(item.get_id(), new_name), GLib.PRIORITY_LOW,
+            None, update_callback, None)
+
+    @log
     def delete_playlist(self, item):
         def update_callback(conn, res, data):
             conn.update_finish(res)
diff --git a/gnomemusic/query.py b/gnomemusic/query.py
index e70cfa7..c4ff40c 100644
--- a/gnomemusic/query.py
+++ b/gnomemusic/query.py
@@ -473,6 +473,31 @@ class Query():
         return query
 
     @staticmethod
+    def rename_playlist(playlist_id, new_name):
+        query = """
+    INSERT OR REPLACE {
+        ?playlist
+            nie:title "%(title)s"
+    }
+    WHERE {
+        ?playlist
+            a nmm:Playlist ;
+            a nfo:MediaList .
+        OPTIONAL {
+            ?playlist
+                nfo:hasMediaFileListEntry ?entry .
+        }
+        FILTER (
+            tracker:id(?playlist) = %(playlist_id)s
+        )
+    }
+    """.replace("\n", " ").strip() % {
+            'title': new_name,
+            'playlist_id': playlist_id
+        }
+        return query
+
+    @staticmethod
     def add_song_to_playlist(playlist_id, song_uri):
         query = """
     INSERT OR REPLACE {
diff --git a/gnomemusic/views/playlistview.py b/gnomemusic/views/playlistview.py
index 36c270c..69f2078 100644
--- a/gnomemusic/views/playlistview.py
+++ b/gnomemusic/views/playlistview.py
@@ -70,7 +70,12 @@ class PlaylistView(BaseView):
         builder = Gtk.Builder()
         builder.add_from_resource('/org/gnome/Music/PlaylistControls.ui')
         headerbar = builder.get_object('grid')
+        self._name_stack = builder.get_object('stack')
         self._name_label = builder.get_object('playlist_name')
+        self._rename_entry = builder.get_object('playlist_rename_entry')
+        self._rename_entry.connect('changed', self._on_rename_entry_changed)
+        self._rename_done_button = builder.get_object(
+            'playlist_rename_done_button')
         self._songs_count_label = builder.get_object('songs_count')
         self._menubutton = builder.get_object('playlist_menubutton')
 
@@ -83,6 +88,11 @@ class PlaylistView(BaseView):
         self._playlist_delete_action.connect('activate',
                                              self._on_delete_activate)
         self._window.add_action(self._playlist_delete_action)
+        self._playlist_rename_action = Gio.SimpleAction.new(
+            'playlist_rename', None)
+        self._playlist_rename_action.connect(
+            'activate', self._on_rename_activate)
+        self._window.add_action(self._playlist_rename_action)
 
         self._grid.insert_row(0)
         self._grid.attach(headerbar, 1, 0, 1, 1)
@@ -125,6 +135,8 @@ class PlaylistView(BaseView):
         self.pl_todelete = None
         self._pl_todelete_index = None
         self._songs_count = 0
+        self._handler_rename_done_button = 0
+        self._handler_rename_entry = 0
 
         self._update_songs_count()
 
@@ -375,6 +387,10 @@ class PlaylistView(BaseView):
         playlist_name = self._playlists_model[_iter][2]
         playlist = self._playlists_model[_iter][5]
 
+        # If playlist rename box is active, disable it
+        if self.rename_active:
+            self.disable_rename_playlist()
+
         self.current_playlist = playlist
         self._name_label.set_text(playlist_name)
         self._current_playlist_index = int(path.to_string())
@@ -386,11 +402,12 @@ class PlaylistView(BaseView):
         self._songs_count = 0
         grilo.populate_playlist_songs(playlist, self._add_item)
 
-        # disable delete button if current playlist is a smart playlist
         if self._current_playlist_is_protected():
             self._playlist_delete_action.set_enabled(False)
+            self._playlist_rename_action.set_enabled(False)
         else:
             self._playlist_delete_action.set_enabled(True)
+            self._playlist_rename_action.set_enabled(True)
 
     @log
     def _add_item(self, source, param, item, remaining=0, data=None):
@@ -479,6 +496,54 @@ class PlaylistView(BaseView):
         self._stage_playlist_for_deletion()
 
     @log
+    @property
+    def rename_active(self):
+        """Indicate if renaming dialog is active"""
+        return self._name_stack.get_visible_child_name() == 'renaming_dialog'
+
+    @log
+    def _on_rename_entry_changed(self, selection):
+        if selection.get_text_length() > 0:
+            self._rename_done_button.set_sensitive(True)
+        else:
+            self._rename_done_button.set_sensitive(False)
+
+    @log
+    def disable_rename_playlist(self):
+        """disables rename button and entry"""
+        self._name_stack.set_visible_child(self._name_label)
+        self._rename_done_button.disconnect(self._handler_rename_done_button)
+        self._rename_entry.disconnect(self._handler_rename_entry)
+
+    @log
+    def _stage_playlist_for_renaming(self):
+        _iter = self._pl_generic_view.get_selection().get_selected()[1]
+        pl_torename = self._playlists_model[_iter][5]
+
+        def playlist_renamed_callback(widget):
+            new_name = self._rename_entry.get_text()
+            if not new_name:
+                return
+
+            self._playlists_model[_iter][2] = new_name
+            pl_torename.set_title(new_name)
+            playlists.rename(pl_torename, new_name)
+            self._name_label.set_text(new_name)
+            self.disable_rename_playlist()
+
+        self._name_stack.set_visible_child_name('renaming_dialog')
+        self._rename_entry.set_text(utils.get_media_title(pl_torename))
+        self._rename_entry.grab_focus()
+        self._handler_rename_entry = self._rename_entry.connect(
+            'activate', playlist_renamed_callback)
+        self._handler_rename_done_button = self._rename_done_button.connect(
+            'clicked', playlist_renamed_callback)
+
+    @log
+    def _on_rename_activate(self, menuitem, data=None):
+        self._stage_playlist_for_renaming()
+
+    @log
     def _on_playlist_created(self, playlists, item):
         self._add_playlist_item_to_model(item)
         if self._playlists_model.iter_n_children(None) == 1:
diff --git a/gnomemusic/window.py b/gnomemusic/window.py
index 5a3f585..25e261a 100644
--- a/gnomemusic/window.py
+++ b/gnomemusic/window.py
@@ -471,7 +471,8 @@ class Window(Gtk.ApplicationWindow):
                 and not event.keyval == Gdk.KEY_space)
                 and GLib.unichar_isprint(chr(key_unic))
                 and (event_and_modifiers == Gdk.ModifierType.SHIFT_MASK
-                    or event_and_modifiers == 0)):
+                    or event_and_modifiers == 0)
+                and not self.views[3].rename_active):
             self.toolbar.searchbar.show_bar(True)
 
     @log
@@ -502,6 +503,12 @@ class Window(Gtk.ApplicationWindow):
             self.toolbar._select_button.set_sensitive(
                 not self.toolbar._select_button.get_sensitive())
 
+        # Disable renaming playlist if it was active when leaving
+        # Playlist view
+        if (self.prev_view == self.views[3]
+                and self.views[3].rename_active):
+            self.views[3].disable_rename_playlist()
+
     @log
     def _toggle_view(self, btn, i):
         self._stack.set_visible_child(self.views[i])


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]