[gtk+/filesystemmodel: 4/28] file system model improvements, step 2



commit 8ba104089216bca253ab984a6c7faab49045bf45
Author: Benjamin Otte <otte gnome org>
Date:   Thu Jun 18 17:03:07 2009 +0200

    file system model improvements, step 2
    
    make columns managed by the creator of the model, so any number of nodes
    can be added as needed. Values are filled on demand using a function
    given when creating the model.
    The reason for this API change is to make the code more similar to
    GtkListStore. This should allow simplifying the code in gtkfilechooser.c
    where these two models are used interchangably.

 gtk/gtkfilechooserdefault.c |   31 +++++++-
 gtk/gtkfilesystemmodel.c    |  181 +++++++++++++++++++++++++++++--------------
 gtk/gtkfilesystemmodel.h    |   16 +++--
 3 files changed, 160 insertions(+), 68 deletions(-)
---
diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
index 6ee285d..0895bd6 100644
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@ -191,6 +191,12 @@ typedef enum {
   SHORTCUT_TYPE_RECENT
 } ShortcutType;
 
+enum {
+  BROWSE_MODEL_COL_INFO,
+  BROWSE_MODEL_COL_DISPLAY_NAME,
+  BROWSE_MODEL_COL_NUM_COLUMNS
+};
+
 /* Column numbers for the search model.  
  * Keep this in sync with search_setup_model() 
  */
@@ -6438,7 +6444,7 @@ load_set_model (GtkFileChooserDefault *impl)
 			   GTK_TREE_MODEL (impl->sort_model));
   gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->browse_files_tree_view));
   gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->browse_files_tree_view),
-				   GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME);
+				   BROWSE_MODEL_COL_DISPLAY_NAME);
   profile_msg ("    gtk_tree_view_set_model end", NULL);
 
   profile_end ("end", NULL);
@@ -6791,6 +6797,22 @@ stop_loading_and_clear_list_model (GtkFileChooserDefault *impl)
   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
 }
 
