[gnome-music/wip/mschraal/core: 118/177] albumsview: Make selection mode work and cleanup



commit 7dfc2d7fc9a8401507c87caae3330d7e52a47452
Author: Marinus Schraal <mschraal gnome org>
Date:   Wed Jun 26 14:54:06 2019 +0200

    albumsview: Make selection mode work and cleanup
    
    Makes selection mode work, however the selected items count refers
    to songs, not albums.

 gnomemusic/corealbum.py                      | 23 +++++++-
 gnomemusic/coredisc.py                       | 25 +++++++++
 gnomemusic/coremodel.py                      |  6 +-
 gnomemusic/coresong.py                       | 17 +++++-
 gnomemusic/grilowrappers/grltrackersource.py |  7 +--
 gnomemusic/views/albumsview.py               | 82 +++++++---------------------
 6 files changed, 85 insertions(+), 75 deletions(-)
---
diff --git a/gnomemusic/corealbum.py b/gnomemusic/corealbum.py
index 5081a451..40d4e19a 100644
--- a/gnomemusic/corealbum.py
+++ b/gnomemusic/corealbum.py
@@ -15,7 +15,6 @@ class CoreAlbum(GObject.GObject):
     composer = GObject.Property(type=str, default=None)
     duration = GObject.Property(type=int, default=0)
     media = GObject.Property(type=Grl.Media)
-    selected = GObject.Property(type=bool, default=False)
     title = GObject.Property(type=str)
     year = GObject.Property(type=str, default="----")
 
@@ -25,6 +24,7 @@ class CoreAlbum(GObject.GObject):
 
         self._coremodel = coremodel
         self._model = None
+        self._selected = False
         self.update(media)
 
     @log
@@ -47,8 +47,10 @@ class CoreAlbum(GObject.GObject):
         return self._model
 
     def _on_list_items_changed(self, model, pos, removed, added):
-        for coredisc in model:
-            coredisc.connect("notify::duration", self._on_duration_changed)
+        with self.freeze_notify():
+            for coredisc in model:
+                coredisc.connect("notify::duration", self._on_duration_changed)
+                coredisc.props.selected = self.props.selected
 
     def _on_duration_changed(self, coredisc, duration):
         duration = 0
@@ -57,3 +59,18 @@ class CoreAlbum(GObject.GObject):
             duration += coredisc.props.duration
 
         self.props.duration = duration
+
+    @GObject.Property(type=bool, default=False)
+    def selected(self):
+        return self._selected
+
+    @selected.setter
+    def selected(self, value):
+        self._selected = value
+
+        # The model is loaded on-demand, so the first time the model is
+        # returned it can still be empty. This is problem for returning
+        # a selection. Trigger loading of the model here if a selection
+        # is requested, it will trigger the filled model update as
+        # well.
+        self.props.model
diff --git a/gnomemusic/coredisc.py b/gnomemusic/coredisc.py
index 4c6bfbf1..a6d51854 100644
--- a/gnomemusic/coredisc.py
+++ b/gnomemusic/coredisc.py
@@ -19,6 +19,7 @@ class CoreDisc(GObject.GObject):
         self._filter_model = None
         self._model = None
         self._old_album_ids = []
+        self._selected = False
         self._sort_model = None
 
         self.update(media)
@@ -40,16 +41,24 @@ class CoreDisc(GObject.GObject):
 
             self._coremodel.get_model().connect(
                 "items-changed", self._on_core_changed)
+            self._model.connect("items-changed", self._on_disc_changed)
 
             self._get_album_disc(
                 self.props.media, self.props.disc_nr, self._filter_model)
 
+        self._on_disc_changed(self._model, None, None, None)
+
         return self._model
 
     def _on_core_changed(self, model, position, removed, added):
         self._get_album_disc(
             self.props.media, self.props.disc_nr, self._filter_model)
 
+    def _on_disc_changed(self, model, position, removed, added):
+        with self.freeze_notify():
+            for coresong in model:
+                coresong.props.selected = self._selected
+
     def _update_duration(self):
         duration = 0
 
@@ -93,3 +102,19 @@ class CoreDisc(GObject.GObject):
 
         self._coremodel._grilo.populate_album_disc_songs(
             media, discnr, _callback)
