[gtk/wip/otte/listview: 27/138] listitem: Add gtk_list_item_get_position()



commit 2650390f7fdebc90e4d8860f80f8d8fe9d77534f
Author: Benjamin Otte <otte redhat com>
Date:   Mon Sep 24 04:01:37 2018 +0200

    listitem: Add gtk_list_item_get_position()
    
    Also refactor the whole list item management yet again.
    
    Now, list item APIs doesn't have bind/unbind functions anymore, but only
    property setters.
    
    The item factory is the only one doing the binding.
    As before, the item manager manages when items need to be bound.

 docs/reference/gtk/gtk4-sections.txt |  1 +
 gtk/gtklistitem.c                    | 67 +++++++++++++++++++++++++++++-------
 gtk/gtklistitem.h                    |  2 ++
 gtk/gtklistitemfactory.c             | 26 ++++++++++++--
 gtk/gtklistitemfactoryprivate.h      |  4 +++
 gtk/gtklistitemmanager.c             | 23 ++++++++++++-
 gtk/gtklistitemmanagerprivate.h      |  3 ++
 gtk/gtklistitemprivate.h             |  5 +--
 gtk/gtklistview.c                    | 18 ++++++++++
 9 files changed, 131 insertions(+), 18 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index 156cba0a78..5045d7322d 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -498,6 +498,7 @@ gtk_single_selection_get_type
 <TITLE>GtkListItem</TITLE>
 GtkListItem
 gtk_list_item_get_item
+gtk_list_item_get_position
 gtk_list_item_get_child
 gtk_list_item_set_child
 <SUBSECTION Standard>
diff --git a/gtk/gtklistitem.c b/gtk/gtklistitem.c
index bb9f019ad6..7bc294ca33 100644
--- a/gtk/gtklistitem.c
+++ b/gtk/gtklistitem.c
@@ -23,6 +23,7 @@
 
 #include "gtkbinlayout.h"
 #include "gtkintl.h"
+#include "gtkselectionmodel.h" /* for GTK_INVALID_LIST_POSITION */
 #include "gtkwidget.h"
 
 /**
@@ -55,6 +56,7 @@ struct _GtkListItem
 
   GObject *item;
   GtkWidget *child;
+  guint position;
 };
 
 struct _GtkListItemClass
@@ -67,6 +69,7 @@ enum
   PROP_0,
   PROP_CHILD,
   PROP_ITEM,
+  PROP_POSITION,
 
   N_PROPS
 };
@@ -104,6 +107,10 @@ gtk_list_item_get_property (GObject    *object,
       g_value_set_object (value, self->item);
       break;
 
+    case PROP_POSITION:
+      g_value_set_uint (value, self->position);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -164,6 +171,18 @@ gtk_list_item_class_init (GtkListItemClass *klass)
                          G_TYPE_OBJECT,
                          G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
+  /**
+   * GtkListItem:position:
+   *
+   * Position of the item
+   */
+  properties[PROP_POSITION] =
+    g_param_spec_uint ("position",
+                       P_("Position"),
+                       P_("Position of the item"),
+                       0, G_MAXUINT, GTK_INVALID_LIST_POSITION,
+                       G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
   g_object_class_install_properties (gobject_class, N_PROPS, properties);
 
   /* This gets overwritten by gtk_list_item_new() but better safe than sorry */
@@ -190,10 +209,10 @@ gtk_list_item_new (const char *css_name)
  * gtk_list_item_get_item:
  * @self: a #GtkListItem
  *
- * Gets the item that is currently displayed or model that @self is
+ * Gets the item that is currently displayed in model that @self is
  * currently bound to or %NULL if @self is unbound.
  *
- * Returns: (nullable) (transfer none) (type GObject): The model in use
+ * Returns: (nullable) (transfer none) (type GObject): The item displayed
  **/
 gpointer
 gtk_list_item_get_item (GtkListItem *self)
@@ -253,28 +272,50 @@ gtk_list_item_set_child (GtkListItem *self,
 }
 
 void
-gtk_list_item_bind (GtkListItem *self,
-                    gpointer     item)
+gtk_list_item_set_item (GtkListItem *self,
+                        gpointer     item)
 {
   g_return_if_fail (GTK_IS_LIST_ITEM (self));
-  g_return_if_fail (G_IS_OBJECT (item));
-  /* Must unbind before rebinding */
-  g_return_if_fail (self->item == NULL);
+  g_return_if_fail (item == NULL || G_IS_OBJECT (item));
 
-  self->item = g_object_ref (item);
+  if (self->item == item)
+    return;
+
+  g_clear_object (&self->item);
+  if (item)
+    self->item = g_object_ref (item);
 
   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]);
 }
 
