]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktreemodelsort.c
don't bother inserting new rows in a level with a zero refcount and
[~andy/gtk] / gtk / gtktreemodelsort.c
index 97492559688855ebba3a3c715208ab5fc40898b5..ed1579421708433a6d068366729c1fdac6940993 100644 (file)
@@ -37,6 +37,7 @@
  * we warned you and we're not liable for any head injuries.
  */
 
+#include <config.h>
 #include <string.h>
 
 #include "gtktreemodelsort.h"
@@ -44,6 +45,9 @@
 #include "gtktreestore.h"
 #include "gtktreedatalist.h"
 #include "gtkintl.h"
+#include "gtkprivate.h"
+#include "gtktreednd.h"
+#include "gtkalias.h"
 
 typedef struct _SortElt SortElt;
 typedef struct _SortLevel SortLevel;
@@ -97,7 +101,7 @@ enum {
 #define SORT_ELT(sort_elt) ((SortElt *)sort_elt)
 #define SORT_LEVEL(sort_level) ((SortLevel *)sort_level)
 
-#define GET_CHILD_ITER(tree_model_sort,child_iter,sort_iter) gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT (tree_model_sort), child_iter, sort_iter);
+#define GET_CHILD_ITER(tree_model_sort,ch_iter,so_iter) gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT (tree_model_sort), ch_iter, so_iter);
 
 #define NO_SORT_FUNC ((GtkTreeIterCompareFunc) 0x1)
 
@@ -108,6 +112,7 @@ static void gtk_tree_model_sort_init                  (GtkTreeModelSort      *tr
 static void gtk_tree_model_sort_class_init            (GtkTreeModelSortClass *tree_model_sort_class);
 static void gtk_tree_model_sort_tree_model_init       (GtkTreeModelIface     *iface);
 static void gtk_tree_model_sort_tree_sortable_init    (GtkTreeSortableIface  *iface);
+static void gtk_tree_model_sort_drag_source_init      (GtkTreeDragSourceIface*iface);
 static void gtk_tree_model_sort_finalize              (GObject               *object);
 static void gtk_tree_model_sort_set_property          (GObject               *object,
                                                       guint                  prop_id,
@@ -178,6 +183,15 @@ static void         gtk_tree_model_sort_real_unref_node    (GtkTreeModel
 static void         gtk_tree_model_sort_unref_node         (GtkTreeModel          *tree_model,
                                                             GtkTreeIter           *iter);
 
+/* TreeDragSource interface */
+static gboolean     gtk_tree_model_sort_row_draggable         (GtkTreeDragSource      *drag_source,
+                                                               GtkTreePath            *path);
+static gboolean     gtk_tree_model_sort_drag_data_get         (GtkTreeDragSource      *drag_source,
+                                                               GtkTreePath            *path,
+                                                              GtkSelectionData       *selection_data);
+static gboolean     gtk_tree_model_sort_drag_data_delete      (GtkTreeDragSource      *drag_source,
+                                                               GtkTreePath            *path);
+
 /* TreeSortable interface */
 static gboolean     gtk_tree_model_sort_get_sort_column_id    (GtkTreeSortable        *sortable,
                                                               gint                   *sort_column_id,
@@ -211,7 +225,7 @@ static void         gtk_tree_model_sort_sort              (GtkTreeModelSort *tre
 static gint         gtk_tree_model_sort_level_find_insert (GtkTreeModelSort *tree_model_sort,
                                                           SortLevel        *level,
                                                           GtkTreeIter      *iter,
-                                                          gboolean          skip_sort_elt);
+                                                          gint             skip_index);
 static gboolean     gtk_tree_model_sort_insert_value      (GtkTreeModelSort *tree_model_sort,
                                                           SortLevel        *level,
                                                           GtkTreePath      *s_path,
@@ -260,6 +274,13 @@ gtk_tree_model_sort_get_type (void)
         NULL
       };
 
+      static const GInterfaceInfo drag_source_info =
+      {
+        (GInterfaceInitFunc) gtk_tree_model_sort_drag_source_init,
+        NULL,
+        NULL
+      };
+
       tree_model_sort_type =
        g_type_register_static (G_TYPE_OBJECT, "GtkTreeModelSort",
                                &tree_model_sort_info, 0);
@@ -271,6 +292,10 @@ gtk_tree_model_sort_get_type (void)
       g_type_add_interface_static (tree_model_sort_type,
                                    GTK_TYPE_TREE_SORTABLE,
                                    &sortable_info);
+
+      g_type_add_interface_static (tree_model_sort_type,
+                                   GTK_TYPE_TREE_DRAG_SOURCE,
+                                   &drag_source_info);
     }
 
   return tree_model_sort_type;
@@ -303,10 +328,10 @@ gtk_tree_model_sort_class_init (GtkTreeModelSortClass *class)
   g_object_class_install_property (object_class,
                                    PROP_MODEL,
                                    g_param_spec_object ("model",
-                                                       _("TreeModelSort Model"),
-                                                       _("The model for the TreeModelSort to sort"),
+                                                       P_("TreeModelSort Model"),
+                                                       P_("The model for the TreeModelSort to sort"),
                                                        GTK_TYPE_TREE_MODEL,
-                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+                                                       GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
 
 static void
@@ -338,11 +363,19 @@ gtk_tree_model_sort_tree_sortable_init (GtkTreeSortableIface *iface)
   iface->has_default_sort_func = gtk_tree_model_sort_has_default_sort_func;
 }
 
+static void
+gtk_tree_model_sort_drag_source_init (GtkTreeDragSourceIface *iface)
+{
+  iface->row_draggable = gtk_tree_model_sort_row_draggable;
+  iface->drag_data_delete = gtk_tree_model_sort_drag_data_delete;
+  iface->drag_data_get = gtk_tree_model_sort_drag_data_get;
+}
+
 /**
  * gtk_tree_model_sort_new_with_model:
  * @child_model: A #GtkTreeModel
  *
- * Creates a new #GtkTreeModel, with @child_model as the child_model.
+ * Creates a new #GtkTreeModel, with @child_model as the child model.
  *
  * Return value: A new #GtkTreeModel.
  */
@@ -436,7 +469,7 @@ gtk_tree_model_sort_row_changed (GtkTreeModel *s_model,
 
   gboolean free_s_path = FALSE;
 
-  gint offset, index = 0, old_index, i;
+  gint index = 0, old_index, i;
 
   g_return_if_fail (start_s_path != NULL || start_s_iter != NULL);
 
@@ -461,6 +494,8 @@ gtk_tree_model_sort_row_changed (GtkTreeModel *s_model,
   level = iter.user_data;
   elt = iter.user_data2;
 
+  level->ref_count++;
+
   if (level->array->len < 2 ||
       (tree_model_sort->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID &&
        tree_model_sort->default_sort_func == NO_SORT_FUNC))
@@ -472,20 +507,18 @@ gtk_tree_model_sort_row_changed (GtkTreeModel *s_model,
 
       gtk_tree_path_free (path);
 
+      level->ref_count--;
+
       return;
     }
-
+  
   if (!GTK_TREE_MODEL_SORT_CACHE_CHILD_ITERS (tree_model_sort))
     {
       gtk_tree_model_get_iter (tree_model_sort->child_model,
                               &tmpiter, start_s_path);
     }
 
-  offset = elt->offset;
-
-  for (i = 0; i < level->array->len; i++)
-    if (elt->offset == g_array_index (level->array, SortElt, i).offset)
-      old_index = i;
+  old_index = elt - SORT_ELT (level->array->data);
 
   memcpy (&tmp, elt, sizeof (SortElt));
 
@@ -493,12 +526,12 @@ gtk_tree_model_sort_row_changed (GtkTreeModel *s_model,
     index = gtk_tree_model_sort_level_find_insert (tree_model_sort,
                                                   level,
                                                   &tmp.iter,
-                                                  TRUE);
+                                                  old_index);
   else
     index = gtk_tree_model_sort_level_find_insert (tree_model_sort,
                                                   level,
                                                   &tmpiter,
-                                                  TRUE);
+                                                  old_index);
 
   if (index < old_index)
     {
@@ -581,6 +614,8 @@ gtk_tree_model_sort_row_changed (GtkTreeModel *s_model,
       g_free (new_order);
     }
 
+  level->ref_count--;
+
   /* emit row_changed signal (at new location) */
   gtk_tree_model_get_iter (GTK_TREE_MODEL (data), &iter, path);
   gtk_tree_model_row_changed (GTK_TREE_MODEL (data), path, &iter);
@@ -693,6 +728,12 @@ gtk_tree_model_sort_row_inserted (GtkTreeModel          *s_model,
   if (!parent_level)
     goto done;
 
+  if (level->ref_count == 0 && level != tree_model_sort->root)
+    {
+      gtk_tree_model_sort_free_level (tree_model_sort, level);
+      goto done;
+    }
+
   if (!gtk_tree_model_sort_insert_value (tree_model_sort,
                                         parent_level,
                                         s_path,
@@ -779,12 +820,20 @@ gtk_tree_model_sort_row_deleted (GtkTreeModel *s_model,
   while (elt->ref_count > 0)
     gtk_tree_model_sort_real_unref_node (GTK_TREE_MODEL (data), &iter, FALSE);
 
-  if (level->ref_count == 0 && level != tree_model_sort->root)
+  if (level->ref_count == 0)
     {
-      /* This will prune the level, so I can just emit the signal and not worry
-       * about cleaning this level up. */
+      /* This will prune the level, so I can just emit the signal and 
+       * not worry about cleaning this level up. 
+       * Careful, root level is not cleaned up in increment stamp.
+       */
       gtk_tree_model_sort_increment_stamp (tree_model_sort);
       gtk_tree_path_free (path);
+      if (level == tree_model_sort->root)
+       {
+         gtk_tree_model_sort_free_level (tree_model_sort, 
+                                         tree_model_sort->root);
+         tree_model_sort->root = NULL;
+       }
       return;
     }
 
@@ -903,7 +952,15 @@ gtk_tree_model_sort_rows_reordered (GtkTreeModel *s_model,
 static GtkTreeModelFlags
 gtk_tree_model_sort_get_flags (GtkTreeModel *tree_model)
 {
+  GtkTreeModelFlags flags;
+
   g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (tree_model), 0);
+  g_return_val_if_fail (GTK_TREE_MODEL_SORT (tree_model)->child_model != NULL, 0);
+
+  flags = gtk_tree_model_get_flags (GTK_TREE_MODEL_SORT (tree_model)->child_model);
+
+  if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
+    return GTK_TREE_MODEL_LIST_ONLY;
 
   return 0;
 }
@@ -966,8 +1023,12 @@ gtk_tree_model_sort_get_iter (GtkTreeModel *tree_model,
       level = g_array_index (level->array, SortElt, indices[i]).children;
     }
 
-  if (level == NULL)
-    return FALSE;
+  if (!level || indices[i] >= level->array->len)
+    {
+      iter->stamp = 0;
+      return FALSE;
+    }
+
   iter->stamp = tree_model_sort->stamp;
   iter->user_data = level;
   iter->user_data2 = &g_array_index (level->array, SortElt, indices[depth - 1]);
@@ -1280,14 +1341,15 @@ gtk_tree_model_sort_get_sort_column_id (GtkTreeSortable *sortable,
 
   g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (sortable), FALSE);
 
-  if (tree_model_sort->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
-    return FALSE;
-
   if (sort_column_id)
     *sort_column_id = tree_model_sort->sort_column_id;
   if (order)
     *order = tree_model_sort->order;
 
+  if (tree_model_sort->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID ||
+      tree_model_sort->sort_column_id == GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
+    return FALSE;
+  
   return TRUE;
 }
 
@@ -1419,6 +1481,65 @@ gtk_tree_model_sort_has_default_sort_func (GtkTreeSortable *sortable)
   return (tree_model_sort->default_sort_func != NULL);
 }
 
+/* DragSource interface */
+static gboolean
+gtk_tree_model_sort_row_draggable (GtkTreeDragSource *drag_source,
+                                   GtkTreePath       *path)
+{
+  GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *)drag_source;
+  GtkTreePath *child_path;
+  gboolean draggable;
+
+  g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (drag_source), FALSE);
+  g_return_val_if_fail (path != NULL, FALSE);
+
+  child_path = gtk_tree_model_sort_convert_path_to_child_path (tree_model_sort,
+                                                               path);
+  draggable = gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (tree_model_sort->child_model), child_path);
+  gtk_tree_path_free (child_path);
+
+  return draggable;
+}
+
+static gboolean
+gtk_tree_model_sort_drag_data_get (GtkTreeDragSource *drag_source,
+                                   GtkTreePath       *path,
+                                   GtkSelectionData  *selection_data)
+{
+  GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *)drag_source;
+  GtkTreePath *child_path;
+  gboolean gotten;
+
+  g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (drag_source), FALSE);
+  g_return_val_if_fail (path != NULL, FALSE);
+
+  child_path = gtk_tree_model_sort_convert_path_to_child_path (tree_model_sort,
+                                                               path);
+  gotten = gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (tree_model_sort->child_model), child_path, selection_data);
+  gtk_tree_path_free (child_path);
+
+  return gotten;
+}
+
+static gboolean
+gtk_tree_model_sort_drag_data_delete (GtkTreeDragSource *drag_source,
+                                      GtkTreePath       *path)
+{
+  GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *)drag_source;
+  GtkTreePath *child_path;
+  gboolean deleted;
+
+  g_return_val_if_fail (GTK_IS_TREE_MODEL_SORT (drag_source), FALSE);
+  g_return_val_if_fail (path != NULL, FALSE);
+
+  child_path = gtk_tree_model_sort_convert_path_to_child_path (tree_model_sort,
+                                                               path);
+  deleted = gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (tree_model_sort->child_model), child_path);
+  gtk_tree_path_free (child_path);
+
+  return deleted;
+}
+
 /* sorting code - private */
 static gint
 gtk_tree_model_sort_compare_func (gconstpointer a,
@@ -1517,6 +1638,8 @@ gtk_tree_model_sort_sort_level (GtkTreeModelSort *tree_model_sort,
   if (level->array->len < 1 && !((SortElt *)level->array->data)->children)
     return;
 
+  level->ref_count++;
+
   /* Set up data */
   data.tree_model_sort = tree_model_sort;
   if (level->parent_elt)
@@ -1638,6 +1761,8 @@ gtk_tree_model_sort_sort_level (GtkTreeModelSort *tree_model_sort,
     }
 
   g_free (new_order);
+
+  level->ref_count--;
 }
 
 static void
@@ -1671,10 +1796,9 @@ static gint
 gtk_tree_model_sort_level_find_insert (GtkTreeModelSort *tree_model_sort,
                                       SortLevel        *level,
                                       GtkTreeIter      *iter,
-                                      gboolean          skip_sort_elt)
+                                      gint             skip_index)
 {
   gint start, middle, end;
-  gint skip_index;
   gint cmp;
   SortElt *tmp_elt;
   GtkTreeIter tmp_iter;
@@ -1706,13 +1830,10 @@ gtk_tree_model_sort_level_find_insert (GtkTreeModelSort *tree_model_sort,
 
   start = 0;
   end = level->array->len;
-  if (skip_sort_elt)
-    {
-      skip_index = SORT_ELT (iter->user_data2) - SORT_ELT (level->array->data);
-      end--;
-    }
-  else
+  if (skip_index < 0)
     skip_index = end;
+  else
+    end--;
 
   if (start == end)
     return 0;
@@ -1787,7 +1908,7 @@ gtk_tree_model_sort_insert_value (GtkTreeModelSort *tree_model_sort,
   else
     index = gtk_tree_model_sort_level_find_insert (tree_model_sort,
                                                    level, s_iter,
-                                                   FALSE);
+                                                   -1);
 
   g_array_insert_vals (level->array, index, &elt, 1);
   tmp_elt = SORT_ELT (level->array->data);
@@ -1826,11 +1947,12 @@ gtk_tree_model_sort_elt_get_path (SortLevel *level,
 /**
  * gtk_tree_model_sort_set_model:
  * @tree_model_sort: The #GtkTreeModelSort.
- * @child_model: A #GtkTreeModel, or NULL.
+ * @child_model: A #GtkTreeModel, or %NULL.
  *
- * Sets the model of @tree_model_sort to be @model.  If @model is NULL, then the
- * old model is unset.  The sort function is unset as a result of this call.
- * The model will be in an unsorted state until a sort function is set.
+ * Sets the model of @tree_model_sort to be @model.  If @model is %NULL, 
+ * then the old model is unset.  The sort function is unset as a result 
+ * of this call. The model will be in an unsorted state until a sort 
+ * function is set.
  **/
 static void
 gtk_tree_model_sort_set_model (GtkTreeModelSort *tree_model_sort,
@@ -1992,8 +2114,8 @@ gtk_real_tree_model_sort_convert_child_path_to_path (GtkTreeModelSort *tree_mode
  * 
  * Converts @child_path to a path relative to @tree_model_sort.  That is,
  * @child_path points to a path in the child model.  The returned path will
- * point to the same row in the sorted model.  If @child_path isn't a valid path
- * on the child model, then %NULL is returned.
+ * point to the same row in the sorted model.  If @child_path isn't a valid 
+ * path on the child model, then %NULL is returned.
  * 
  * Return value: A newly allocated #GtkTreePath, or %NULL
  **/
@@ -2047,10 +2169,11 @@ gtk_tree_model_sort_convert_child_iter_to_iter (GtkTreeModelSort *tree_model_sor
  * @tree_model_sort: A #GtkTreeModelSort
  * @sorted_path: A #GtkTreePath to convert
  * 
- * Converts @sorted_path to a path on the child model of @tree_model_sort.  That
- * is, @sorted_path points to a location in @tree_model_sort.  The returned path
- * will point to the same location in the model not being sorted.  If @sorted_path 
- * does not point to a location in the child model, %NULL is returned.
+ * Converts @sorted_path to a path on the child model of @tree_model_sort.  
+ * That is, @sorted_path points to a location in @tree_model_sort.  The 
+ * returned path will point to the same location in the model not being 
+ * sorted.  If @sorted_path does not point to a location in the child model, 
+ * %NULL is returned.
  * 
  * Return value: A newly allocated #GtkTreePath, or %NULL
  **/
@@ -2215,7 +2338,7 @@ gtk_tree_model_sort_build_level (GtkTreeModelSort *tree_model_sort,
          if (gtk_tree_model_iter_next (tree_model_sort->child_model, &iter) == FALSE &&
              i < length - 1)
            {
-             g_warning ("There is a discrepency between the sort model and the child model.");
+             g_warning ("There is a discrepancy between the sort model and the child model.");
              return;
            }
        }
@@ -2382,8 +2505,9 @@ gtk_tree_model_sort_iter_is_valid_helper (GtkTreeIter *iter,
  * @tree_model_sort: A #GtkTreeModelSort.
  * @iter: A #GtkTreeIter.
  *
- * WARNING: This function is slow. Only use it for debugging and/or testing
- * purposes.
+ * <warning><para>
+ * This function is slow. Only use it for debugging and/or testing purposes.
+ * </para></warning>
  *
  * Checks if the given iter is a valid iter for this #GtkTreeModelSort.
  *
@@ -2404,3 +2528,6 @@ gtk_tree_model_sort_iter_is_valid (GtkTreeModelSort *tree_model_sort,
   return gtk_tree_model_sort_iter_is_valid_helper (iter,
                                                   tree_model_sort->root);
 }
+
+#define __GTK_TREE_MODEL_SORT_C__
+#include "gtkaliasdef.c"