[gnome-music/wip/mschraal/core] searchview: Very basic functional



commit 3980a6272926b7196e8897494991031defbbfbbf
Author: Marinus Schraal <mschraal gnome org>
Date:   Sat Jul 6 17:04:44 2019 +0200

    searchview: Very basic functional

 gnomemusic/coremodel.py                         |  64 ++++
 gnomemusic/grilowrappers/grltrackerplaylists.py | 449 ++++++++++++++++++++++++
 gnomemusic/grilowrappers/grltrackersource.py    |   3 +
 gnomemusic/views/playlistsview.py               |  67 ++--
 4 files changed, 562 insertions(+), 21 deletions(-)
---
diff --git a/gnomemusic/coremodel.py b/gnomemusic/coremodel.py
index a895e689..8d7c4d78 100644
--- a/gnomemusic/coremodel.py
+++ b/gnomemusic/coremodel.py
@@ -1,3 +1,5 @@
+import math
+
 import gi
 gi.require_versions({'Dazzle': '1.0', 'Gfm': '0.1'})
 from gi.repository import Dazzle, GObject, Gio, Gfm, Gtk
@@ -7,6 +9,7 @@ from gnomemusic import log
 from gnomemusic.coreartist import CoreArtist
 from gnomemusic.coregrilo import CoreGrilo
 from gnomemusic.coresong import CoreSong
+from gnomemusic.grilowrappers.grltrackerplaylists import Playlist
 from gnomemusic.player import PlayerPlaylist
 from gnomemusic.songliststore import SongListStore
 from gnomemusic.widgets.songwidget import SongWidget
@@ -68,6 +71,14 @@ class CoreModel(GObject.GObject):
             self._artist_model)
         self._artist_search_model.set_filter_func(lambda a: False)
 
+        self._playlists_model = Gio.ListStore.new(Playlist)
+        self._playlists_model_filter = Dazzle.ListModelFilter.new(
+            self._playlists_model)
+        self._playlists_model_sort = Gfm.SortListModel.new(
+            self._playlists_model_filter)
+        self._playlists_model_sort.set_sort_func(
+            self._wrap_list_store_sort_func(self._playlists_sort))
+
         self._grilo = CoreGrilo(self, self._coreselection)
 
     def _filter_selected(self, coresong):
@@ -81,6 +92,24 @@ class CoreModel(GObject.GObject):
         name_b = artist_b.props.artist.casefold()
         return name_a > name_b
 
+    def _playlists_sort(self, playlist_a, playlist_b):
+        if playlist_a.props.is_smart:
+            if not playlist_b.props.is_smart:
+                return -1
+            title_a = playlist_a.props.title.casefold()
+            title_b = playlist_b.props.title.casefold()
+            return title_a > title_b
+
+        if playlist_b.props.is_smart:
+            return 1
+
+        # cannot use GLib.DateTime.compare
+        # https://gitlab.gnome.org/GNOME/pygobject/issues/334
+        # newest first
+        date_diff = playlist_b.props.creation_date.difference(
+            playlist_a.props.creation_date)
+        return math.copysign(1, date_diff)
+
     def _wrap_list_store_sort_func(self, func):
 
         def wrap(a, b, *user_data):
@@ -232,6 +261,30 @@ class CoreModel(GObject.GObject):
                     "items-changed", _on_items_changed)
 
                 self.emit("playlist-loaded")
+            elif playlist_type == PlayerPlaylist.Type.PLAYLIST:
+                # if self._search_signal_id:
+                #     self._song_search_model.disconnect(self._search_signal_id)
+
+                self._playlist_model.remove_all()
+
+                for model_song in model:
+                    song = CoreSong(
+                        model_song.props.media, self._coreselection,
+                        self._grilo)
+
+                    self._playlist_model.append(song)
+
+                    if model_song is coresong:
+                        song.props.state = SongWidget.State.PLAYING
+
+                    song.bind_property(
+                        "state", model_song, "state",
+                        GObject.BindingFlags.SYNC_CREATE)
+
+                # self._search_signal_id = self._song_search_model.connect(
+                #     "items-changed", _on_items_changed)
+
+                self.emit("playlist-loaded")
 
     def search(self, text):
         self._grilo.search(text)