+
+    @GObject.Property(
+        type=bool, default=False, flags=GObject.BindingFlags.SYNC_CREATE)
+    def selected(self):
+        return self._selected
+
+    @selected.setter
+    def selected(self, value):
+        self._selected = value
+
+        # The model is loaded on-demand, so the first time the model is
+        # returned it can still be empty. This is problem for returning
+        # a selection. Trigger loading of the model here if a selection
+        # is requested, it will trigger the filled model update as
+        # well.
+        self.props.model
diff --git a/gnomemusic/coremodel.py b/gnomemusic/coremodel.py
index a1ae199f..0d2b43bc 100644
--- a/gnomemusic/coremodel.py
+++ b/gnomemusic/coremodel.py
@@ -158,7 +158,8 @@ class CoreModel(GObject.GObject):
 
                 for disc in model:
                     for model_song in disc.props.model:
-                        song = CoreSong(model_song.props.media)
+                        song = CoreSong(
+                            model_song.props.media, self._coreselection)
 
                         self._playlist_model.append(song)
                         song.bind_property(
@@ -177,7 +178,8 @@ class CoreModel(GObject.GObject):
                 for artist_album in model:
                     for disc in artist_album.model:
                         for model_song in disc.model:
-                            song = CoreSong(model_song.props.media)
+                            song = CoreSong(
+                                model_song.props.media, self._coreselection)
 
                             self._playlist_model.append(song)
                             song.bind_property(
diff --git a/gnomemusic/coresong.py b/gnomemusic/coresong.py
index 530098e1..0fcb03de 100644
--- a/gnomemusic/coresong.py
+++ b/gnomemusic/coresong.py
@@ -18,17 +18,18 @@ class CoreSong(GObject.GObject):
     duration = GObject.Property(type=int)
     media = GObject.Property(type=Grl.Media)
     play_count = GObject.Property(type=int)
-    selected = GObject.Property(type=bool, default=False)
     state = GObject.Property()  # FIXME: How to set an IntEnum type?
     title = GObject.Property(type=str)
     track_number = GObject.Property(type=int)
     url = GObject.Property(type=str)
 
     @log
-    def __init__(self, media):
+    def __init__(self, media, coreselection):
         super().__init__()
 
+        self._coreselection = coreselection
         self._favorite = False
+        self._selected = False
 
         self.update(media)
 
@@ -52,6 +53,18 @@ class CoreSong(GObject.GObject):
         self.props.media.set_favourite(self._favorite)
         grilo.toggle_favorite(self.props.media, True)
 
+    @GObject.Property(type=bool, default=False)
+    def selected(self):
+        return self._selected
+
+    @selected.setter
+    def selected(self, value):
+        if self._selected == value:
+            return
+
+        self._selected = value
+        self._coreselection.update_selection(self, self._selected)
+
     @log
     def update(self, media):
         self.props.media = media
diff --git a/gnomemusic/grilowrappers/grltrackersource.py b/gnomemusic/grilowrappers/grltrackersource.py
index 164a0937..957b5601 100644
--- a/gnomemusic/grilowrappers/grltrackersource.py
+++ b/gnomemusic/grilowrappers/grltrackersource.py
@@ -213,14 +213,12 @@ class GrlTrackerSource(GObject.GObject):
             # print("NO MEDIA", source, op_id, media, error)
             return
 
-        song = CoreSong(media)
+        song = CoreSong(media, self._core_selection)
         self._model.append(song)
         self._hash[media.get_id()] = song
 
         print("UPDATE ID", media.get_id(), media.get_title())
 
-        song.connect("notify::selected", self._core_selection.update_selection)
-
     def _on_source_removed(self, registry, source):
         print("removed", source.props.source_id)
 
@@ -263,11 +261,10 @@ class GrlTrackerSource(GObject.GObject):
             # print("NO MEDIA", source, op_id, media, error)
             return
 
-        song = CoreSong(media)
+        song = CoreSong(media, self._core_selection)
         self._model.append(song)
         self._hash[media.get_id()] = song
 
-        song.connect("notify::selected", self._core_selection.update_selection)
         # self._url_table[media.get_url()] = song
 
     def _initial_albums_fill(self, source):
diff --git a/gnomemusic/views/albumsview.py b/gnomemusic/views/albumsview.py
index df41c40d..c769ccc1 100644
--- a/gnomemusic/views/albumsview.py
+++ b/gnomemusic/views/albumsview.py
@@ -51,8 +51,6 @@ class AlbumsView(BaseView):
         self._album_widget.bind_property(
             "selection-mode", self, "selection-mode",
             GObject.BindingFlags.BIDIRECTIONAL)
-        self._album_widget.bind_property(
-            "selected-items-count", self, "selected-items-count")
 
         self.add(self._album_widget)
         self.albums_selected = []
@@ -104,6 +102,18 @@ class AlbumsView(BaseView):
     def _create_widget(self, corealbum):
         album_widget = AlbumCover(corealbum)
 
+        self.bind_property(
+            "selection-mode", album_widget, "selection-mode",
+            GObject.BindingFlags.SYNC_CREATE
+            | GObject.BindingFlags.BIDIRECTIONAL)
+
+        # NOTE: Adding SYNC_CREATE here will trigger all the nested
+        # models to be created. This will slow down initial start,
+        # but will improve initial 'selecte all' speed.
+        album_widget.bind_property(
+            "selected", corealbum, "selected",
+            GObject.BindingFlags.BIDIRECTIONAL)
+
         return album_widget
 
     @log
@@ -113,14 +123,14 @@ class AlbumsView(BaseView):
 
     @log
     def _on_child_activated(self, widget, child, user_data=None):
+        corealbum = child.props.corealbum
         if self.props.selection_mode:
             return
 
-        item = child.props.corealbum
         # Update and display the album widget if not in selection mode
-        self._album_widget.update(item)
+        self._album_widget.update(corealbum)
 
-        self._set_album_headerbar(item)
+        self._set_album_headerbar(corealbum)
         self.set_visible_child(self._album_widget)
 
     @log
@@ -136,72 +146,18 @@ class AlbumsView(BaseView):
         self._init = True
         self._view.show()
 
-    @log
-    def get_selected_songs(self, callback):
-        # FIXME: we call into private objects with full knowledge of
-        # what is there
-        if self._headerbar.props.state == HeaderBar.State.CHILD:
-            callback(self._album_widget.get_selected_songs())
-        else:
-            self.items_selected = []
-            self.items_selected_callback = callback
-            self.albums_index = 0
-            if len(self.albums_selected):
-                self._get_selected_album_songs()
-
-    def _create_album_item(self, item):
-        child = AlbumCover(item)
-
-        child.connect('notify::selected', self._on_selection_changed)
-
-        self.bind_property(
-            'selection-mode', child, 'selection-mode',
-            GObject.BindingFlags.BIDIRECTIONAL)
-
-        return child
-
-    @log
-    def _on_selection_changed(self, child, data=None):
-        if (child.props.selected
-                and child.props.media not in self.albums_selected):
-            self.albums_selected.append(child.props.media)
-        elif (not child.props.selected
-                and child.props.media in self.albums_selected):
-            self.albums_selected.remove(child.props.media)
-
-        self.props.selected_items_count = len(self.albums_selected)
-
-    @log
-    def _get_selected_album_songs(self):
-        grilo.populate_album_songs(
-            self.albums_selected[self.albums_index],
-            self._add_selected_item)
-        self.albums_index += 1
-
-    @log
-    def _add_selected_item(self, source, param, item, remaining=0, data=None):
-        if item:
-            self.items_selected.append(item)
-        if remaining == 0:
-            if self.albums_index < self.props.selected_items_count:
-                self._get_selected_album_songs()
-            else:
-                self.items_selected_callback(self.items_selected)
-
     def _toggle_all_selection(self, selected):
         """
         Selects or unselects all items without sending the notify::active
         signal for performance purposes.
         """
-        for child in self._view.get_children():
-            child.props.selected = selected
+        with self._window._app._coreselection.freeze_notify():
+            for child in self._view.get_children():
+                child.props.selected = selected
+                child.props.corealbum.props.selected = selected
 
-    @log
     def select_all(self):
-        self.albums_selected = list(self.all_items)
         self._toggle_all_selection(True)
 
-    @log
     def unselect_all(self):
-        self.albums_selected = []
         self._toggle_all_selection(False)


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