[gnome-games/wip/exalm/db: 26/29] ui: Use GameModel and PlatformModel for collection



commit 246e1729df3ce6929d46d6d431e6c0e2c0bbc720
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Sat Feb 8 19:25:48 2020 +0500

    ui: Use GameModel and PlatformModel for collection
    
    Make the code more organized, and prepare for database caching.
    
    Unfortunately, it also means we cannot use set_filter_func() and have to
    implement filters manually. Long-term we should use GTK4's filter model,
    but now this will have to do.

 src/ui/application-window.vala   |   8 +--
 src/ui/application.vala          |   8 +--
 src/ui/collection-box.vala       |  16 +++---
 src/ui/collection-icon-view.vala |  90 ++++++------------------------
 src/ui/collection-view.vala      |  14 ++---
 src/ui/platform-list-item.vala   |   4 --
 src/ui/platforms-view.vala       | 115 +++++++++++++++------------------------
 7 files changed, 86 insertions(+), 169 deletions(-)
---
diff --git a/src/ui/application-window.vala b/src/ui/application-window.vala
index 3f1970da..63115f60 100644
--- a/src/ui/application-window.vala
+++ b/src/ui/application-window.vala
@@ -59,10 +59,10 @@ private class Games.ApplicationWindow : Gtk.ApplicationWindow {
        private uint inhibit_cookie;
        private Gtk.ApplicationInhibitFlags inhibit_flags;
 
-       public ListModel collection { get; construct; }
+       public GameModel game_model { get; construct; }
 
-       public ApplicationWindow (Application application, ListModel collection) {
-               Object (application: application, collection: collection);
+       public ApplicationWindow (Application application, GameModel game_model) {
+               Object (application: application, game_model: game_model);
 
                current_view = collection_view;
        }
@@ -82,7 +82,7 @@ private class Games.ApplicationWindow : Gtk.ApplicationWindow {
                if (settings.get_boolean ("window-maximized"))
                        maximize ();
 
-               collection_view = new CollectionView (this, collection);
+               collection_view = new CollectionView (this, game_model);
                display_view = new DisplayView (this);
 
                content_box.add (collection_view.content_box);
diff --git a/src/ui/application.vala b/src/ui/application.vala
index 20acd729..02a35307 100644
--- a/src/ui/application.vala
+++ b/src/ui/application.vala
@@ -12,7 +12,7 @@ public class Games.Application : Gtk.Application {
        private bool game_list_loaded;
 
        private GameCollection game_collection;
-       private ListStore list_store;
+       private GameModel game_model;
        private CoverLoader cover_loader;
 
        private Manette.Monitor manette_monitor;
@@ -203,8 +203,8 @@ public class Games.Application : Gtk.Application {
                init_game_sources ();
                load_game_list.begin ();
 
-               list_store = new ListStore (typeof (Game));
-               game_collection.game_added.connect (game => list_store.append (game));
+               game_model = new GameModel ();
+               game_collection.game_added.connect (game_model.add_game);
 
                cover_loader = new CoverLoader ();
        }
@@ -215,7 +215,7 @@ public class Games.Application : Gtk.Application {
                        return;
                }
 
-               window = new ApplicationWindow (this, list_store);
+               window = new ApplicationWindow (this, game_model);
                window.destroy.connect (() => {
                        quit_application ();
                });
diff --git a/src/ui/collection-box.vala b/src/ui/collection-box.vala
index 81f6181c..31931139 100644
--- a/src/ui/collection-box.vala
+++ b/src/ui/collection-box.vala
@@ -4,7 +4,7 @@
 private class Games.CollectionBox : Gtk.Box {
        public signal void game_activated (Game game);
 
-       public ListModel collection { get; construct; }
+       public GameModel game_model { get; construct; }
        public bool search_mode { get; set; }
        public bool loading_notification { get; set; }
 
@@ -65,12 +65,12 @@ private class Games.CollectionBox : Gtk.Box {
                var icon_name = Config.APPLICATION_ID + "-symbolic";
                viewstack.child_set (collection_view, "icon-name", icon_name);
 
-               collection_view.model = collection;
-               platform_view.model = collection;
+               collection_view.game_model = game_model;
+               platform_view.game_model = game_model;
        }
 
-       public CollectionBox (ListModel collection) {
-               Object (collection: collection);
+       public CollectionBox (GameModel game_model) {
+               Object (game_model: game_model);
        }
 
        public void show_error (string error_message) {
@@ -128,11 +128,13 @@ private class Games.CollectionBox : Gtk.Box {
        }
 
        public bool found_games () {
-               for (int i = 0; i < collection.get_n_items (); i++) {
-                       var game = collection.get_item (i) as Game;
+               for (int i = 0; i < game_model.get_n_items (); i++) {
+                       var game = game_model.get_item (i) as Game;
+
                        if (game.matches_search_terms (filtering_terms))
                                return true;
                }
+
                return false;
        }
 
diff --git a/src/ui/collection-icon-view.vala b/src/ui/collection-icon-view.vala
index 7f4248e6..222af0f1 100644
--- a/src/ui/collection-icon-view.vala
+++ b/src/ui/collection-icon-view.vala
@@ -12,26 +12,14 @@ private class Games.CollectionIconView : Gtk.Bin {
                this.game_filter = game_filter;
        }
 
-       private ulong model_changed_id;
-       private ListModel _model;
-       public ListModel model {
-               get { return _model; }
+       private GameModel _game_model;
+       public GameModel game_model {
+               get { return _game_model; }
                set {
-                       if (model != null)
-                               model.disconnect (model_changed_id);
+                       _game_model = value;
+                       flow_box.bind_model (game_model, add_game);
 
-                       _model = value;
-                       clear_content ();
-                       if (model == null)
-                               return;
-
-                       for (int i = 0; i < model.get_n_items (); i++) {
-                               var game = model.get_item (i) as Game;
-                               add_game (game);
-                       }
-                       model_changed_id = model.items_changed.connect (on_items_changed);
-
-                       flow_box.invalidate_sort ();
+                       game_model.items_changed.connect (apply_filter);
                }
        }
 
@@ -64,8 +52,6 @@ private class Games.CollectionIconView : Gtk.Bin {
 
        construct {
                flow_box.max_children_per_line = uint.MAX;
-               flow_box.set_filter_func (filter_box);
-               flow_box.set_sort_func (sort_boxes);
        }
 
        [GtkCallback]
@@ -109,7 +95,7 @@ private class Games.CollectionIconView : Gtk.Bin {
 
        public void set_filter (string[] filtering_terms) {
                this.filtering_terms = filtering_terms;
-               flow_box.invalidate_filter ();
+               apply_filter ();
        }
 
        public void reset_scroll_position () {
@@ -144,10 +130,6 @@ private class Games.CollectionIconView : Gtk.Bin {
                flow_box.unselect_all ();
        }
 
-       public void invalidate_flow_box_filter () {
-               flow_box.invalidate_filter ();
-       }
-
        [GtkCallback]
        private bool on_gamepad_browse (Gtk.DirectionType direction) {
                if (!has_game_selected ())
@@ -177,49 +159,27 @@ private class Games.CollectionIconView : Gtk.Bin {
 
        [GtkCallback]
        private void on_child_activated (Gtk.FlowBoxChild child) {
-               if (child.get_child () is GameIconView)
-                       on_game_view_activated (child.get_child () as GameIconView);
-       }
+               var game_view = child.get_child () as GameIconView;
 
-       private void on_game_view_activated (GameIconView game_view) {
                game_activated (game_view.game);
        }
 
-       private void on_items_changed (uint position, uint removed, uint added) {
-               // FIXME: currently games are never removed, update this function if
-               // necessary.
-               assert (removed == 0);
-
-               for (uint i = position; i < position + added; i++) {
-                       var game = model.get_item (i) as Game;
-                       add_game (game);
-               }
-       }
+       private Gtk.Widget add_game (Object item) {
+               var game = item as Game;
 
-       private void add_game (Game game) {
                var game_view = new GameIconView (game);
-               var child = new Gtk.FlowBoxChild ();
-
-               game_view.visible = true;
-               child.visible = true;
+               game_view.show ();
 
-               child.add (game_view);
-               flow_box.add (child);
+               return game_view;
        }
 
-       private void clear_content () {
-               flow_box.forall ((child) => { flow_box.remove (child); });
-       }
-
-       private bool filter_box (Gtk.FlowBoxChild child) {
-               var game_view = child.get_child () as GameIconView;
-               if (game_view == null)
-                       return false;
-
-               if (game_view.game == null)
-                       return false;
+       public void apply_filter () {
+               flow_box.foreach (widget => {
+                       var child = widget as Gtk.FlowBoxChild;
+                       var game_view = child.get_child () as GameIconView;
 
-               return filter_game (game_view.game);
+                       widget.visible = filter_game (game_view.game);
+               });
        }
 
        private bool filter_game (Game game) {
@@ -229,20 +189,6 @@ private class Games.CollectionIconView : Gtk.Bin {
                return game.matches_search_terms (filtering_terms);
        }
 
-       private int sort_boxes (Gtk.FlowBoxChild child1, Gtk.FlowBoxChild child2) {
-               var game_view1 = child1.get_child () as GameIconView;
-               var game_view2 = child2.get_child () as GameIconView;
-
-               assert (game_view1 != null);
-               assert (game_view2 != null);
-
-               return sort_games (game_view1.game, game_view2.game);
-       }
-
-       private int sort_games (Game game1, Game game2) {
-               return game1.name.collate (game2.name);
-       }
-
        [GtkCallback]
        private void on_size_allocate (Gtk.Allocation allocation) {
                // If the window's width is less than half the width of a 1920×1080
diff --git a/src/ui/collection-view.vala b/src/ui/collection-view.vala
index 23fe5643..259f0121 100644
--- a/src/ui/collection-view.vala
+++ b/src/ui/collection-view.vala
@@ -33,7 +33,7 @@ private class Games.CollectionView : Object, UiView {
        }
 
        public Gtk.Window window { get; construct; }
-       public ListModel collection { get; construct; }
+       public GameModel game_model { get; construct; }
 
        public bool loading_notification { get; set; }
        public bool search_mode { get; set; }
@@ -47,16 +47,16 @@ private class Games.CollectionView : Object, UiView {
        private KonamiCode konami_code;
 
        construct {
-               box = new CollectionBox (collection);
+               box = new CollectionBox (game_model);
                header_bar = new CollectionHeaderBar ();
                box.game_activated.connect (game => {
                        game_activated (game);
                });
 
-               collection.items_changed.connect (() => {
-                       is_collection_empty = collection.get_n_items () == 0;
+               game_model.items_changed.connect (() => {
+                       is_collection_empty = game_model.get_n_items () == 0;
                });
-               is_collection_empty = collection.get_n_items () == 0;
+               is_collection_empty = game_model.get_n_items () == 0;
 
                header_bar.viewstack = box.viewstack;
                is_collection_empty = true;
@@ -98,8 +98,8 @@ private class Games.CollectionView : Object, UiView {
                konami_code.code_performed.connect (on_konami_code_performed);
        }
 
-       public CollectionView (Gtk.Window window, ListModel collection) {
-               Object (window: window, collection: collection);
+       public CollectionView (Gtk.Window window, GameModel game_model) {
+               Object (window: window, game_model: game_model);
        }
 
        public void show_error (string error_message) {
diff --git a/src/ui/platform-list-item.vala b/src/ui/platform-list-item.vala
index 3fd6c13e..653910d9 100644
--- a/src/ui/platform-list-item.vala
+++ b/src/ui/platform-list-item.vala
@@ -14,8 +14,4 @@ private class Games.PlatformListItem : Gtk.ListBoxRow {
        public PlatformListItem (Platform platform) {
                Object (platform: platform);
        }
-
-       public static int compare (PlatformListItem a, PlatformListItem b) {
-               return a.platform.get_name ().collate (b.platform.get_name ());
-       }
 }
diff --git a/src/ui/platforms-view.vala b/src/ui/platforms-view.vala
index db774942..755a4077 100644
--- a/src/ui/platforms-view.vala
+++ b/src/ui/platforms-view.vala
@@ -15,28 +15,22 @@ private class Games.PlatformsView : Gtk.Bin {
        [GtkChild]
        private GamepadBrowse gamepad_browse;
 
-       private ulong model_items_changed_id;
-
-       private GenericSet<Platform> platforms;
        private Platform selected_platform;
        private bool has_used_gamepad;
 
        private string[] filtering_terms;
 
-       private ListModel _model;
-       public ListModel model {
-               get { return _model; }
+       private GameModel _game_model;
+       public GameModel game_model {
+               get { return _game_model; }
                set {
-                       if (model_items_changed_id != 0) {
-                               _model.disconnect (model_items_changed_id);
-                               model_items_changed_id = 0;
-                       }
+                       _game_model = value;
+                       collection_view.game_model = value;
 
-                       _model = value;
-                       collection_view.model = _model;
+                       var platform_model = new PlatformModel (value);
+                       list_box.bind_model (platform_model, add_platform);
 
-                       if (model != null)
-                               model_items_changed_id = model.items_changed.connect (on_model_changed);
+                       platform_model.items_changed.connect (apply_filter);
                }
        }
 
@@ -60,18 +54,37 @@ private class Games.PlatformsView : Gtk.Bin {
        public string subview_title { get; set; }
 
        construct {
-               platforms = new GenericSet<Platform> (Platform.hash, Platform.equal);
+               collection_view.set_game_filter (filter_game);
+       }
 
-               list_box.set_sort_func (sort_rows);
+       private void apply_filter () {
+               list_box.foreach (widget => {
+                       var row = widget as PlatformListItem;
 
-               collection_view.set_game_filter (filter_game);
+                       if (row == null)
+                               return;
+
+                       widget.set_visible (filter_list (row));
+               });
        }
 
-       private int sort_rows (Gtk.ListBoxRow row1, Gtk.ListBoxRow row2) {
-               var item1 = row1 as PlatformListItem;
-               var item2 = row2 as PlatformListItem;
+       private bool filter_list (PlatformListItem item) {
+               if (item.platform == null)
+                       return false;
+
+               Game[] visible_games = {};
+               for (int i = 0; i < game_model.get_n_items (); i++) {
+                       var game = game_model.get_item (i) as Game;
 
-               return PlatformListItem.compare (item1, item2);
+                       if (game.matches_search_terms (filtering_terms))
+                               visible_games += game;
+               }
+
+               foreach (var game in visible_games)
+                       if (game.get_platform () == item.platform)
+                               return true;
+
+               return false;
        }
 
        private bool filter_game (Game game) {
@@ -103,7 +116,9 @@ private class Games.PlatformsView : Gtk.Bin {
        public void set_filter (string[] filtering_terms) {
                this.filtering_terms = filtering_terms;
                collection_view.set_filter (filtering_terms);
-               hide_empty_sidebar_items ();
+
+               apply_filter ();
+               select_first_visible_row ();
        }
 
        public bool gamepad_button_press_event (Manette.Event event) {
@@ -204,29 +219,11 @@ private class Games.PlatformsView : Gtk.Bin {
                selected_platform = row.platform;
                subview_title = selected_platform.get_name ();
 
-               collection_view.invalidate_flow_box_filter ();
+               collection_view.apply_filter ();
                collection_view.reset_scroll_position ();
        }
 
-       private void on_model_changed (uint position, uint removed, uint added) {
-               // FIXME: currently games are never removed, update this function if
-               // necessary.
-               assert (removed == 0);
-
-               for (uint i = position; i < position + added; i++) {
-                       var game = model.get_item (i) as Game;
-                       var platform = game.get_platform ();
-
-                       if (!platforms.contains (platform)) {
-                               platforms.add (platform);
-
-                               var platform_list_item = new PlatformListItem (platform);
-                               list_box.add (platform_list_item);
-                       }
-               }
-       }
-
-       public void select_first_visible_row () {
+       private void select_first_visible_row () {
                foreach (var child in list_box.get_children ()) {
                        var row = child as Gtk.ListBoxRow;
 
@@ -253,37 +250,13 @@ private class Games.PlatformsView : Gtk.Bin {
                }
        }
 
-       private void hide_empty_sidebar_items () {
-               // Create an array of all the games which fit the search text entered
-               // in the top search bar
-               Game[] visible_games = {};
-
-               for (int i = 0; i < model.get_n_items (); i++) {
-                       var game = model.get_item (i) as Game;
-
-                       if (game.matches_search_terms (filtering_terms))
-                               visible_games += game;
-               }
+       private Gtk.Widget add_platform (Object object) {
+               var platform = object as Platform;
 
-               foreach (var row in list_box.get_children ()) {
-                       var platform_item = row as PlatformListItem;
-                       var platform = platform_item.platform;
-                       // Assume row doesn't have any games to show
-                       var is_row_visible = false;
+               var item = new PlatformListItem (platform);
+               item.show ();
 
-                       foreach (var game in visible_games) {
-                               var game_platform = game.get_platform ().get_name ();
-
-                               if (game_platform == platform.get_name ()) {
-                                       is_row_visible = true;
-                                       break;
-                               }
-                       }
-
-                       row.visible = is_row_visible;
-               }
-
-               select_first_visible_row ();
+               return item;
        }
 
        [GtkCallback]


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