@@ -296,3 +349,14 @@ class CoreModel(GObject.GObject):
         type=Gtk.ListStore, default=None, flags=GObject.ParamFlags.READABLE)
     def songs_gtkliststore(self):
         return self._songliststore
+
+    @GObject.Property(
+        type=Gio.ListStore, default=None, flags=GObject.ParamFlags.READABLE)
+    def playlists(self):
+        return self._playlists_model
+
+    @GObject.Property(
+        type=Gfm.SortListModel, default=None,
+        flags=GObject.ParamFlags.READABLE)
+    def playlists_sort(self):
+        return self._playlists_model_sort
diff --git a/gnomemusic/grilowrappers/grltrackerplaylists.py b/gnomemusic/grilowrappers/grltrackerplaylists.py
new file mode 100644
index 00000000..5fff7493
--- /dev/null
+++ b/gnomemusic/grilowrappers/grltrackerplaylists.py
@@ -0,0 +1,449 @@
+import time
+
+from gettext import gettext as _
+
+import gi
+gi.require_versions({"Grl": "0.3", 'Tracker': "2.0"})
+from gi.repository import Gio, Grl, GLib, GObject
+
+from gnomemusic.coresong import CoreSong
+import gnomemusic.utils as utils
+
+
+class GrlTrackerPlaylists(GObject.GObject):
+
+    METADATA_KEYS = [
+        Grl.METADATA_KEY_ALBUM,
+        Grl.METADATA_KEY_ALBUM_ARTIST,
+        Grl.METADATA_KEY_ALBUM_DISC_NUMBER,
+        Grl.METADATA_KEY_ARTIST,
+        Grl.METADATA_KEY_CREATION_DATE,
+        Grl.METADATA_KEY_COMPOSER,
+        Grl.METADATA_KEY_DURATION,
+        Grl.METADATA_KEY_FAVOURITE,
+        Grl.METADATA_KEY_ID,
+        Grl.METADATA_KEY_PLAY_COUNT,
+        Grl.METADATA_KEY_THUMBNAIL,
+        Grl.METADATA_KEY_TITLE,
+        Grl.METADATA_KEY_TRACK_NUMBER,
+        Grl.METADATA_KEY_URL
+    ]
+
+    def __repr__(self):
+        return "<GrlTrackerPlaylists>"
+
+    def __init__(self, source, coremodel, coreselection, grilo):
+        super().__init__()
+
+        self._coremodel = coremodel
+        self._coreselection = coreselection
+        self._grilo = grilo
+        self._source = source
+        self._model = self._coremodel.props.playlists
+
+        self._fast_options = Grl.OperationOptions()
+        self._fast_options.set_resolution_flags(
+            Grl.ResolutionFlags.FAST_ONLY | Grl.ResolutionFlags.IDLE_RELAY)
+
+        self._initial_playlists_fill()
+
+    def _initial_playlists_fill(self):
+        smart_playlists = {
+            "MostPlayed": MostPlayed(),
+            "NeverPlayed": NeverPlayed(),
+            "RecentlyPlayed": RecentlyPlayed(),
+            "RecentlyAdded": RecentlyAdded(),
+            "Favorites": Favorites()
+        }
+
+        for playlist in smart_playlists.values():
+
+            def _add_to_model(
+                    source, op_id, media, remaining, user_data, error):
+                if error:
+                    print("ERROR", error)
+                    return
+
+                if not media:
+                    user_data.props.count = user_data.props.model.get_n_items()
+                    return
+
+                coresong = CoreSong(media, self._coreselection, self._grilo)
+                user_data.props.model.append(coresong)
+
+            options = self._fast_options.copy()
+
+            self._source.query(
+                playlist.props.query, self.METADATA_KEYS, options,
+                _add_to_model, playlist)
+
+            self._model.append(playlist)
+
+        self._all_user_playlists()
+
+    def _all_user_playlists(self):
+        query = """
+        SELECT DISTINCT
+            rdf:type(?playlist)
+            tracker:id(?playlist) AS ?id
+            nie:title(?playlist) AS ?title
+            tracker:added(?playlist) AS ?creation_date
+            nfo:entryCounter(?playlist) AS ?childcount
+        WHERE
+        {
+            ?playlist a nmm:Playlist .
+            OPTIONAL { ?playlist nie:url ?url;
+                       tracker:available ?available . }
+            FILTER ( !STRENDS(LCASE(?url), '.m3u')
+                     && !STRENDS(LCASE(?url), '.m3u8')
+                     && !STRENDS(LCASE(?url), '.pls')
+                     || !BOUND(nfo:belongsToContainer(?playlist)) )
+            FILTER ( !BOUND(?tag) )
+            OPTIONAL { ?playlist nao:hasTag ?tag }
+        }
+        """.replace('\n', ' ').strip()
+
+        options = self._fast_options.copy()
+
+        self._source.query(
+            query, self.METADATA_KEYS, options, self._add_user_playlist)
+
+    def _add_user_playlist(
+            self, source, param, item, data, error):
+        if not item:
+            return
+
+        playlist = Playlist(
+            pl_id=item.get_id(), title=utils.get_media_title(item),
+            creation_date=item.get_creation_date(), source=self._source,
+            coremodel=self._coremodel, coreselection=self._coreselection,
+            grilo=self._grilo)
+
+        self._model.append(playlist)
+
+
+class Playlist(GObject.GObject):
+    """ Base class of all playlists """
+
+    METADATA_KEYS = [
+        Grl.METADATA_KEY_ALBUM,
+        Grl.METADATA_KEY_ALBUM_ARTIST,
+        Grl.METADATA_KEY_ALBUM_DISC_NUMBER,
+        Grl.METADATA_KEY_ARTIST,
+        Grl.METADATA_KEY_CREATION_DATE,
+        Grl.METADATA_KEY_COMPOSER,
+        Grl.METADATA_KEY_DURATION,
+        Grl.METADATA_KEY_FAVOURITE,
+        Grl.METADATA_KEY_ID,
+        Grl.METADATA_KEY_PLAY_COUNT,
+        Grl.METADATA_KEY_THUMBNAIL,
+        Grl.METADATA_KEY_TITLE,
+        Grl.METADATA_KEY_TRACK_NUMBER,
+        Grl.METADATA_KEY_URL
+    ]
+
+    count = GObject.Property(type=int, default=0)
+    creation_date = GObject.Property(type=GLib.DateTime, default=None)
+    is_smart = GObject.Property(type=bool, default=False)
+    pl_id = GObject.Property(type=str, default=None)
+    query = GObject.Property(type=str, default=None)
+    tag_text = GObject.Property(type=str, default=None)
+    title = GObject.Property(type=str, default=None)
+
+    def __repr__(self):
+        return "<Playlist>"
+
+    def __init__(
+            self, pl_id=None, query=None, tag_text=None, title=None,
+            creation_date=None, source=None, coremodel=None,
+            coreselection=None, grilo=None):
+        super().__init__()
+
+        self.props.pl_id = pl_id
+        self.props.query = query
+        self.props.tag_text = tag_text
+        self.props.title = title
+        self.props.creation_date = creation_date
+        self._model = None
+        self._source = source
+        self._coremodel = coremodel
+        self._coreselection = coreselection
+        self._grilo = grilo
+
+    @GObject.Property(type=Gio.ListStore, default=None)
+    def model(self):
+        if self._model is None:
+            self._model = Gio.ListStore()
+
+            self._populate_model()
+
+        return self._model
+
+    @model.setter
+    def model(self, value):
+        self._model = value
+
+    def _populate_model(self):
+        query = """
+        SELECT
+            rdf:type(?song)
+            ?song AS ?tracker_urn
+            tracker:id(?entry) AS ?id
+            nie:url(?song) AS ?url
+            nie:title(?song) AS ?title
+            nmm:artistName(nmm:performer(?song)) AS ?artist
+            nie:title(nmm:musicAlbum(?song)) AS ?album
+            nfo:duration(?song) AS ?duration
+            ?tag AS ?favourite
+            nie:contentAccessed(?song) AS ?last_played_time
+            nie:usageCounter(?song) AS ?play_count
+        WHERE {
+            ?playlist a nmm:Playlist ;
+                      a nfo:MediaList ;
+                        nfo:hasMediaFileListEntry ?entry .
+            ?entry a nfo:MediaFileListEntry ;
+                     nfo:entryUrl ?url .
+            ?song a nmm:MusicPiece ;
+                  a nfo:FileDataObject ;
+                    nie:url ?url .
+            OPTIONAL {
+                ?song nao:hasTag ?tag .
+                FILTER( ?tag = nao:predefined-tag-favorite )
+            }
+            FILTER (
+                %(filter_clause)s
+            )
+            FILTER (
+                NOT EXISTS { ?song a nmm:Video }
+                && NOT EXISTS { ?song a nmm:Playlist }
+            )
+        }
+        ORDER BY nfo:listPosition(?entry)
+        """.replace('\n', ' ').strip() % {
+            'filter_clause': 'tracker:id(?playlist) = ' + self.props.pl_id
+        }
+
+        def _add_to_playlist_cb(
+                source, op_id, media, remaining, user_data, error):
+            if not media:
+                self.props.count = self._model.get_n_items()
+                return
+
+            coresong = CoreSong(media, self._coreselection, self._grilo)
+            self._model.append(coresong)
+
+        options = Grl.OperationOptions()
+        options.set_resolution_flags(
+            Grl.ResolutionFlags.FAST_ONLY | Grl.ResolutionFlags.IDLE_RELAY)
+
+        self._source.query(
+            query, self.METADATA_KEYS, options, _add_to_playlist_cb, None)
+
+
+class SmartPlaylist(Playlist):
+    """Base class for smart playlists"""
+
+    def __repr__(self):
+        return "<SmartPlaylist>"
+
+    def __init__(self):
+        super().__init__()
+
+        self.props.is_smart = True
+
+    @GObject.Property(type=Gio.ListStore, default=None)
+    def model(self):
+        if self._model is None:
+            self._model = Gio.ListStore.new(CoreSong)
+
+        return self._model
+
+
+class MostPlayed(SmartPlaylist):
+    """Most Played smart playlist"""
+
+    def __init__(self):
+        super().__init__()
+
+        self.props.tag_text = "MOST_PLAYED"
+        # TRANSLATORS: this is a playlist name
+        self.props.title = _("Most Played")
+        self.props.query = """
+        SELECT
+            rdf:type(?song)
+            tracker:id(?song) AS ?id
+            ?song AS ?tracker_urn
+            nie:title(?song) AS ?title
+            nie:url(?song) AS ?url
+            nie:title(?song) AS ?title
+            nmm:artistName(nmm:performer(?song)) AS ?artist
+            nie:title(nmm:musicAlbum(?song)) AS ?album
+            nfo:duration(?song) AS ?duration
+            nie:usageCounter(?song) AS ?play_count
+            nmm:trackNumber(?song) AS ?track_number
+            nmm:setNumber(nmm:musicAlbumDisc(?song)) AS ?album_disc_number
+            ?tag AS ?favourite
+        WHERE {
+            ?song a nmm:MusicPiece ;
+                    nie:usageCounter ?count .
+            OPTIONAL { ?song nao:hasTag ?tag .
+                       FILTER (?tag = nao:predefined-tag-favorite) }
+        }
+        ORDER BY DESC(?count) LIMIT 50
+        """.replace('\n', ' ').strip()
+
+
+class NeverPlayed(SmartPlaylist):
+    """Never Played smart playlist"""
+
+    def __init__(self):
+        super().__init__()
+
+        self.props.tag_text = "NEVER_PLAYED"
+        # TRANSLATORS: this is a playlist name
+        self.props.title = _("Never Played")
+        self.props.query = """
+        SELECT
+            rdf:type(?song)
+            tracker:id(?song) AS ?id
+            ?song AS ?tracker_urn
+            nie:title(?song) AS ?title
+            nie:url(?song) AS ?url
+            nie:title(?song) AS ?title
+            nmm:artistName(nmm:performer(?song)) AS ?artist
+            nie:title(nmm:musicAlbum(?song)) AS ?album
+            nfo:duration(?song) AS ?duration
+            nie:usageCounter(?song) AS ?play_count
+            nmm:trackNumber(?song) AS ?track_number
+            nmm:setNumber(nmm:musicAlbumDisc(?song)) AS ?album_disc_number
+            ?tag AS ?favourite
+        WHERE {
+            ?song a nmm:MusicPiece ;
+            FILTER ( NOT EXISTS { ?song nie:usageCounter ?count .} )
+            OPTIONAL { ?song nao:hasTag ?tag .
+                       FILTER (?tag = nao:predefined-tag-favorite) }
+        } ORDER BY nfo:fileLastAccessed(?song) LIMIT 50
+        """.replace('\n', ' ').strip()
+
+
+class RecentlyPlayed(SmartPlaylist):
+    """Recently Played smart playlist"""
+
+    def __init__(self):
+        super().__init__()
+
+        self.props.tag_text = "RECENTLY_PLAYED"
+        # TRANSLATORS: this is a playlist name
+        self.props.title = _("Recently Played")
+
+        sparql_midnight_dateTime_format = "%Y-%m-%dT00:00:00Z"
+        days_difference = 7
+        seconds_difference = days_difference * 86400
+        compare_date = time.strftime(
+            sparql_midnight_dateTime_format,
+            time.gmtime(time.time() - seconds_difference))
+        self.props.query = """
+        SELECT
+            rdf:type(?song)
+            tracker:id(?song) AS ?id
+            ?song AS ?tracker_urn
+            nie:title(?song) AS ?title
+            nie:url(?song) AS ?url
+            nie:title(?song) AS ?title
+            nmm:artistName(nmm:performer(?song)) AS ?artist
+            nie:title(nmm:musicAlbum(?song)) AS ?album
+            nfo:duration(?song) AS ?duration
+            nie:usageCounter(?song) AS ?play_count
+            nmm:trackNumber(?song) AS ?track_number
+            nmm:setNumber(nmm:musicAlbumDisc(?song)) AS ?album_disc_number
+            ?tag AS ?favourite
+        WHERE {
+            ?song a nmm:MusicPiece ;
+                    nie:contentAccessed ?last_played .
+            FILTER ( ?last_played > '%(compare_date)s'^^xsd:dateTime
+                     && EXISTS { ?song nie:usageCounter ?count .} )
+            OPTIONAL { ?song nao:hasTag ?tag .
+                       FILTER (?tag = nao:predefined-tag-favorite) }
+        } ORDER BY DESC(?last_played) LIMIT 50
+        """.replace('\n', ' ').strip() % {
+            'compare_date': compare_date
+        }
+
+
+class RecentlyAdded(SmartPlaylist):
+    """Recently Added smart playlist"""
+
+    def __init__(self):
+        super().__init__()
+
+        self.props.tag_text = "RECENTLY_ADDED"
+        # TRANSLATORS: this is a playlist name
+        self.props.title = _("Recently Added")
+
+        sparql_midnight_dateTime_format = "%Y-%m-%dT00:00:00Z"
+        days_difference = 7
+        seconds_difference = days_difference * 86400
+        compare_date = time.strftime(
+            sparql_midnight_dateTime_format,
+            time.gmtime(time.time() - seconds_difference))
+        self.props.query = """
+        SELECT
+            rdf:type(?song)
+            tracker:id(?song) AS ?id
+            ?song AS ?tracker_urn
+            nie:title(?song) AS ?title
+            nie:url(?song) AS ?url
+            nie:title(?song) AS ?title
+            nmm:artistName(nmm:performer(?song)) AS ?artist
+            nie:title(nmm:musicAlbum(?song)) AS ?album
+            nfo:duration(?song) AS ?duration
+            nie:usageCounter(?song) AS ?play_count
+            nmm:trackNumber(?song) AS ?track_number
+            nmm:setNumber(nmm:musicAlbumDisc(?song)) AS ?album_disc_number
+            ?tag AS ?favourite
+        WHERE {
+            ?song a nmm:MusicPiece ;
+                    tracker:added ?added .
+            FILTER ( tracker:added(?song) > '%(compare_date)s'^^xsd:dateTime )
+            OPTIONAL { ?song nao:hasTag ?tag .
+                       FILTER (?tag = nao:predefined-tag-favorite) }
+        } ORDER BY DESC(tracker:added(?song)) LIMIT 50
+        """.replace('\n', ' ').strip() % {
+            'compare_date': compare_date,
+        }
+
+
+class Favorites(SmartPlaylist):
+    """Favorites smart playlist"""
+
+    def __init__(self):
+        super().__init__()
+
+        self.props.tag_text = "FAVORITES"
+        # TRANSLATORS: this is a playlist name
+        self.props.title = _("Favorite Songs")
+        self.props.query = """
+            SELECT
+                rdf:type(?song)
+                tracker:id(?song) AS ?id
+                ?song AS ?tracker_urn
+                nie:title(?song) AS ?title
+                nie:url(?song) AS ?url
+                nie:title(?song) AS ?title
+                nmm:artistName(nmm:performer(?song)) AS ?artist
+                nie:title(nmm:musicAlbum(?song)) AS ?album
+                nfo:duration(?song) AS ?duration
+                nie:usageCounter(?song) AS ?play_count
+                nmm:trackNumber(?song) AS ?track_number
+                nmm:setNumber(nmm:musicAlbumDisc(?song)) AS ?album_disc_number
+                nao:predefined-tag-favorite AS ?favourite
+            WHERE {
+                ?song a nmm:MusicPiece ;
+                        nie:isStoredAs ?as ;
+                        nao:hasTag nao:predefined-tag-favorite .
+                ?as nie:url ?url .
+            OPTIONAL { ?song nao:hasTag ?tag .
+                       FILTER (?tag = nao:predefined-tag-favorite) }
+
+            } ORDER BY DESC(tracker:added(?song))
+        """.replace('\n', ' ').strip()
diff --git a/gnomemusic/grilowrappers/grltrackersource.py b/gnomemusic/grilowrappers/grltrackersource.py
index fcefcc2d..46e9b131 100644
--- a/gnomemusic/grilowrappers/grltrackersource.py
+++ b/gnomemusic/grilowrappers/grltrackersource.py
@@ -6,6 +6,7 @@ from gnomemusic.corealbum import CoreAlbum
 from gnomemusic.coreartist import CoreArtist
 from gnomemusic.coredisc import CoreDisc
 from gnomemusic.coresong import CoreSong
