ComboBox fixes for changing models



The attached is what I think is the correct fix for dealing with
models that change under the GtkComboBox. So far I've done no
testing other than compilation, but I'm going to try and 
write up a test case now.

I'd very much appreciate it if one or more people could review,
especially someone who knows something about GtkTreeModel.

Thanks,
						Owen

Tue Mar  2 11:45:50 2004  Owen Taylor  <otaylor redhat com>

        * gtk/gtkcombobox.c: Always connect to the changed
        signals on the model, update the active item as
        appropriate when rows are inserted/deleted/reordered,
        re-layout the menu on ::rows-reordered.

        * gtk/gtkcellview.c (gtk_cell_view_set_displayed_row):
        Allow %NULL for path to unset and leave no current
        path.

Index: gtk/gtkcellview.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkcellview.c,v
retrieving revision 1.13
diff -u -p -r1.13 gtkcellview.c
--- gtk/gtkcellview.c	9 Feb 2004 21:19:35 -0000	1.13
+++ gtk/gtkcellview.c	2 Mar 2004 16:58:09 -0000
@@ -877,19 +877,35 @@ gtk_cell_view_set_model (GtkCellView  *c
     g_object_ref (G_OBJECT (cell_view->priv->model));
 }
 
+/**
+ * gtk_cell_view_set_displayed_row:
+ * @cell_view: a #GtkCellView
+ * @path: a #GtkTreePath or %NULL to unset.
+ * 
+ * Sets the row of the model that is currently displayed
+ * by the #GtkCellView. If the path is unset, then the
+ * contents of the cellview "stick" at their last value;
+ * this is not normally a desired result, but may be
+ * a needed intermediate state if say, the model for
+ * the #GtkCellView becomes temporarily empty.
+ **/
 void
 gtk_cell_view_set_displayed_row (GtkCellView *cell_view,
                                  GtkTreePath *path)
 {
   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
   g_return_if_fail (GTK_IS_TREE_MODEL (cell_view->priv->model));
-  g_return_if_fail (path != NULL);
 
   if (cell_view->priv->displayed_row)
     gtk_tree_row_reference_free (cell_view->priv->displayed_row);
 
-  cell_view->priv->displayed_row =
-    gtk_tree_row_reference_new (cell_view->priv->model, path);
+  if (path)
+    {
+      cell_view->priv->displayed_row =
+	gtk_tree_row_reference_new (cell_view->priv->model, path);
+    }
+  else
+    cell_view->priv->displayed_row = NULL;
 
   /* force resize and redraw */
   gtk_widget_queue_resize (GTK_WIDGET (cell_view));
Index: gtk/gtkcombobox.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkcombobox.c,v
retrieving revision 1.50
diff -u -p -r1.50 gtkcombobox.c
--- gtk/gtkcombobox.c	29 Feb 2004 01:33:01 -0000	1.50
+++ gtk/gtkcombobox.c	2 Mar 2004 16:58:10 -0000
@@ -91,12 +91,12 @@ struct _GtkComboBoxPrivate
 
   guint inserted_id;
   guint deleted_id;
+  guint reordered_id;
+  guint changed_id;
 
   gint width;
   GSList *cells;
 
-  guint changed_id;
-
   guint popup_in_progress : 1;
 };
 
@@ -233,6 +233,24 @@ static gboolean gtk_combo_box_expose_eve
 static gboolean gtk_combo_box_scroll_event         (GtkWidget        *widget,
                                                     GdkEventScroll   *event);
 