+/**
+ * gtk_list_item_get_position:
+ * @self: a #GtkListItem
+ *
+ * Gets the position in the model that @self currently displays.
+ * If @self is unbound, 0 is returned.
+ *
+ * Returns: The position of this item
+ **/
+guint
+gtk_list_item_get_position (GtkListItem *self)
+{
+  g_return_val_if_fail (GTK_IS_LIST_ITEM (self), 0);
+
+  return self->position;
+}
+
 void
-gtk_list_item_unbind (GtkListItem *self)
+gtk_list_item_set_position (GtkListItem *self,
+                            guint        position)
 {
   g_return_if_fail (GTK_IS_LIST_ITEM (self));
-  /* Must be bound */
-  g_return_if_fail (self->item != NULL);
 
-  g_clear_object (&self->item);
+  if (self->position == position)
+    return;
 
-  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]);
+  self->position = position;
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_POSITION]);
 }
 
diff --git a/gtk/gtklistitem.h b/gtk/gtklistitem.h
index 3af77cb14e..ed7f21c45f 100644
--- a/gtk/gtklistitem.h
+++ b/gtk/gtklistitem.h
@@ -44,6 +44,8 @@ GType           gtk_list_item_get_type                          (void) G_GNUC_CO
 
 GDK_AVAILABLE_IN_ALL
 gpointer        gtk_list_item_get_item                          (GtkListItem            *self);