+from gnomemusic.grilowrappers.grltrackerplaylists import GrlTrackerPlaylists
 
 
 class GrlTrackerSource(GObject.GObject):
@@ -54,6 +55,8 @@ class GrlTrackerSource(GObject.GObject):
         self._initial_albums_fill(self._source)
         self._initial_artists_fill(self._source)
 
+        GrlTrackerPlaylists(source, coremodel, coreselection, grilo)
+
         self._source.connect("content-changed", self._on_content_changed)
 
     @GObject.Property(
diff --git a/gnomemusic/views/playlistsview.py b/gnomemusic/views/playlistsview.py
index 7a8c0747..c14ff88a 100644
--- a/gnomemusic/views/playlistsview.py
+++ b/gnomemusic/views/playlistsview.py
@@ -27,7 +27,6 @@ from gettext import gettext as _
 from gi.repository import Gdk, Gio, GLib, GObject, Gtk, Pango
 
 from gnomemusic import log
-from gnomemusic.grilo import grilo
 from gnomemusic.player import ValidationStatus, PlayerPlaylist
 from gnomemusic.playlists import Playlists
 from gnomemusic.views.baseview import BaseView
@@ -36,6 +35,7 @@ from gnomemusic.widgets.playlistcontextmenu import PlaylistContextMenu
 from gnomemusic.widgets.playlistcontrols import PlaylistControls
 from gnomemusic.widgets.playlistdialog import PlaylistDialog
 from gnomemusic.widgets.sidebarrow import SidebarRow
+from gnomemusic.widgets.songwidget import SongWidget
 import gnomemusic.utils as utils
 
 
@@ -59,12 +59,14 @@ class PlaylistsView(BaseView):
         super().__init__(
             'playlists', _("Playlists"), window, sidebar_container)
 
+        self._coremodel = window._app.props.coremodel
+        self._model = self._coremodel.props.playlists
         self._window = window
         self.player = player
 
-        self._view.get_style_context().add_class('songs-list')
+        # self._view.get_style_context().add_class('songs-list')
 
-        self._add_list_renderers()
+        # self._add_list_renderers()
 
         self._pl_ctrls = PlaylistControls()
         self._pl_ctrls.connect('playlist-renamed', self._on_playlist_renamed)
@@ -134,7 +136,8 @@ class PlaylistsView(BaseView):
 
         self._playlists_model = self._playlists.get_playlists_model()
         self._sidebar.bind_model(
-            self._playlists_model, self._add_playlist_to_sidebar)
+            self._coremodel.props.playlists_sort,
+            self._add_playlist_to_sidebar)
         self._playlists_model.connect(
             "items-changed", self._on_playlists_model_changed)
 