+/* listening to the model */
+static void     gtk_combo_box_model_row_inserted   (GtkTreeModel     *model,
+						    GtkTreePath      *path,
+						    GtkTreeIter      *iter,
+						    gpointer          user_data);
+static void     gtk_combo_box_model_row_deleted    (GtkTreeModel     *model,
+						    GtkTreePath      *path,
+						    gpointer          user_data);
+static void     gtk_combo_box_model_rows_reordered (GtkTreeModel     *model,
+						    GtkTreePath      *path,
+						    GtkTreeIter      *iter,
+						    gint             *new_order,
+						    gpointer          user_data);
+static void     gtk_combo_box_model_row_changed    (GtkTreeModel     *model,
+						    GtkTreePath      *path,
+						    GtkTreeIter      *iter,
+						    gpointer          data);
+
 /* list */
 static void     gtk_combo_box_list_position        (GtkComboBox      *combo_box, 
 						    gint             *x, 
@@ -285,6 +303,11 @@ static void     gtk_combo_box_menu_row_i
 static void     gtk_combo_box_menu_row_deleted     (GtkTreeModel     *model,
                                                     GtkTreePath      *path,
                                                     gpointer          user_data);
+static void     gtk_combo_box_menu_rows_reordered  (GtkTreeModel     *model,
+						    GtkTreePath      *path,
+						    GtkTreeIter      *iter,
+						    gint             *new_order,
+						    gpointer          user_data);
 static void     gtk_combo_box_menu_row_changed     (GtkTreeModel     *model,
                                                     GtkTreePath      *path,
                                                     GtkTreeIter      *iter,
@@ -1244,6 +1267,12 @@ gtk_combo_box_unset_model (GtkComboBox *
 				   combo_box->priv->deleted_id);
       combo_box->priv->deleted_id = -1;
     }
+  if (combo_box->priv->reordered_id != -1)
+    {
+      g_signal_handler_disconnect (combo_box->priv->model,
+				   combo_box->priv->reordered_id);
+      combo_box->priv->reordered_id = -1;
+    }
   if (combo_box->priv->changed_id != -1)
     {
       g_signal_handler_disconnect (combo_box->priv->model,
@@ -1263,32 +1292,28 @@ gtk_combo_box_unset_model (GtkComboBox *
 static void
 gtk_combo_box_set_model_internal (GtkComboBox *combo_box)
 {
-  if (!combo_box->priv->tree_view)
-    {
-      /* menu mode */
-      combo_box->priv->inserted_id =
-        g_signal_connect (combo_box->priv->model, "row_inserted",
-                          G_CALLBACK (gtk_combo_box_menu_row_inserted),
-                          combo_box);
-      combo_box->priv->deleted_id =
-        g_signal_connect (combo_box->priv->model, "row_deleted",
-                          G_CALLBACK (gtk_combo_box_menu_row_deleted),
-                          combo_box);
-      combo_box->priv->changed_id =
-        g_signal_connect (combo_box->priv->model, "row_changed",
-                          G_CALLBACK (gtk_combo_box_menu_row_changed),
-                          combo_box);
-    }
-  else
+  combo_box->priv->inserted_id =
+    g_signal_connect (combo_box->priv->model, "row_inserted",
+		      G_CALLBACK (gtk_combo_box_model_row_inserted),
+		      combo_box);
+  combo_box->priv->deleted_id =
+    g_signal_connect (combo_box->priv->model, "row_deleted",
+		      G_CALLBACK (gtk_combo_box_model_row_deleted),
+		      combo_box);
+  combo_box->priv->reordered_id =
+    g_signal_connect (combo_box->priv->model, "rows_reordered",
+		      G_CALLBACK (gtk_combo_box_model_rows_reordered),
+		      combo_box);
+  combo_box->priv->changed_id =
+    g_signal_connect (combo_box->priv->model, "row_changed",
+		      G_CALLBACK (gtk_combo_box_model_row_changed),
+		      combo_box);
+      
+  if (combo_box->priv->tree_view)
     {
       /* list mode */
       gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view),
                                combo_box->priv->model);
-
-      combo_box->priv->changed_id =
-        g_signal_connect (combo_box->priv->model, "row_changed",
-                          G_CALLBACK (gtk_combo_box_list_row_changed),
-                          combo_box);
     }
 }
 
@@ -1767,6 +1792,89 @@ gtk_combo_box_menu_item_activate (GtkWid
 }
 
 static void
+gtk_combo_box_model_row_inserted (GtkTreeModel     *model,
+				  GtkTreePath      *path,
+				  GtkTreeIter      *iter,
+				  gpointer          user_data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+  gint index = gtk_tree_path_get_indices (path)[0];
+  
+  if (combo_box->priv->active_item >= index)
+    combo_box->priv->active_item++;
+      
+  if (!combo_box->priv->tree_view)
+    gtk_combo_box_menu_row_inserted (model, path, iter, user_data);
+}
+
+static void
+gtk_combo_box_model_row_deleted (GtkTreeModel     *model,
+				 GtkTreePath      *path,
+				 gpointer          user_data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+  gint index = gtk_tree_path_get_indices (path)[0];
+
+  if (index == combo_box->priv->active_item)
+    {
+      gint items = gtk_tree_model_iter_n_children (model, NULL);
+
+      if (items == 0)
+	  gtk_combo_box_set_active (combo_box, -1);
+      else
+	  gtk_combo_box_set_active (combo_box, (index + 1) % items);
+    }
+  else if (combo_box->priv->active_item > index)
+    combo_box->priv->active_item--;
+
+  if (!combo_box->priv->tree_view)
+    gtk_combo_box_menu_row_deleted (model, path, user_data);
+}
+
+static void
+gtk_combo_box_model_rows_reordered (GtkTreeModel    *model,
+				    GtkTreePath     *path,
+				    GtkTreeIter     *iter,
+				    gint            *new_order,
+				    gpointer         user_data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+  gint items = gtk_tree_model_iter_n_children (model, NULL);
+  gint i;
+
+  for (i = 0; i < items; i++)
+    if (new_order[i] == combo_box->priv->active_item)
+      {
+	combo_box->priv->active_item = i;
+	break;
+      }
+
+  if (!combo_box->priv->tree_view)
+    gtk_combo_box_menu_rows_reordered (model, path, iter, new_order, user_data);
+  
+}
+						    
+static void
+gtk_combo_box_model_row_changed (GtkTreeModel     *model,
+				 GtkTreePath      *path,
+				 GtkTreeIter      *iter,
+				 gpointer          user_data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+  gint index = gtk_tree_path_get_indices (path)[0];
+
+  if (index == combo_box->priv->active_item &&
+      combo_box->priv->cell_view)
+    gtk_widget_queue_resize (GTK_WIDGET (combo_box->priv->cell_view));
+  
+  if (combo_box->priv->tree_view)
+    gtk_combo_box_list_row_changed (model, path, iter, user_data);
+  else
+    gtk_combo_box_menu_row_changed (model, path, iter, user_data);
+}
+
+
+static void
 gtk_combo_box_menu_row_inserted (GtkTreeModel *model,
                                  GtkTreePath  *path,
                                  GtkTreeIter  *iter,
@@ -1799,7 +1907,7 @@ gtk_combo_box_menu_row_deleted (GtkTreeM
                                 GtkTreePath  *path,
                                 gpointer      user_data)
 {
-  gint index, items;
+  gint index;
   GtkWidget *menu;
   GtkWidget *item;
   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
@@ -1808,10 +1916,6 @@ gtk_combo_box_menu_row_deleted (GtkTreeM
     return;
 
   index = gtk_tree_path_get_indices (path)[0];
-  items = gtk_tree_model_iter_n_children (model, NULL);
-
-  if (gtk_combo_box_get_active (combo_box) == index)
-    gtk_combo_box_set_active (combo_box, index + 1 % items);
 
   menu = combo_box->priv->popup_widget;
   g_return_if_fail (GTK_IS_MENU (menu));
@@ -1823,6 +1927,18 @@ gtk_combo_box_menu_row_deleted (GtkTreeM
 }
 
 static void
+gtk_combo_box_menu_rows_reordered  (GtkTreeModel     *model,
+				    GtkTreePath      *path,
+				    GtkTreeIter      *iter,
+				    gint             *new_order,
+				    gpointer          user_data)
+{
+  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
+
+  gtk_combo_box_relayout (combo_box);
+}
+				    
+static void
 gtk_combo_box_menu_row_changed (GtkTreeModel *model,
                                 GtkTreePath  *path,
                                 GtkTreeIter  *iter,


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