+GDK_AVAILABLE_IN_ALL
+guint           gtk_list_item_get_position                      (GtkListItem            *self);
 
 GDK_AVAILABLE_IN_ALL
 void            gtk_list_item_set_child                         (GtkListItem            *self,
diff --git a/gtk/gtklistitemfactory.c b/gtk/gtklistitemfactory.c
index a9a58689a0..684380f3b1 100644
--- a/gtk/gtklistitemfactory.c
+++ b/gtk/gtklistitemfactory.c
@@ -105,14 +105,31 @@ gtk_list_item_factory_create (GtkListItemFactory *self)
 void
 gtk_list_item_factory_bind (GtkListItemFactory *self,
                             GtkListItem        *list_item,
+                            guint               position,
                             gpointer            item)
 {
   g_return_if_fail (GTK_IS_LIST_ITEM_FACTORY (self));
   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
 
-  gtk_list_item_bind (list_item, item);
+  g_object_freeze_notify (G_OBJECT (list_item));
+
+  gtk_list_item_set_item (list_item, item);
+  gtk_list_item_set_position (list_item, position);
 
   self->bind_func (gtk_list_item_get_child (list_item), item, self->user_data);
+
+  g_object_thaw_notify (G_OBJECT (list_item));
+}
+
+void
+gtk_list_item_factory_update (GtkListItemFactory *self,
+                              GtkListItem        *list_item,
+                              guint               position)
+{
+  g_return_if_fail (GTK_IS_LIST_ITEM_FACTORY (self));
+  g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
+
+  gtk_list_item_set_position (list_item, position);
 }
 
 void
@@ -122,5 +139,10 @@ gtk_list_item_factory_unbind (GtkListItemFactory *self,
   g_return_if_fail (GTK_IS_LIST_ITEM_FACTORY (self));
   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
 
-  gtk_list_item_unbind (list_item);
+  g_object_freeze_notify (G_OBJECT (list_item));
+
+  gtk_list_item_set_item (list_item, NULL);
+  gtk_list_item_set_position (list_item, 0);
+
+  g_object_thaw_notify (G_OBJECT (list_item));
 }
diff --git a/gtk/gtklistitemfactoryprivate.h b/gtk/gtklistitemfactoryprivate.h
index a6bec12faf..21bc5b5586 100644
--- a/gtk/gtklistitemfactoryprivate.h
+++ b/gtk/gtklistitemfactoryprivate.h
@@ -47,7 +47,11 @@ GtkListItem *           gtk_list_item_factory_create            (GtkListItemFact
 
 void                    gtk_list_item_factory_bind              (GtkListItemFactory     *self,
                                                                  GtkListItem            *list_item,
+                                                                 guint                   position,
                                                                  gpointer                item);
+void                    gtk_list_item_factory_update            (GtkListItemFactory     *self,
+                                                                 GtkListItem            *list_item,
+                                                                 guint                   position);
 void                    gtk_list_item_factory_unbind            (GtkListItemFactory     *self,
                                                                  GtkListItem            *list_item);
 
diff --git a/gtk/gtklistitemmanager.c b/gtk/gtklistitemmanager.c
index a88502efbb..d365137d18 100644
--- a/gtk/gtklistitemmanager.c
+++ b/gtk/gtklistitemmanager.c
@@ -236,7 +236,7 @@ gtk_list_item_manager_acquire_list_item (GtkListItemManager *self,
   result = gtk_list_item_factory_create (self->factory);
 
   item = g_list_model_get_item (self->model, position);
-  gtk_list_item_factory_bind (self->factory, result, item);
+  gtk_list_item_factory_bind (self->factory, result, position, item);
   g_object_unref (item);
   gtk_widget_insert_before (GTK_WIDGET (result), self->widget, next_sibling);
 
@@ -274,6 +274,7 @@ gtk_list_item_manager_try_reacquire_list_item (GtkListItemManager       *self,
   item = g_list_model_get_item (self->model, position);
   if (g_hash_table_steal_extended (change->items, item, NULL, (gpointer *) &result))
     {
+      gtk_list_item_factory_update (self->factory, result, position);
       gtk_widget_insert_before (GTK_WIDGET (result), self->widget, next_sibling);
       /* XXX: Should we let the listview do this? */
       gtk_widget_queue_resize (GTK_WIDGET (result));
@@ -287,6 +288,26 @@ gtk_list_item_manager_try_reacquire_list_item (GtkListItemManager       *self,
   return GTK_WIDGET (result);
 }
 
+/**
+ * gtk_list_item_manager_update_list_item:
+ * @self: a #GtkListItemManager
+ * @item: a #GtkListItem that has been acquired
+ * @position: the new position of that list item
+ *
+ * Updates the position of the given @item. This function must be called whenever
+ * the position of an item changes, like when new items are added before it.
+ **/
+void
+gtk_list_item_manager_update_list_item (GtkListItemManager *self,
+                                        GtkWidget          *item,
+                                        guint               position)
+{
+  g_return_if_fail (GTK_IS_LIST_ITEM_MANAGER (self));
+  g_return_if_fail (GTK_IS_LIST_ITEM (item));
+
+  gtk_list_item_factory_update (self->factory, GTK_LIST_ITEM (item), position);
+}
+
 /*
  * gtk_list_item_manager_release_list_item:
  * @self: a #GtkListItemManager
diff --git a/gtk/gtklistitemmanagerprivate.h b/gtk/gtklistitemmanagerprivate.h
index 2af8e8fae7..d1cdfaf819 100644
--- a/gtk/gtklistitemmanagerprivate.h
+++ b/gtk/gtklistitemmanagerprivate.h
@@ -63,6 +63,9 @@ GtkWidget *             gtk_list_item_manager_try_reacquire_list_item
                                                                  GtkListItemManagerChange *change,
                                                                  guint                   position,
                                                                  GtkWidget              *next_sibling);
+void                    gtk_list_item_manager_update_list_item  (GtkListItemManager     *self,
+                                                                 GtkWidget              *item,
+                                                                 guint                   position);
 void                    gtk_list_item_manager_release_list_item (GtkListItemManager     *self,
                                                                  GtkListItemManagerChange *change,
                                                                  GtkWidget              *widget);
diff --git a/gtk/gtklistitemprivate.h b/gtk/gtklistitemprivate.h
index a0a90f7d79..f238685c76 100644
--- a/gtk/gtklistitemprivate.h
+++ b/gtk/gtklistitemprivate.h
@@ -26,9 +26,10 @@ G_BEGIN_DECLS
 
 GtkWidget *     gtk_list_item_new                               (const char             *css_name);
 
-void            gtk_list_item_bind                              (GtkListItem            *self,
+void            gtk_list_item_set_item                          (GtkListItem            *self,
                                                                  gpointer                item);
-void            gtk_list_item_unbind                            (GtkListItem            *self);
+void            gtk_list_item_set_position                      (GtkListItem            *self,
+                                                                 guint                   position);
 
 G_END_DECLS
 
diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c
index f5c36e55fc..1539a2a530 100644
--- a/gtk/gtklistview.c
+++ b/gtk/gtklistview.c
@@ -509,6 +509,22 @@ gtk_list_view_add_rows (GtkListView              *self,
   gtk_widget_queue_resize (GTK_WIDGET (self));
 }
 
+static void
+gtk_list_view_update_rows (GtkListView *self,
+                           guint        position)
+{
+  ListRow *row;
+
+  for (row = gtk_list_view_get_row (self, position, NULL);
+       row;
+       row = gtk_rb_tree_node_get_next (row))
+    {
+      gtk_list_item_manager_update_list_item (self->item_manager, row->widget, position);
+
+      position++;
+    }
+}
+
 static void
 gtk_list_view_model_items_changed_cb (GListModel  *model,
                                       guint        position,
@@ -522,6 +538,8 @@ gtk_list_view_model_items_changed_cb (GListModel  *model,
 
   gtk_list_view_remove_rows (self, change, position, removed);
   gtk_list_view_add_rows (self, change, position, added);
+  if (removed != added)
+    gtk_list_view_update_rows (self, position + added);
 
   gtk_list_item_manager_end_change (self->item_manager, change);
 }


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