[gnome-music] playlistview: Use Gtk.Template
- From: Marinus Schraal <mschraal src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-music] playlistview: Use Gtk.Template
- Date: Sun, 29 Jul 2018 07:24:31 +0000 (UTC)
commit cf34619ead036650838ea73d6104e69b926d2736
Author: Apostol Bakalov <apogza gmail com>
Date: Sun Jul 29 07:23:46 2018 +0000
playlistview: Use Gtk.Template
data/PlaylistContextMenu.ui | 30 ++++---
data/PlaylistControls.ui | 104 ++++++++++++------------
gnomemusic/views/playlistview.py | 127 +++++++++--------------------
gnomemusic/widgets/playlistcontextmenu.py | 45 +++++++++++
gnomemusic/widgets/playlistcontrols.py | 130 ++++++++++++++++++++++++++++++
po/POTFILES.in | 1 +
6 files changed, 283 insertions(+), 154 deletions(-)
---
diff --git a/data/PlaylistContextMenu.ui b/data/PlaylistContextMenu.ui
index 7be19bb8..107ba577 100644
--- a/data/PlaylistContextMenu.ui
+++ b/data/PlaylistContextMenu.ui
@@ -1,17 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <menu id="song_menu">
- <item>
- <attribute name="label" translatable="yes">Play</attribute>
- <attribute name="action">win.play_song</attribute>
- </item>
- <item>
- <attribute name="label" translatable="yes">Add to Playlist…</attribute>
- <attribute name="action">win.add_song_to_playlist</attribute>
- </item>
- <item>
- <attribute name="label" translatable="yes">Remove From Playlist</attribute>
- <attribute name="action">win.remove_song</attribute>
- </item>
+ <menu id="_song_menu">
+ <item>
+ <attribute name="label" translatable="yes">Play</attribute>
+ <attribute name="action">win.play_song</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Add to Playlist…</attribute>
+ <attribute name="action">win.add_song_to_playlist</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Remove From Playlist</attribute>
+ <attribute name="action">win.remove_song</attribute>
+ </item>
</menu>
+ <template class="PlaylistContextMenu" parent="GtkPopover">
+ <property name="position">3</property>
+ </template>
</interface>
+
diff --git a/data/PlaylistControls.ui b/data/PlaylistControls.ui
index 76302951..64456fdd 100644
--- a/data/PlaylistControls.ui
+++ b/data/PlaylistControls.ui
@@ -15,7 +15,7 @@
<attribute name="action">win.playlist_rename</attribute>
</item>
</menu>
- <object class="GtkGrid" id="grid">
+ <template class="PlaylistControls" parent="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_start">18</property>
@@ -23,59 +23,63 @@
<property name="margin_top">18</property>
<property name="margin_bottom">18</property>
<child>
- <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>
- <style>
- <class name="playlist-name-label"/>
- </style>
- </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>
+ <object class="GtkStack" id="_name_stack">
<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 class="GtkLabel" id="_name_label">
+ <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>
+ <style>
+ <class name="playlist-name-label"/>
+ </style>
</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 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="_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>
+ <signal name="activate" handler="_on_playlist_renamed" swapped="no"/>
+ <signal name="changed" handler="_on_rename_entry_changed" swapped="no"/>
+ <signal name="key-press-event" handler="_on_rename_entry_key_pressed" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="_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>
+ <signal name="clicked" handler="_on_playlist_renamed" swapped="no" />
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="name">renaming_dialog</property>
+ </packing>
</child>
</object>
- <packing>
- <property name="name">renaming_dialog</property>
- </packing>
- </child>
- </object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
@@ -84,7 +88,7 @@
</packing>
</child>
<child>
- <object class="GtkLabel" id="songs_count">
+ <object class="GtkLabel" id="_songs_count_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
@@ -101,7 +105,7 @@
</packing>
</child>
<child>
- <object class="GtkMenuButton" id="playlist_menubutton">
+ <object class="GtkMenuButton" id="_menubutton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -123,5 +127,5 @@
<property name="height">2</property>
</packing>
</child>
- </object>
+ </template>
</interface>
diff --git a/gnomemusic/views/playlistview.py b/gnomemusic/views/playlistview.py
index 9ed93ec7..c357d925 100644
--- a/gnomemusic/views/playlistview.py
+++ b/gnomemusic/views/playlistview.py
@@ -22,8 +22,9 @@
# code, but you are not obligated to do so. If you do not wish to do so,
# delete this exception statement from your version.
-from gettext import gettext as _, ngettext
-from gi.repository import Gio, GLib, GObject, Gtk, Gdk, Pango
+from gettext import gettext as _
+
+from gi.repository import Gio, GLib, GObject, Gtk, Pango
from gnomemusic import log
from gnomemusic.grilo import grilo
@@ -31,6 +32,8 @@ from gnomemusic.player import DiscoveryStatus
from gnomemusic.playlists import Playlists, StaticPlaylists
from gnomemusic.views.baseview import BaseView
from gnomemusic.widgets.notificationspopup import PlaylistNotification
+from gnomemusic.widgets.playlistcontextmenu import PlaylistContextMenu
+from gnomemusic.widgets.playlistcontrols import PlaylistControls
from gnomemusic.widgets.playlistdialog import PlaylistDialog
import gnomemusic.utils as utils
@@ -69,26 +72,10 @@ class PlaylistView(BaseView):
self._add_list_renderers()
- 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_entry.connect(
- 'key-press-event', self._on_rename_entry_key_pressed)
- 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')
-
- builder = Gtk.Builder()
- builder.add_from_resource('/org/gnome/Music/PlaylistContextMenu.ui')
- self._popover_menu = builder.get_object('song_menu')
- self._song_popover = Gtk.Popover.new_from_model(
- self._view, self._popover_menu)
- self._song_popover.set_position(Gtk.PositionType.BOTTOM)
+ self._pl_ctrls = PlaylistControls()
+ self._pl_ctrls.connect('playlist-renamed', self._on_playlist_renamed)
+
+ self._song_popover = PlaylistContextMenu(self._view)
play_song = Gio.SimpleAction.new('play_song', None)
play_song.connect('activate', self._play_song)
@@ -120,7 +107,7 @@ class PlaylistView(BaseView):
self._window.add_action(self._playlist_rename_action)
self._grid.insert_row(0)
- self._grid.attach(headerbar, 1, 0, 1, 1)
+ self._grid.attach(self._pl_ctrls, 1, 0, 1, 1)
sidebar_container.set_size_request(220, -1)
sidebar_container.get_style_context().add_class('side-panel')
@@ -138,11 +125,7 @@ class PlaylistView(BaseView):
self._current_playlist_index = None
self.pls_todelete = {}
self._songs_todelete = {}
- self._songs_count = 0
- self._handler_rename_done_button = 0
- self._handler_rename_entry = 0
-
- self._update_songs_count()
+ self._update_songs_count(0)
self.model.connect('row-inserted', self._on_song_inserted)
self.model.connect('row-deleted', self._on_song_deleted)
@@ -156,8 +139,9 @@ class PlaylistView(BaseView):
self.show_all()
@log
- def _on_changes_pending(self, data=None):
- pass
+ def _update_songs_count(self, songs_count):
+ self._songs_count = songs_count
+ self._pl_ctrls.update_songs_count(songs_count)
@log
def _setup_view(self, view_type):
@@ -373,7 +357,6 @@ class PlaylistView(BaseView):
self._song_popover.set_relative_to(self._view)
self._song_popover.set_pointing_to(rect)
self._song_popover.popup()
- return
@log
def _drag_begin(self, widget_, drag_context):
@@ -539,10 +522,10 @@ class PlaylistView(BaseView):
playlist_name = utils.get_media_title(playlist)
if self.rename_active:
- self.disable_rename_playlist()
+ self._pl_ctrls.disable_rename_playlist()
self._current_playlist = playlist
- self._name_label.set_text(playlist_name)
+ self._pl_ctrls.props.playlist_name = playlist_name
self._current_playlist_index = row.get_index()
# if the active queue has been set by this playlist,
@@ -551,7 +534,7 @@ class PlaylistView(BaseView):
self.model.clear()
self._iter_to_clean = None
self._iter_to_clean_model = None
- self._songs_count = 0
+ self._update_songs_count(0)
grilo.populate_playlist_songs(playlist, self._add_song)
if self._current_playlist_is_protected():
@@ -588,7 +571,6 @@ class PlaylistView(BaseView):
:param Gtk.ListStore model: model
"""
if not song:
- self._update_songs_count()
self.emit('playlist-songs-loaded')
return None
@@ -599,15 +581,9 @@ class PlaylistView(BaseView):
index, [2, 3, 5, 9],
[title, artist, song, song.get_favourite()])
- self._songs_count += 1
+ self._update_songs_count(self._songs_count + 1)
return iter_
- @log
- def _update_songs_count(self):
- self._songs_count_label.set_text(
- ngettext("%d Song", "%d Songs", self._songs_count)
- % self._songs_count)
-
@log
def _on_play_activate(self, menuitem, data=None):
_iter = self.model.get_iter_first()
@@ -622,18 +598,15 @@ class PlaylistView(BaseView):
@log
def _current_playlist_is_protected(self):
current_playlist_id = self._current_playlist.get_id()
- if current_playlist_id in StaticPlaylists().get_ids():
- return True
- else:
- return False
+ return current_playlist_id in StaticPlaylists().get_ids()
@log
def _is_current_playlist(self, playlist):
"""Check if playlist is currently displayed"""
- if (self._current_playlist
- and playlist.get_id() == self._current_playlist.get_id()):
- return True
- return False
+ if self._current_playlist is None:
+ return False
+
+ return playlist.get_id() == self._current_playlist.get_id()
@log
def _get_removal_notification_message(self, type_, media_id):
@@ -717,7 +690,6 @@ class PlaylistView(BaseView):
'Playlist', self._current_playlist.get_id()):
path = self.model.get_path(iter_)
self.player.add_song(self.model, path, iter_)
- self._update_songs_count()
self._songs_todelete.pop(media_id)
@log
@@ -739,47 +711,22 @@ class PlaylistView(BaseView):
@GObject.Property(type=bool, default=False)
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):
- self._rename_done_button.set_sensitive(selection.get_text_length() > 0)
-
- @log
- def _on_rename_entry_key_pressed(self, widget, event):
- if event.keyval == Gdk.KEY_Escape:
- self.disable_rename_playlist()
-
- @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)
+ return self._pl_ctrls.props.rename_active
@log
def _stage_playlist_for_renaming(self, menuitem, data=None):
selection = self._sidebar.get_selected_row()
pl_torename = selection.playlist
+ self._pl_ctrls.enable_rename_playlist(pl_torename)
- def playlist_renamed_callback(widget):
- new_name = self._rename_entry.get_text()
- if not new_name:
- return
-
- selection.get_child().set_text(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()
+ @log
+ def _on_playlist_renamed(self, arguments, new_name):
+ selection = self._sidebar.get_selected_row()
+ selection.get_child().props.label = new_name
- 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)
+ pl_torename = selection.playlist
+ pl_torename.set_title(new_name)
+ playlists.rename(pl_torename, new_name)
@log
def _on_playlist_created(self, playlists, playlist):
@@ -797,20 +744,18 @@ class PlaylistView(BaseView):
@log
def _remove_song_from_playlist(self, playlist, item, index):
- if (self._is_current_playlist(playlist)):
- model = self.model
- else:
+ if not self._is_current_playlist(playlist):
return
+ model = self.model
+
iter_ = model.get_iter_from_string(str(index))
if self.player.playing_playlist(
'Playlist', self._current_playlist.get_id()):
self.player.remove_song(model, model.get_path(iter_))
model.remove(iter_)
- self._songs_count -= 1
- self._update_songs_count()
- return
+ self._update_songs_count(self._songs_count - 1)
@log
def populate(self):
diff --git a/gnomemusic/widgets/playlistcontextmenu.py b/gnomemusic/widgets/playlistcontextmenu.py
new file mode 100644
index 00000000..dfab7b9a
--- /dev/null
+++ b/gnomemusic/widgets/playlistcontextmenu.py
@@ -0,0 +1,45 @@
+# Copyright 2018 The GNOME Music Developers
+#
+# GNOME Music is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GNOME Music is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with GNOME Music; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The GNOME Music authors hereby grant permission for non-GPL compatible
+# GStreamer plugins to be used and distributed together with GStreamer
+# and GNOME Music. This permission is above and beyond the permissions
+# granted by the GPL license by which GNOME Music is covered. If you
+# modify this code, you may extend this exception to your version of the
+# code, but you are not obligated to do so. If you do not wish to do so,
+# delete this exception statement from your version.
+
+from gi.repository import Gtk
+
+from gnomemusic import log
+
+
+@Gtk.Template(resource_path='/org/gnome/Music/PlaylistContextMenu.ui')
+class PlaylistContextMenu(Gtk.Popover):
+
+ __gtype_name__ = 'PlaylistContextMenu'
+
+ _song_menu = Gtk.Template.Child()
+
+ def __repr__(self):
+ return '<PlaylistContextMenu>'
+
+ @log
+ def __init__(self, view):
+ super().__init__()
+
+ self.props.relative_to = view
+ self.bind_model(self._song_menu, None)
diff --git a/gnomemusic/widgets/playlistcontrols.py b/gnomemusic/widgets/playlistcontrols.py
new file mode 100644
index 00000000..882d9c20
--- /dev/null
+++ b/gnomemusic/widgets/playlistcontrols.py
@@ -0,0 +1,130 @@
+# Copyright 2018 The GNOME Music Developers
+#
+# GNOME Music is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GNOME Music is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with GNOME Music; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The GNOME Music authors hereby grant permission for non-GPL compatible
+# GStreamer plugins to be used and distributed together with GStreamer
+# and GNOME Music. This permission is above and beyond the permissions
+# granted by the GPL license by which GNOME Music is covered. If you
+# modify this code, you may extend this exception to your version of the
+# code, but you are not obligated to do so. If you do not wish to do so,
+# delete this exception statement from your version.
+
+import gettext
+
+from gi.repository import Gdk, GObject, Gtk
+
+from gnomemusic import log
+import gnomemusic.utils as utils
+
+
+@Gtk.Template(resource_path='/org/gnome/Music/PlaylistControls.ui')
+class PlaylistControls(Gtk.Grid):
+ """Widget holding the playlist controls"""
+
+ __gsignals__ = {
+ 'playlist-renamed': (GObject.SignalFlags.RUN_FIRST, None, (str,))
+ }
+
+ __gtype_name__ = "PlaylistControls"
+
+ _name_stack = Gtk.Template.Child()
+ _name_label = Gtk.Template.Child()
+ _rename_entry = Gtk.Template.Child()
+ _rename_done_button = Gtk.Template.Child()
+ _songs_count_label = Gtk.Template.Child()
+ _menubutton = Gtk.Template.Child()
+
+ playlist_name = GObject.Property(
+ type=str, default="", flags=GObject.ParamFlags.READWRITE)
+
+ def __repr__(self):
+ return '<PlaylistControls>'
+
+ def __init__(self):
+ super().__init__()
+ self.bind_property("playlist-name", self._name_label, "label")
+
+ @Gtk.Template.Callback()
+ @log
+ def _on_rename_entry_changed(self, selection):
+ selection_length = selection.props.text_length
+ self._rename_done_button.props.sensitive = selection_length > 0
+
+ @Gtk.Template.Callback()
+ @log
+ def _on_rename_entry_key_pressed(self, widget, event):
+ if event.keyval == Gdk.KEY_Escape:
+ self.disable_rename_playlist()
+
+ @Gtk.Template.Callback()
+ @log
+ def _on_playlist_renamed(self, widget):
+ new_name = self._rename_entry.props.text
+
+ if not new_name:
+ return
+
+ self.props.playlist_name = new_name
+ self.disable_rename_playlist()
+ self.emit('playlist-renamed', new_name)
+
+ @log
+ def enable_rename_playlist(self, pl_torename):
+ """Enables rename button and entry
+
+ :param Grl.Media pl_torename : The playlist to rename
+ """
+ self._name_stack.props.visible_child_name = "renaming_dialog"
+ self._set_rename_entry_text_and_focus(
+ utils.get_media_title(pl_torename))
+
+ @log
+ def disable_rename_playlist(self):
+ """Disables rename button and entry"""
+ self._name_stack.props.visible_child = self._name_label
+
+ @log
+ def update_songs_count(self, songs_count):
+ """Updates the number of songs label
+
+ :param int songs_count: The number of songs in the playlist
+ """
+ self._songs_count_label.props.label = gettext.ngettext(
+ "{} Song", "{} Songs", songs_count).format(songs_count)
+
+ @GObject.Property(type=bool, default=False)
+ def rename_active(self):
+ """Indicate if renaming dialog is active
+
+ :return: Renaming dialog active
+ :rtype: bool
+ """
+
+ return self._name_stack.props.visible_child_name == "renaming_dialog"
+
+ @GObject.Property
+ def rename_entry_text(self):
+ """Gets the value of the rename entry input
+
+ :return: Contents of rename entry field
+ :rtype: string
+ """
+ return self._rename_entry.props.text
+
+ @log
+ def _set_rename_entry_text_and_focus(self, text):
+ self._rename_entry.props.text = text
+ self._rename_entry.grab_focus()
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 7b70f3db..f18a2eb5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -26,6 +26,7 @@ gnomemusic/widgets/disclistboxwidget.py
gnomemusic/widgets/headerbar.py
gnomemusic/widgets/notificationspopup.py
gnomemusic/widgets/playertoolbar.py
+gnomemusic/widgets/playlistcontrols.py
gnomemusic/widgets/playlistdialog.py
gnomemusic/widgets/starhandlerwidget.py
gnomemusic/window.py
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]