@@ -150,17 +153,19 @@ class PlaylistsView(BaseView):
         view_container = Gtk.ScrolledWindow(hexpand=True, vexpand=True)
         self._box.pack_start(view_container, True, True, 0)
 
-        self._view = Gtk.TreeView()
-        self._view.set_headers_visible(False)
-        self._view.set_valign(Gtk.Align.START)
-        self._view.set_model(self.model)
-        self._view.set_activate_on_single_click(True)
-        self._view.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
+        self._view = Gtk.ListBox()
 
-        self._view.connect('row-activated', self._on_song_activated)
-        self._view.connect('drag-begin', self._drag_begin)
-        self._view.connect('drag-end', self._drag_end)
-        self._song_drag = {'active': False}
+        # self._view = Gtk.TreeView()
+        # self._view.set_headers_visible(False)
+        # self._view.set_valign(Gtk.Align.START)
+        # self._view.set_model(self.model)
+        # self._view.set_activate_on_single_click(True)
+        # self._view.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
+
+        # self._view.connect('row-activated', self._on_song_activated)
+        # self._view.connect('drag-begin', self._drag_begin)
+        # self._view.connect('drag-end', self._drag_end)
+        # self._song_drag = {'active': False}
 
         self._controller = Gtk.GestureMultiPress().new(self._view)
         self._controller.props.propagation_phase = Gtk.PropagationPhase.CAPTURE