+static void
+file_system_model_set (GtkFileSystemModel *model,
+		       GFile              *file,
+                       GFileInfo          *info,
+                       GValue             *values,
+                       gpointer            unused)
+{
+  g_value_set_object (&values[0], info);
+
+  if (info == NULL)
+    g_value_set_static_string (&values[1], "");
+  else
+    g_value_set_string (&values[1], g_file_info_get_display_name (info));
+
+}
+
 /* Gets rid of the old list model and creates a new one for the current folder */
 static gboolean
 set_list_model (GtkFileChooserDefault *impl,
@@ -6808,7 +6830,12 @@ set_list_model (GtkFileChooserDefault *impl,
   impl->browse_files_model = _gtk_file_system_model_new (impl->current_folder,
                                                          "standard::name,standard::type,standard::display-name,"
                                                          "standard::is-hidden,standard::is-backup",
-							 "standard,time,thumbnail");
+							 "standard,time,thumbnail",
+                                                         file_system_model_set,
+                                                         NULL,
+                                                         BROWSE_MODEL_COL_NUM_COLUMNS,
+                                                         G_TYPE_FILE_INFO,
+                                                         G_TYPE_STRING);
   load_setup_timer (impl); /* This changes the state to LOAD_PRELOAD */
 
   g_signal_connect (impl->browse_files_model, "finished-loading",
diff --git a/gtk/gtkfilesystemmodel.c b/gtk/gtkfilesystemmodel.c
index c947dc1..c8bee02 100644
--- a/gtk/gtkfilesystemmodel.c
+++ b/gtk/gtkfilesystemmodel.c
@@ -27,6 +27,7 @@
 
 #include "gtkintl.h"
 #include "gtkmarshalers.h"
+#include "gtktreedatalist.h"
 #include "gtktreednd.h"
 #include "gtktreemodel.h"
 #include "gtkalias.h"
@@ -52,6 +53,9 @@ struct _FileModelNode
   guint                 index;          /* index in path - aka visible nodes before this one */
 
   guint                 visible :1;     /* if the file is currently visible */
+  guint                 values_set :1;  /* true if the set function has been called on this node */
+
+  GValue                values[1];      /* actually n_columns values */
 };
 
 struct _GtkFileSystemModel
@@ -65,6 +69,11 @@ struct _GtkFileSystemModel
   GCancellable *        cancellable;    /* cancellable in use for all operations - cancelled on dispose */
   GArray *              files;          /* array of FileModelNode containing all our files */
 
+  guint                 n_columns;      /* number of columns */
+  GType *               column_types;   /* types of each column */
+  GtkFileSystemModelSet set_func;       /* function to call to fill in values in columns */
+  gpointer              set_data;       /* data to pass to set_func */
+
   GtkFileSystemModelFilter filter_func; /* filter to use for deciding which nodes are visible */
   gpointer              filter_data;    /* data to pass to filter_func */
 
@@ -103,8 +112,30 @@ struct _GtkFileSystemModelClass
 
 /*** FileModelNode ***/
 
-#define get_node(_model, _index) (&g_array_index ((_model)->files, FileModelNode, (_index)))
-#define gtk_tree_path_new_from_node(_model, _index) gtk_tree_path_new_from_indices (get_node ((_model), (_index))->index, -1)
+#define NODE_SIZE(_model) (sizeof (FileModelNode) + sizeof (GValue) * (MAX ((model)->n_columns, 1) - 1))
+#define get_node(_model, _index) ((FileModelNode *) (((guint8 *) (_model)->files->data) + (_index) * NODE_SIZE (_model)))
+
+static GtkTreePath *
+gtk_tree_path_new_from_node (GtkFileSystemModel *model, guint id)
+{
+  FileModelNode *node = get_node (model, id);
+
+  g_assert (node->index < model->files->len);
+
+  return gtk_tree_path_new_from_indices (node->index, -1);
+}
+
+static void
+node_ensure_values_set (GtkFileSystemModel *model, guint id)
+{
+  FileModelNode *node = get_node (model, id);
+
+  if (node->values_set)
+    return;
+
+  model->set_func (model, node->file, node->info, node->values, model->set_data);
+  node->values_set = TRUE;
+}
 
 static void
 node_set_visible (GtkFileSystemModel *model, guint id, gboolean visible)
@@ -186,23 +217,20 @@ gtk_file_system_model_get_flags (GtkTreeModel *tree_model)
 static gint
 gtk_file_system_model_get_n_columns (GtkTreeModel *tree_model)
 {
-  return GTK_FILE_SYSTEM_MODEL_N_COLUMNS;
+  GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
+  
+  return model->n_columns;
 }
 
 static GType
 gtk_file_system_model_get_column_type (GtkTreeModel *tree_model,
 				       gint          i)
 {
-  switch (i)
-    {
-    case GTK_FILE_SYSTEM_MODEL_INFO:
-      return G_TYPE_FILE_INFO;
-    case GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME:
-      return G_TYPE_STRING;
-    default:
-      g_assert_not_reached ();
-      return G_TYPE_NONE;
-    }
+  GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
+  
+  g_return_val_if_fail (i >= 0 && (guint) i < model->n_columns, G_TYPE_NONE);
+
+  return model->column_types[i];
 }
 
 static int
@@ -220,7 +248,8 @@ gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
 				      gint          n)
 {
   GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
-  FileModelNode *node, *first;
+  char *node;
+  guint id;
 
   g_return_val_if_fail (n >= 0, FALSE);
 
@@ -230,16 +259,16 @@ gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
   node = bsearch (GUINT_TO_POINTER ((guint) n), 
                   model->files->data,
                   model->files->len,
-                  sizeof (FileModelNode),
+                  NODE_SIZE (model),
                   compare_indices);
   if (node == NULL)
     return FALSE;
 
-  first = get_node (model, 0);
-  while (node >= first && !node->visible)
-    node--;
+  id = (node - model->files->data) / NODE_SIZE (model);
+  while (!get_node (model, id)->visible)
+    id--;
 
-  ITER_INIT_FROM_INDEX (model, iter, (guint) (node - get_node (model, 0)));
+  ITER_INIT_FROM_INDEX (model, iter, id);
   return TRUE;
 }
 
@@ -270,36 +299,23 @@ gtk_file_system_model_get_path (GtkTreeModel *tree_model,
 static void
 gtk_file_system_model_get_value (GtkTreeModel *tree_model,
 				 GtkTreeIter  *iter,
-				 gint          column,
+				 gint          i_can_has_uint,
 				 GValue       *value)
 {
   GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
   FileModelNode *node;
+  guint column = i_can_has_uint;
   
+  g_return_if_fail (column < model->n_columns);
   g_return_if_fail (ITER_IS_VALID (model, iter));
 
   node = get_node (model, ITER_INDEX (iter));
   g_assert (node->visible);
   
-  switch (column)
-    {
-    case GTK_FILE_SYSTEM_MODEL_INFO:
-      g_value_init (value, G_TYPE_FILE_INFO);
-      g_value_set_object (value, node->info);
-      break;
-    case GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME:
-      {
-	g_value_init (value, G_TYPE_STRING);
-
-	if (node->info == NULL)
-	  g_value_set_static_string (value, "");
-	else
-	  g_value_set_string (value, g_file_info_get_display_name (node->info));
-      }
-      break;
-    default:
-      g_assert_not_reached ();
-    }
+  node_ensure_values_set (model, ITER_INDEX (iter));
+
+  g_value_init (value, model->column_types[column]);
+  g_value_copy (&node->values[column], value);
 }
 
 static gboolean
@@ -513,25 +529,31 @@ _gtk_file_system_model_class_init (GtkFileSystemModelClass *class)
 
 /* NB: takes ownership of file and info */
 static void
-gtk_file_system_model_add_node (GtkFileSystemModel *model,
-                                FileModelNode *     node)
+gtk_file_system_model_add_node (GtkFileSystemModel *model, GFile *file, GFileInfo *info)
 {
-  g_assert (!node->visible); /* must be made visible later */
-  g_assert (model->files->len > 0);
+  FileModelNode *node = g_slice_alloc0 (NODE_SIZE (model));
+  guint i;
 
-  node->index = get_node (model, model->files->len - 1)->index;
+  node->file = file;
+  node->info = info;
+
+  if (model->files->len > 0)
+    node->index = get_node (model, model->files->len - 1)->index;
+  else
+    node->index = -1;
+
+  for (i = 0; i < model->n_columns; i++)
+    {
+      g_value_init (&node->values[i], model->column_types[i]);
+    }
 
   g_array_append_vals (model->files, node, 1);
+  g_slice_free1 (NODE_SIZE (model), node);
 }
 
 static void
 _gtk_file_system_model_init (GtkFileSystemModel *model)
 {
-  FileModelNode node = { NULL, NULL, -1, FALSE };
-
-  model->files = g_array_new (FALSE, FALSE, sizeof (FileModelNode));
-  g_array_append_val (model->files, node);
-
   model->show_files = TRUE;
   model->show_folders = TRUE;
   model->show_hidden = FALSE;
@@ -561,21 +583,20 @@ gtk_file_system_model_got_files (GObject *object, GAsyncResult *res, gpointer da
 
   for (walk = files; walk; walk = walk->next)
     {
-      FileModelNode node;
       const char *name;
+      GFileInfo *info;
+      GFile *file;
       
-      node.info = walk->data;
-      name = g_file_info_get_name (node.info);
+      info = walk->data;
+      name = g_file_info_get_name (info);
       if (name == NULL)
         {
           /* Shouldn't happen, but the APIs allow it */
-          g_object_unref (node.info);
+          g_object_unref (info);
           continue;
         }
-      node.file = g_file_get_child (model->dir, name);
-      /* set as invisible, because node_should_be_visible() requires it being added already */
-      node.visible = FALSE; 
-      gtk_file_system_model_add_node (model, &node);
+      file = g_file_get_child (model->dir, name);
+      gtk_file_system_model_add_node (model, file, info);
       node_set_visible (model, model->files->len - 1,
                         node_should_be_visible (model, model->files->len - 1));
     }
@@ -635,6 +656,35 @@ gtk_file_system_model_got_enumerator (GObject *dir, GAsyncResult *res, gpointer
   gdk_threads_leave ();
 }
 
+static void
+gtk_file_system_model_set_n_columns (GtkFileSystemModel *model,
+                                     gint                n_columns,
+                                     va_list             args)
+{
+  guint i;
+
+  g_assert (model->files == NULL);
+
+  model->n_columns = n_columns;
+  model->column_types = g_slice_alloc0 (sizeof (GType) * n_columns);
+
+  for (i = 0; i < (guint) n_columns; i++)
+    {
+      GType type = va_arg (args, GType);
+      if (! _gtk_tree_data_list_check_type (type))
+	{
+	  g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
+          continue;
+	}
+
+      model->column_types[i] = type;
+    }
+
+  model->files = g_array_new (FALSE, FALSE, NODE_SIZE (model));
+  /* add editable node at start */
+  gtk_file_system_model_add_node (model, NULL, NULL);
+}
+
 /**
  * _gtk_file_system_model_new:
  * @directory: the directory to show.
@@ -659,11 +709,16 @@ gtk_file_system_model_got_enumerator (GObject *dir, GAsyncResult *res, gpointer
  * was an error.
  **/
 GtkFileSystemModel *
-_gtk_file_system_model_new (GFile *      dir,
-			    const gchar *attributes,
-			    const gchar *full_attributes)
+_gtk_file_system_model_new (GFile *               dir,
+			    const gchar *         attributes,
+			    const gchar *         full_attributes,
+                            GtkFileSystemModelSet set_func,
+                            gpointer              set_data,
+                            guint                 n_columns,
+                            ...)
 {
   GtkFileSystemModel *model;
+  va_list args;
 
   g_return_val_if_fail (G_IS_FILE (dir), NULL);
 
@@ -671,6 +726,12 @@ _gtk_file_system_model_new (GFile *      dir,
   model->dir = g_object_ref (dir);
   model->attributes = g_strdup (attributes);
   model->full_attributes = g_strdup (full_attributes);
+  model->set_func = set_func;
+  model->set_data = set_data;
+
+  va_start (args, n_columns);
+  gtk_file_system_model_set_n_columns (model, n_columns, args);
+  va_end (args);
 
   g_object_ref (model);
   g_file_enumerate_children_async (dir,
diff --git a/gtk/gtkfilesystemmodel.h b/gtk/gtkfilesystemmodel.h
index f9e608d..dabd6a5 100644
--- a/gtk/gtkfilesystemmodel.h
+++ b/gtk/gtkfilesystemmodel.h
@@ -34,15 +34,19 @@ typedef struct _GtkFileSystemModel      GtkFileSystemModel;
 
 GType _gtk_file_system_model_get_type (void) G_GNUC_CONST;
 
-typedef enum {
-  GTK_FILE_SYSTEM_MODEL_INFO,
-  GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME,
-  GTK_FILE_SYSTEM_MODEL_N_COLUMNS
-} GtkFileSystemModelColumns;
+typedef void (*GtkFileSystemModelSet)        (GtkFileSystemModel *model,
+					      GFile              *file,
+					      GFileInfo          *info,
+                                              GValue             *values,
+					      gpointer            user_data);
 
 GtkFileSystemModel *_gtk_file_system_model_new              (GFile *             dir,
                                                              const gchar *       attributes,
-                                                             const gchar *       full_attributes);
+                                                             const gchar *       full_attributes,
+                                                             GtkFileSystemModelSet set_func,
+                                                             gpointer            set_data,
+                                                             guint               n_columns,
+                                                             ...);
 GFileInfo *         _gtk_file_system_model_get_info         (GtkFileSystemModel *model,
 							     GtkTreeIter        *iter);
 gboolean            _gtk_file_system_model_get_iter_for_file(GtkFileSystemModel *model,



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