@@ -295,11 +300,11 @@ class PlaylistsView(BaseView):
         if removed == 0:
             return
 
-        row_next = (self._sidebar.get_row_at_index(position)
-                    or self._sidebar.get_row_at_index(position - 1))
-        if row_next:
-            self._sidebar.select_row(row_next)
-            row_next.emit("activate")
+        # row_next = (self._sidebar.get_row_at_index(position)
+        #             or self._sidebar.get_row_at_index(position - 1))
+        # if row_next:
+        #     self._sidebar.select_row(row_next)
+        #     row_next.emit("activate")
 
     @log
     def _on_song_validated(self, player, index, status):
@@ -527,9 +532,12 @@ class PlaylistsView(BaseView):
         if self.rename_active:
             self._pl_ctrls.disable_rename_playlist()
 
+        self._view.bind_model(playlist.props.model, self._create_song_widget)
+
         self._current_playlist = playlist
         self._pl_ctrls.props.playlist_name = playlist_name
-
+        self._update_songs_count(playlist.props.count)
+        return
         # if the active queue has been set by this playlist,
         # use it as model, otherwise build the liststore
         self._view.set_model(None)
@@ -538,7 +546,7 @@ class PlaylistsView(BaseView):
         self._iter_to_clean_model = None
         self._pl_ctrls.freeze_notify()
         self._update_songs_count(0)
-        grilo.populate_playlist_songs(playlist, self._add_song)
+        # grilo.populate_playlist_songs(playlist, self._add_song)
 
         protected_pl = self._current_playlist.props.is_smart
         self._playlist_delete_action.set_enabled(not protected_pl)
@@ -546,6 +554,23 @@ class PlaylistsView(BaseView):
         self._remove_song_action.set_enabled(not protected_pl)
         self._view.set_reorderable(not protected_pl)
 
+    def _create_song_widget(self, coresong):
+        song_widget = SongWidget(coresong)
+
+        song_widget.connect('button-release-event', self._song_activated)
+
+        return song_widget
+
+    def _song_activated(self, widget, event):
+        print(widget)
+        print(self._view.get_focus_child())
+        self._coremodel.set_playlist_model(
+            PlayerPlaylist.Type.PLAYLIST, widget.props.coresong,
+            self._current_playlist.props.model)
+        self.player.play()
+
+        return True
+
     @log
     def _add_song(self, source, param, song, remaining=0, data=None):
         """Grilo.populate_playlist_songs callback.


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