1 /* GTK - The GIMP Toolkit
2 * gtkfilesystemmodel.c: GtkTreeModel wrapping a GtkFileSystem
3 * Copyright (C) 2003, Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
23 #include "gtkfilesystemmodel.h"
28 #include "gtkfilesystem.h"
30 #include "gtkmarshalers.h"
31 #include "gtktreedatalist.h"
32 #include "gtktreednd.h"
33 #include "gtktreemodel.h"
36 /*** Structure: how GtkFileSystemModel works
38 * This is a custom GtkTreeModel used to hold a collection of files for GtkFileChooser. There are two use cases:
40 * 1. The model populates itself from a folder, using the GIO file enumerator API. This happens if you use
41 * _gtk_file_system_model_new_for_directory(). This is the normal usage for showing the contents of a folder.
43 * 2. The caller populates the model by hand, with files not necessarily in the same folder. This happens
44 * if you use _gtk_file_system_model_new() and then _gtk_file_system_model_add_and_query_file(). This is
45 * the special kind of usage for "search" and "recent-files", where the file chooser gives the model the
46 * files to be displayed.
48 * Each file is kept in a FileModelNode structure. Each FileModelNode holds a GFile* and other data. All the
49 * node structures have the same size, determined at runtime, depending on the number of columns that were passed
50 * to _gtk_file_system_model_new() or _gtk_file_system_model_new_for_directory() (that is, the size of a node is
51 * not sizeof (FileModelNode), but rather model->node_size). The last field in the FileModelNode structure,
52 * node->values[], is an array of GValue, used to hold the data for those columns.
54 * The model stores an array of FileModelNode structures in model->files. This is a GArray where each element is
55 * model->node_size bytes in size (the model computes that node size when initializing itself). There are
56 * convenience macros, get_node() and node_index(), to access that array based on an array index or a pointer to
57 * a node inside the array.
59 * The model accesses files through two of its fields:
61 * model->files - GArray of FileModelNode structures.
63 * model->file_lookup - hash table that maps a GFile* to an index inside the model->files array.
65 * The model->file_lookup hash table is populated lazily. It is both accessed and populated with the
66 * node_get_for_file() function. The invariant is that the files in model->files[n] for n < g_hash_table_size
67 * (model->file_lookup) are already added to the hash table. The hash table will get cleared when we re-sort the
68 * files, as the array will be in a different order and the indexes need to be rebuilt.
70 * Each FileModelNode has a node->visible field, which indicates whether the node is visible in the GtkTreeView.
71 * A node may be invisible if, for example, it corresponds to a hidden file and the file chooser is not showing
74 * Since not all nodes in the model->files array may be visible, we need a way to map visible row indexes from
75 * the treeview to array indexes in our array of files. And thus we introduce a bit of terminology:
77 * index - An index in the model->files array. All variables/fields that represent indexes are either called
78 * "index" or "i_*", or simply "i" for things like loop counters.
80 * row - An index in the GtkTreeView, i.e. the index of a row within the outward-facing API of the
81 * GtkFileSystemModel. However, note that our rows are 1-based, not 0-based, for the reason explained in the
82 * following paragraph. Variables/fields that represent visible rows are called "row", or "r_*", or simply
85 * Each FileModelNode has a node->row field which is the number of visible rows in the treeview, *before and
86 * including* that node. This means that node->row is 1-based, instead of 0-based --- this makes some code
87 * simpler, believe it or not :) This also means that when the calling GtkTreeView gives us a GtkTreePath, we
88 * turn the 0-based treepath into a 1-based row for our purposes. If a node is not visible, it will have the
89 * same row number as its closest preceding visible node.
91 * We try to compute the node->row fields lazily. A node is said to be "valid" if its node->row is accurate.
92 * For this, the model keeps a model->n_nodes_valid field which is the count of valid nodes starting from the
93 * beginning of the model->files array. When a node changes its information, or when a node gets deleted, that
94 * node and the following ones get invalidated by simply setting model->n_nodes_valid to the array index of the
95 * node. If the model happens to need a node's row number and that node is in the model->files array after
96 * model->n_nodes_valid, then the nodes get re-validated up to the sought node. See node_validate_rows() for
99 * You never access a node->row directly. Instead, call node_get_tree_row(). That function will validate the nodes
100 * up to the sought one if the node is not valid yet, and it will return a proper 0-based row.
105 /* priority used for all async callbacks in the main loop
106 * This should be higher than redraw priorities so multiple callbacks
107 * firing can be handled without intermediate redraws */
108 #define IO_PRIORITY G_PRIORITY_DEFAULT
110 /* random number that everyone else seems to use, too */
111 #define FILES_PER_QUERY 100
113 typedef struct _FileModelNode FileModelNode;
114 typedef struct _GtkFileSystemModelClass GtkFileSystemModelClass;
116 struct _FileModelNode
118 GFile * file; /* file represented by this node or NULL for editable */
119 GFileInfo * info; /* info for this file or NULL if unknown */
121 guint row; /* if valid (see model->n_valid_indexes), visible nodes before and including
122 * this one - see the "Structure" comment above.
125 guint visible :1; /* if the file is currently visible */
126 guint frozen_add :1; /* true if the model was frozen and the entry has not been added yet */
128 GValue values[1]; /* actually n_columns values */
131 struct _GtkFileSystemModel
133 GObject parent_instance;
135 GFile * dir; /* directory that's displayed */
136 guint dir_thaw_source;/* GSource id for unfreezing the model */
137 char * attributes; /* attributes the file info must contain, or NULL for all attributes */
138 GFileMonitor * dir_monitor; /* directory that is monitored, or NULL if monitoring was not supported */
140 GCancellable * cancellable; /* cancellable in use for all operations - cancelled on dispose */
141 GArray * files; /* array of FileModelNode containing all our files */
142 gsize node_size; /* Size of a FileModelNode structure once its ->values field has n_columns */
143 guint n_nodes_valid; /* count of valid nodes (i.e. those whose node->row is accurate) */
144 GHashTable * file_lookup; /* mapping of GFile => array index in model->files
145 * This hash table doesn't always have the same number of entries as the files array;
146 * it can get cleared completely when we resort.
147 * The hash table gets re-populated in node_get_for_file() if this mismatch is
151 guint n_columns; /* number of columns */
152 GType * column_types; /* types of each column */
153 GtkFileSystemModelGetValue get_func; /* function to call to fill in values in columns */
154 gpointer get_data; /* data to pass to get_func */
156 GtkFileFilter * filter; /* filter to use for deciding which nodes are visible */
158 int sort_column_id; /* current sorting column */
159 GtkSortType sort_order; /* current sorting order */
160 GList * sort_list; /* list of sorting functions */
161 GtkTreeIterCompareFunc default_sort_func; /* default sort function */
162 gpointer default_sort_data; /* data to pass to default sort func */
163 GDestroyNotify default_sort_destroy; /* function to call to destroy default_sort_data */
165 guint frozen; /* number of times we're frozen */
167 gboolean filter_on_thaw :1;/* set when filtering needs to happen upon thawing */
168 gboolean sort_on_thaw :1;/* set when sorting needs to happen upon thawing */
170 guint show_hidden :1; /* whether to show hidden files */
171 guint show_folders :1;/* whether to show folders */
172 guint show_files :1; /* whether to show files */
175 #define GTK_FILE_SYSTEM_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_MODEL, GtkFileSystemModelClass))
176 #define GTK_IS_FILE_SYSTEM_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_MODEL))
177 #define GTK_FILE_SYSTEM_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_MODEL, GtkFileSystemModelClass))
179 struct _GtkFileSystemModelClass
181 GObjectClass parent_class;
185 void (*finished_loading) (GtkFileSystemModel *model, GError *error);
188 static void add_file (GtkFileSystemModel *model,
191 static void remove_file (GtkFileSystemModel *model,
195 * @user_data: the model
196 * @user_data2: GUINT_TO_POINTER of array index of current entry
198 * All other fields are unused. Note that the array index does not corrspond
199 * 1:1 with the path index as entries might not be visible.
201 #define ITER_INDEX(iter) GPOINTER_TO_UINT((iter)->user_data2)
202 #define ITER_IS_VALID(model, iter) ((model) == (iter)->user_data)
203 #define ITER_INIT_FROM_INDEX(model, _iter, _index) G_STMT_START {\
204 g_assert (_index < (model)->files->len); \
205 (_iter)->user_data = (model); \
206 (_iter)->user_data2 = GUINT_TO_POINTER (_index); \
209 /*** FileModelNode ***/
211 /* Get a FileModelNode structure given an index in the model->files array of nodes */
212 #define get_node(_model, _index) ((FileModelNode *) ((_model)->files->data + (_index) * (_model)->node_size))
214 /* Get an index within the model->files array of nodes, given a FileModelNode* */
215 #define node_index(_model, _node) (((gchar *) (_node) - (_model)->files->data) / (_model)->node_size)
217 /* @up_to_index: smallest model->files array index that will be valid after this call
218 * @up_to_row: smallest node->row that will be valid after this call
220 * If you want to validate up to an index or up to a row, specify the index or
221 * the row you want and specify G_MAXUINT for the other argument. Pass
222 * G_MAXUINT for both arguments for "validate everything".
225 node_validate_rows (GtkFileSystemModel *model, guint up_to_index, guint up_to_row)
229 if (model->files->len == 0)
232 up_to_index = MIN (up_to_index, model->files->len - 1);
234 i = model->n_nodes_valid;
236 row = get_node (model, i - 1)->row;
240 while (i <= up_to_index && row <= up_to_row)
242 FileModelNode *node = get_node (model, i);
248 model->n_nodes_valid = i;
252 node_get_tree_row (GtkFileSystemModel *model, guint index)
254 if (model->n_nodes_valid <= index)
255 node_validate_rows (model, index, G_MAXUINT);
257 return get_node (model, index)->row - 1;
261 node_invalidate_index (GtkFileSystemModel *model, guint id)
263 model->n_nodes_valid = MIN (model->n_nodes_valid, id);
267 gtk_tree_path_new_from_node (GtkFileSystemModel *model, guint id)
269 guint i = node_get_tree_row (model, id);
271 g_assert (i < model->files->len);
273 return gtk_tree_path_new_from_indices (i, -1);
277 emit_row_inserted_for_node (GtkFileSystemModel *model, guint id)
282 path = gtk_tree_path_new_from_node (model, id);
283 ITER_INIT_FROM_INDEX (model, &iter, id);
284 gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
285 gtk_tree_path_free (path);
289 emit_row_changed_for_node (GtkFileSystemModel *model, guint id)
294 path = gtk_tree_path_new_from_node (model, id);
295 ITER_INIT_FROM_INDEX (model, &iter, id);
296 gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
297 gtk_tree_path_free (path);
301 emit_row_deleted_for_row (GtkFileSystemModel *model, guint row)
305 path = gtk_tree_path_new_from_indices (row, -1);
306 gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
307 gtk_tree_path_free (path);
311 node_set_visible (GtkFileSystemModel *model, guint id, gboolean visible)
313 FileModelNode *node = get_node (model, id);
315 if (node->visible == visible ||
321 node->visible = TRUE;
322 node_invalidate_index (model, id);
323 emit_row_inserted_for_node (model, id);
329 row = node_get_tree_row (model, id);
330 g_assert (row < model->files->len);
332 node->visible = FALSE;
333 node_invalidate_index (model, id);
334 emit_row_deleted_for_row (model, row);
339 node_should_be_visible (GtkFileSystemModel *model, guint id)
341 FileModelNode *node = get_node (model, id);
342 GtkFileFilterInfo filter_info = { 0, };
343 GtkFileFilterFlags required;
344 gboolean is_folder, result;
345 char *mime_type = NULL;
346 char *filename = NULL;
349 if (node->info == NULL)
352 if (!model->show_hidden &&
353 (g_file_info_get_is_hidden (node->info) || g_file_info_get_is_backup (node->info)))
356 is_folder = _gtk_file_info_consider_as_directory (node->info);
359 if (model->show_folders != model->show_files &&
360 model->show_folders != is_folder)
366 if (model->filter == NULL)
370 required = gtk_file_filter_get_needed (model->filter);
372 filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME;
373 filter_info.display_name = g_file_info_get_display_name (node->info);
375 if (required & GTK_FILE_FILTER_MIME_TYPE)
377 const char *s = g_file_info_get_content_type (node->info);
380 mime_type = g_content_type_get_mime_type (s);
383 filter_info.mime_type = mime_type;
384 filter_info.contains |= GTK_FILE_FILTER_MIME_TYPE;
389 if (required & GTK_FILE_FILTER_FILENAME)
391 filename = g_file_get_path (node->file);
394 filter_info.filename = filename;
395 filter_info.contains |= GTK_FILE_FILTER_FILENAME;
399 if (required & GTK_FILE_FILTER_URI)
401 uri = g_file_get_uri (node->file);
404 filter_info.uri = uri;
405 filter_info.contains |= GTK_FILE_FILTER_URI;
409 result = gtk_file_filter_filter (model->filter, &filter_info);
418 /*** GtkTreeModel ***/
420 static GtkTreeModelFlags
421 gtk_file_system_model_get_flags (GtkTreeModel *tree_model)
423 /* GTK_TREE_MODEL_ITERS_PERSIST doesn't work with arrays :( */
424 return GTK_TREE_MODEL_LIST_ONLY;
428 gtk_file_system_model_get_n_columns (GtkTreeModel *tree_model)
430 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
432 return model->n_columns;
436 gtk_file_system_model_get_column_type (GtkTreeModel *tree_model,
439 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
441 g_return_val_if_fail (i >= 0 && (guint) i < model->n_columns, G_TYPE_NONE);
443 return model->column_types[i];
447 compare_indices (gconstpointer key, gconstpointer _node)
449 const FileModelNode *node = _node;
451 return GPOINTER_TO_UINT (key) - node->row;
455 gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
460 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
465 g_return_val_if_fail (n >= 0, FALSE);
470 row_to_find = n + 1; /* plus one as our node->row numbers are 1-based; see the "Structure" comment at the beginning */
472 if (model->n_nodes_valid > 0 &&
473 get_node (model, model->n_nodes_valid - 1)->row >= row_to_find)
475 /* Fast path - the nodes are valid up to the sought one.
477 * First, find a node with the sought row number...*/
479 node = bsearch (GUINT_TO_POINTER (row_to_find),
481 model->n_nodes_valid,
487 /* ... Second, back up until we find the first visible node with that row number */
489 id = node_index (model, node);
490 while (!get_node (model, id)->visible)
493 g_assert (get_node (model, id)->row == row_to_find);
497 /* Slow path - the nodes need to be validated up to the sought one */
499 node_validate_rows (model, G_MAXUINT, n); /* note that this is really "n", not row_to_find - see node_validate_rows() */
500 id = model->n_nodes_valid - 1;
501 if (model->n_nodes_valid == 0 || get_node (model, id)->row != row_to_find)
505 ITER_INIT_FROM_INDEX (model, iter, id);
510 gtk_file_system_model_get_iter (GtkTreeModel *tree_model,
514 g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
516 return gtk_file_system_model_iter_nth_child (tree_model,
519 gtk_tree_path_get_indices (path)[0]);
523 gtk_file_system_model_get_path (GtkTreeModel *tree_model,
526 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
528 g_return_val_if_fail (ITER_IS_VALID (model, iter), NULL);
530 return gtk_tree_path_new_from_node (model, ITER_INDEX (iter));
534 gtk_file_system_model_get_value (GtkTreeModel *tree_model,
539 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
540 const GValue *original;
542 g_return_if_fail ((guint) column < model->n_columns);
543 g_return_if_fail (ITER_IS_VALID (model, iter));
545 original = _gtk_file_system_model_get_value (model, iter, column);
548 g_value_init (value, G_VALUE_TYPE (original));
549 g_value_copy (original, value);
552 g_value_init (value, model->column_types[column]);
556 gtk_file_system_model_iter_next (GtkTreeModel *tree_model,
559 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
562 g_return_val_if_fail (ITER_IS_VALID (model, iter), FALSE);
564 for (i = ITER_INDEX (iter) + 1; i < model->files->len; i++)
566 FileModelNode *node = get_node (model, i);
570 ITER_INIT_FROM_INDEX (model, iter, i);
579 gtk_file_system_model_iter_children (GtkTreeModel *tree_model,
587 gtk_file_system_model_iter_has_child (GtkTreeModel *tree_model,
594 gtk_file_system_model_iter_n_children (GtkTreeModel *tree_model,
597 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
602 return node_get_tree_row (model, model->files->len - 1) + 1;
606 gtk_file_system_model_iter_parent (GtkTreeModel *tree_model,
614 gtk_file_system_model_ref_node (GtkTreeModel *tree_model,
621 gtk_file_system_model_unref_node (GtkTreeModel *tree_model,
628 gtk_file_system_model_iface_init (GtkTreeModelIface *iface)
630 iface->get_flags = gtk_file_system_model_get_flags;
631 iface->get_n_columns = gtk_file_system_model_get_n_columns;
632 iface->get_column_type = gtk_file_system_model_get_column_type;
633 iface->get_iter = gtk_file_system_model_get_iter;
634 iface->get_path = gtk_file_system_model_get_path;
635 iface->get_value = gtk_file_system_model_get_value;
636 iface->iter_next = gtk_file_system_model_iter_next;
637 iface->iter_children = gtk_file_system_model_iter_children;
638 iface->iter_has_child = gtk_file_system_model_iter_has_child;
639 iface->iter_n_children = gtk_file_system_model_iter_n_children;
640 iface->iter_nth_child = gtk_file_system_model_iter_nth_child;
641 iface->iter_parent = gtk_file_system_model_iter_parent;
642 iface->ref_node = gtk_file_system_model_ref_node;
643 iface->unref_node = gtk_file_system_model_unref_node;
646 /*** GtkTreeSortable ***/
648 typedef struct _SortData SortData;
650 GtkFileSystemModel * model;
651 GtkTreeIterCompareFunc func;
653 int order; /* -1 to invert sort order or 1 to keep it */
656 /* returns FALSE if no sort necessary */
658 sort_data_init (SortData *data, GtkFileSystemModel *model)
660 GtkTreeDataSortHeader *header;
662 if (model->files->len <= 2)
665 switch (model->sort_column_id)
667 case GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID:
668 if (!model->default_sort_func)
670 data->func = model->default_sort_func;
671 data->data = model->default_sort_data;
673 case GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID:
676 header = _gtk_tree_data_list_get_header (model->sort_list, model->sort_column_id);
679 data->func = header->func;
680 data->data = header->data;
684 data->order = model->sort_order == GTK_SORT_DESCENDING ? -1 : 1;
690 compare_array_element (gconstpointer a, gconstpointer b, gpointer user_data)
692 SortData *data = user_data;
693 GtkTreeIter itera, iterb;
695 ITER_INIT_FROM_INDEX (data->model, &itera, node_index (data->model, a));
696 ITER_INIT_FROM_INDEX (data->model, &iterb, node_index (data->model, b));
697 return data->func (GTK_TREE_MODEL (data->model), &itera, &iterb, data->data) * data->order;
701 gtk_file_system_model_sort (GtkFileSystemModel *model)
707 model->sort_on_thaw = TRUE;
711 if (sort_data_init (&data, model))
715 guint r, n_visible_rows;
717 node_validate_rows (model, G_MAXUINT, G_MAXUINT);
718 n_visible_rows = node_get_tree_row (model, model->files->len - 1) + 1;
719 model->n_nodes_valid = 0;
720 g_hash_table_remove_all (model->file_lookup);
721 g_qsort_with_data (get_node (model, 1), /* start at index 1; don't sort the editable row */
722 model->files->len - 1,
724 compare_array_element,
726 g_assert (model->n_nodes_valid == 0);
727 g_assert (g_hash_table_size (model->file_lookup) == 0);
730 int *new_order = g_new (int, n_visible_rows);
733 for (i = 0; i < model->files->len; i++)
735 FileModelNode *node = get_node (model, i);
742 new_order[r] = node->row;
746 g_assert (r == n_visible_rows);
747 path = gtk_tree_path_new ();
748 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model),
752 gtk_tree_path_free (path);
757 model->sort_on_thaw = FALSE;
761 gtk_file_system_model_sort_node (GtkFileSystemModel *model, guint node)
764 gtk_file_system_model_sort (model);
768 gtk_file_system_model_get_sort_column_id (GtkTreeSortable *sortable,
769 gint *sort_column_id,
772 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (sortable);
775 *sort_column_id = model->sort_column_id;
777 *order = model->sort_order;
779 if (model->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID ||
780 model->sort_column_id == GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
787 gtk_file_system_model_set_sort_column_id (GtkTreeSortable *sortable,
791 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (sortable);
793 if ((model->sort_column_id == sort_column_id) &&
794 (model->sort_order == order))
797 if (sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
799 if (sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
801 GtkTreeDataSortHeader *header = NULL;
803 header = _gtk_tree_data_list_get_header (model->sort_list,
806 /* We want to make sure that we have a function */
807 g_return_if_fail (header != NULL);
808 g_return_if_fail (header->func != NULL);
812 g_return_if_fail (model->default_sort_func != NULL);
817 model->sort_column_id = sort_column_id;
818 model->sort_order = order;
820 gtk_tree_sortable_sort_column_changed (sortable);
822 gtk_file_system_model_sort (model);
826 gtk_file_system_model_set_sort_func (GtkTreeSortable *sortable,
828 GtkTreeIterCompareFunc func,
830 GDestroyNotify destroy)
832 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (sortable);
834 model->sort_list = _gtk_tree_data_list_set_header (model->sort_list,
836 func, data, destroy);
838 if (model->sort_column_id == sort_column_id)
839 gtk_file_system_model_sort (model);
843 gtk_file_system_model_set_default_sort_func (GtkTreeSortable *sortable,
844 GtkTreeIterCompareFunc func,
846 GDestroyNotify destroy)
848 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (sortable);
850 if (model->default_sort_destroy)
852 GDestroyNotify d = model->default_sort_destroy;
854 model->default_sort_destroy = NULL;
855 d (model->default_sort_data);
858 model->default_sort_func = func;
859 model->default_sort_data = data;
860 model->default_sort_destroy = destroy;
862 if (model->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
863 gtk_file_system_model_sort (model);
867 gtk_file_system_model_has_default_sort_func (GtkTreeSortable *sortable)
869 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (sortable);
871 return (model->default_sort_func != NULL);
875 gtk_file_system_model_sortable_init (GtkTreeSortableIface *iface)
877 iface->get_sort_column_id = gtk_file_system_model_get_sort_column_id;
878 iface->set_sort_column_id = gtk_file_system_model_set_sort_column_id;
879 iface->set_sort_func = gtk_file_system_model_set_sort_func;
880 iface->set_default_sort_func = gtk_file_system_model_set_default_sort_func;
881 iface->has_default_sort_func = gtk_file_system_model_has_default_sort_func;
884 /*** GtkTreeDragSource ***/
887 drag_source_row_draggable (GtkTreeDragSource *drag_source,
890 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (drag_source);
893 if (!gtk_file_system_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
896 return ITER_INDEX (&iter) != 0;
900 drag_source_drag_data_get (GtkTreeDragSource *drag_source,
902 GtkSelectionData *selection_data)
904 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (drag_source);
909 if (!gtk_file_system_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
912 node = get_node (model, ITER_INDEX (&iter));
913 if (node->file == NULL)
916 uris[0] = g_file_get_uri (node->file);
918 gtk_selection_data_set_uris (selection_data, uris);
925 drag_source_iface_init (GtkTreeDragSourceIface *iface)
927 iface->row_draggable = drag_source_row_draggable;
928 iface->drag_data_get = drag_source_drag_data_get;
929 iface->drag_data_delete = NULL;
932 /*** GtkFileSystemModel ***/
940 static guint file_system_model_signals[LAST_SIGNAL] = { 0 };
944 G_DEFINE_TYPE_WITH_CODE (GtkFileSystemModel, _gtk_file_system_model, G_TYPE_OBJECT,
945 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
946 gtk_file_system_model_iface_init)
947 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
948 gtk_file_system_model_sortable_init)
949 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
950 drag_source_iface_init))
953 gtk_file_system_model_dispose (GObject *object)
955 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (object);
957 if (model->dir_thaw_source)
959 g_source_remove (model->dir_thaw_source);
960 model->dir_thaw_source = 0;
963 g_cancellable_cancel (model->cancellable);
964 if (model->dir_monitor)
965 g_file_monitor_cancel (model->dir_monitor);
967 G_OBJECT_CLASS (_gtk_file_system_model_parent_class)->dispose (object);
972 gtk_file_system_model_finalize (GObject *object)
974 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (object);
977 for (i = 0; i < model->files->len; i++)
981 FileModelNode *node = get_node (model, i);
983 g_object_unref (node->file);
985 g_object_unref (node->info);
987 for (v = 0; v < model->column_types; v++)
988 if (G_VALUE_TYPE (node->values[v]) != G_TYPE_INVALID)
989 g_value_unset (&node->values[v]);
991 g_array_free (model->files, TRUE);
993 g_object_unref (model->cancellable);
994 g_free (model->attributes);
996 g_object_unref (model->dir);
997 if (model->dir_monitor)
998 g_object_unref (model->dir_monitor);
999 g_hash_table_destroy (model->file_lookup);
1001 g_object_unref (model->filter);
1003 g_slice_free1 (sizeof (GType) * n_columns, model->column_types);
1005 _gtk_tree_data_list_header_free (model->sort_list);
1006 if (model->default_sort_destroy)
1007 model->default_sort_destroy (model->default_sort_data);
1009 G_OBJECT_CLASS (_gtk_file_system_model_parent_class)->finalize (object);
1013 _gtk_file_system_model_class_init (GtkFileSystemModelClass *class)
1015 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1017 gobject_class->finalize = gtk_file_system_model_finalize;
1018 gobject_class->dispose = gtk_file_system_model_dispose;
1020 file_system_model_signals[FINISHED_LOADING] =
1021 g_signal_new (I_("finished-loading"),
1022 G_OBJECT_CLASS_TYPE (gobject_class),
1024 G_STRUCT_OFFSET (GtkFileSystemModelClass, finished_loading),
1026 _gtk_marshal_VOID__POINTER,
1027 G_TYPE_NONE, 1, G_TYPE_POINTER);
1031 _gtk_file_system_model_init (GtkFileSystemModel *model)
1033 model->show_files = TRUE;
1034 model->show_folders = TRUE;
1035 model->show_hidden = FALSE;
1037 model->sort_column_id = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
1039 model->file_lookup = g_hash_table_new (g_file_hash, (GEqualFunc) g_file_equal);
1040 model->cancellable = g_cancellable_new ();
1046 gtk_file_system_model_closed_enumerator (GObject *object, GAsyncResult *res, gpointer data)
1048 g_file_enumerator_close_finish (G_FILE_ENUMERATOR (object), res, NULL);
1052 thaw_func (gpointer data)
1054 GtkFileSystemModel *model = data;
1056 _gtk_file_system_model_thaw_updates (model);
1057 model->dir_thaw_source = 0;
1063 gtk_file_system_model_got_files (GObject *object, GAsyncResult *res, gpointer data)
1065 GFileEnumerator *enumerator = G_FILE_ENUMERATOR (object);
1066 GtkFileSystemModel *model = data;
1067 GList *walk, *files;
1068 GError *error = NULL;
1070 gdk_threads_enter ();
1072 files = g_file_enumerator_next_files_finish (enumerator, res, &error);
1076 if (model->dir_thaw_source == 0)
1078 _gtk_file_system_model_freeze_updates (model);
1079 model->dir_thaw_source = gdk_threads_add_timeout_full (IO_PRIORITY + 1,
1086 for (walk = files; walk; walk = walk->next)
1093 name = g_file_info_get_name (info);
1096 /* Shouldn't happen, but the APIs allow it */
1097 g_object_unref (info);
1100 file = g_file_get_child (model->dir, name);
1101 add_file (model, file, info);
1102 g_object_unref (file);
1103 g_object_unref (info);
1105 g_list_free (files);
1107 g_file_enumerator_next_files_async (enumerator,
1108 g_file_is_native (model->dir) ? 50 * FILES_PER_QUERY : FILES_PER_QUERY,
1111 gtk_file_system_model_got_files,
1116 g_file_enumerator_close_async (enumerator,
1119 gtk_file_system_model_closed_enumerator,
1121 if (model->dir_thaw_source != 0)
1123 g_source_remove (model->dir_thaw_source);
1124 model->dir_thaw_source = 0;
1125 _gtk_file_system_model_thaw_updates (model);
1128 g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0, error);
1131 g_error_free (error);
1133 g_object_unref (model);
1136 gdk_threads_leave ();
1140 gtk_file_system_model_query_done (GObject * object,
1144 GtkFileSystemModel *model = data; /* only a valid pointer if not cancelled */
1145 GFile *file = G_FILE (object);
1148 info = g_file_query_info_finish (file, res, NULL);
1152 _gtk_file_system_model_update_file (model, file, info, TRUE);
1156 gtk_file_system_model_monitor_change (GFileMonitor * monitor,
1159 GFileMonitorEvent type,
1160 GtkFileSystemModel *model)
1164 case G_FILE_MONITOR_EVENT_CREATED:
1165 case G_FILE_MONITOR_EVENT_CHANGED:
1166 case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
1167 /* We can treat all of these the same way */
1168 g_file_query_info_async (file,
1170 G_FILE_QUERY_INFO_NONE,
1173 gtk_file_system_model_query_done,
1176 case G_FILE_MONITOR_EVENT_DELETED:
1177 remove_file (model, file);
1179 case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
1180 /* FIXME: use freeze/thaw with this somehow? */
1181 case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
1182 case G_FILE_MONITOR_EVENT_UNMOUNTED:
1190 gtk_file_system_model_got_enumerator (GObject *dir, GAsyncResult *res, gpointer data)
1192 GtkFileSystemModel *model = data;
1193 GFileEnumerator *enumerator;
1194 GError *error = NULL;
1196 gdk_threads_enter ();
1198 enumerator = g_file_enumerate_children_finish (G_FILE (dir), res, &error);
1199 if (enumerator == NULL)
1201 g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0, error);
1202 g_object_unref (model);
1203 g_error_free (error);
1207 g_file_enumerator_next_files_async (enumerator,
1208 g_file_is_native (model->dir) ? 50 * FILES_PER_QUERY : FILES_PER_QUERY,
1211 gtk_file_system_model_got_files,
1213 g_object_unref (enumerator);
1214 model->dir_monitor = g_file_monitor_directory (model->dir,
1215 G_FILE_MONITOR_NONE,
1217 NULL); /* we don't mind if directory monitoring isn't supported, so the GError is NULL here */
1218 if (model->dir_monitor)
1219 g_signal_connect (model->dir_monitor,
1221 G_CALLBACK (gtk_file_system_model_monitor_change),
1225 gdk_threads_leave ();
1229 gtk_file_system_model_set_n_columns (GtkFileSystemModel *model,
1235 g_assert (model->files == NULL);
1236 g_assert (n_columns > 0);
1238 model->n_columns = n_columns;
1239 model->column_types = g_slice_alloc (sizeof (GType) * n_columns);
1241 model->node_size = sizeof (FileModelNode) + sizeof (GValue) * (n_columns - 1); /* minus 1 because FileModelNode.values[] has a default size of 1 */
1243 for (i = 0; i < (guint) n_columns; i++)
1245 GType type = va_arg (args, GType);
1246 if (! _gtk_tree_data_list_check_type (type))
1248 g_error ("%s: type %s cannot be a column type for GtkFileSystemModel\n", G_STRLOC, g_type_name (type));
1249 return; /* not reached */
1252 model->column_types[i] = type;
1255 model->sort_list = _gtk_tree_data_list_header_new (n_columns, model->column_types);
1257 model->files = g_array_sized_new (FALSE, FALSE, model->node_size, FILES_PER_QUERY);
1258 /* add editable node at start */
1259 g_array_set_size (model->files, 1);
1260 memset (get_node (model, 0), 0, model->node_size);
1264 gtk_file_system_model_set_directory (GtkFileSystemModel *model,
1266 const gchar * attributes)
1268 g_assert (G_IS_FILE (dir));
1270 model->dir = g_object_ref (dir);
1271 model->attributes = g_strdup (attributes);
1273 g_object_ref (model);
1274 g_file_enumerate_children_async (model->dir,
1276 G_FILE_QUERY_INFO_NONE,
1279 gtk_file_system_model_got_enumerator,
1284 static GtkFileSystemModel *
1285 _gtk_file_system_model_new_valist (GtkFileSystemModelGetValue get_func,
1290 GtkFileSystemModel *model;
1292 model = g_object_new (GTK_TYPE_FILE_SYSTEM_MODEL, NULL);
1293 model->get_func = get_func;
1294 model->get_data = get_data;
1296 gtk_file_system_model_set_n_columns (model, n_columns, args);
1302 * _gtk_file_system_model_new:
1303 * @get_func: function to call for getting a value
1304 * @get_data: user data argument passed to @get_func
1305 * @n_columns: number of columns
1306 * @...: @n_columns #GType types for the columns
1308 * Creates a new #GtkFileSystemModel object. You need to add files
1309 * to the list using _gtk_file_system_model_add_and_query_file()
1310 * or _gtk_file_system_model_update_file().
1312 * Return value: the newly created #GtkFileSystemModel
1314 GtkFileSystemModel *
1315 _gtk_file_system_model_new (GtkFileSystemModelGetValue get_func,
1320 GtkFileSystemModel *model;
1323 g_return_val_if_fail (get_func != NULL, NULL);
1324 g_return_val_if_fail (n_columns > 0, NULL);
1326 va_start (args, n_columns);
1327 model = _gtk_file_system_model_new_valist (get_func, get_data, n_columns, args);
1334 * _gtk_file_system_model_new_for_directory:
1335 * @directory: the directory to show.
1336 * @attributes: attributes to immediately load or %NULL for all
1337 * @get_func: function that the model should call to query data about a file
1338 * @get_data: user data to pass to the @get_func
1339 * @n_columns: number of columns
1340 * @...: @n_columns #GType types for the columns
1342 * Creates a new #GtkFileSystemModel object. The #GtkFileSystemModel
1343 * object wraps the given @directory as a #GtkTreeModel.
1344 * The model will query the given directory with the given @attributes
1345 * and add all files inside the directory automatically. If supported,
1346 * it will also monitor the drectory and update the model's
1347 * contents to reflect changes, if the @directory supports monitoring.
1349 * Return value: the newly created #GtkFileSystemModel
1351 GtkFileSystemModel *
1352 _gtk_file_system_model_new_for_directory (GFile * dir,
1353 const gchar * attributes,
1354 GtkFileSystemModelGetValue get_func,
1359 GtkFileSystemModel *model;
1362 g_return_val_if_fail (G_IS_FILE (dir), NULL);
1363 g_return_val_if_fail (get_func != NULL, NULL);
1364 g_return_val_if_fail (n_columns > 0, NULL);
1366 va_start (args, n_columns);
1367 model = _gtk_file_system_model_new_valist (get_func, get_data, n_columns, args);
1370 gtk_file_system_model_set_directory (model, dir, attributes);
1376 gtk_file_system_model_refilter_all (GtkFileSystemModel *model)
1382 model->filter_on_thaw = TRUE;
1386 _gtk_file_system_model_freeze_updates (model);
1388 /* start at index 1, don't change the editable */
1389 for (i = 1; i < model->files->len; i++)
1391 node_set_visible (model, i, node_should_be_visible (model, i));
1394 model->filter_on_thaw = FALSE;
1395 _gtk_file_system_model_thaw_updates (model);
1399 * _gtk_file_system_model_set_show_hidden:
1400 * @model: a #GtkFileSystemModel
1401 * @show_hidden: whether hidden files should be displayed
1403 * Sets whether hidden files should be included in the #GtkTreeModel
1407 _gtk_file_system_model_set_show_hidden (GtkFileSystemModel *model,
1408 gboolean show_hidden)
1410 g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
1412 show_hidden = show_hidden != FALSE;
1414 if (show_hidden != model->show_hidden)
1416 model->show_hidden = show_hidden;
1417 gtk_file_system_model_refilter_all (model);
1422 * _gtk_file_system_model_set_show_folders:
1423 * @model: a #GtkFileSystemModel
1424 * @show_folders: whether folders should be displayed
1426 * Sets whether folders should be included in the #GtkTreeModel for
1430 _gtk_file_system_model_set_show_folders (GtkFileSystemModel *model,
1431 gboolean show_folders)
1433 g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
1435 show_folders = show_folders != FALSE;
1437 if (show_folders != model->show_folders)
1439 model->show_folders = show_folders;
1440 gtk_file_system_model_refilter_all (model);
1445 * _gtk_file_system_model_set_show_files:
1446 * @model: a #GtkFileSystemModel
1447 * @show_files: whether files (as opposed to folders) should
1450 * Sets whether files (as opposed to folders) should be included
1451 * in the #GtkTreeModel for display.
1454 _gtk_file_system_model_set_show_files (GtkFileSystemModel *model,
1455 gboolean show_files)
1457 g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
1459 show_files = show_files != FALSE;
1461 if (show_files != model->show_files)
1463 model->show_files = show_files;
1464 gtk_file_system_model_refilter_all (model);
1469 * _gtk_file_system_model_get_cancellable:
1472 * Gets the cancellable used by the @model. This is the cancellable used
1473 * internally by the @model that will be cancelled when @model is
1474 * disposed. So you can use it for operations that should be cancelled
1475 * when the model goes away.
1477 * Returns: The cancellable used by @model
1480 _gtk_file_system_model_get_cancellable (GtkFileSystemModel *model)
1482 g_return_val_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model), NULL);
1484 return model->cancellable;
1488 * _gtk_file_system_model_iter_is_visible:
1490 * @iter: a valid iterator
1492 * Checks if the iterator is visible. A visible iterator references
1493 * a row that is currently exposed using the #GtkTreeModel API. If
1494 * the iterator is invisible, it references a file that is not shown
1495 * for some reason, such as being filtered by the current filter or
1496 * being a hidden file.
1498 * Returns: %TRUE if the iterator is visible
1501 _gtk_file_system_model_iter_is_visible (GtkFileSystemModel *model,
1504 FileModelNode *node;
1506 g_return_val_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model), FALSE);
1507 g_return_val_if_fail (iter != NULL, FALSE);
1509 node = get_node (model, ITER_INDEX (iter));
1510 return node->visible;
1514 * _gtk_file_system_model_get_info:
1515 * @model: a #GtkFileSystemModel
1516 * @iter: a #GtkTreeIter pointing to a row of @model
1518 * Gets the #GFileInfo structure for a particular row
1521 * Return value: a #GFileInfo structure. This structure
1522 * is owned by @model and must not be modified or freed.
1523 * If you want to keep the information for later use,
1524 * you must take a reference, since the structure may be
1525 * freed on later changes to the file system. If you have
1526 * called _gtk_file_system_model_add_editable() and the @iter
1527 * corresponds to the row that this function returned, the
1528 * return value will be NULL.
1531 _gtk_file_system_model_get_info (GtkFileSystemModel *model,
1534 FileModelNode *node;
1536 g_return_val_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model), NULL);
1537 g_return_val_if_fail (iter != NULL, NULL);
1539 node = get_node (model, ITER_INDEX (iter));
1540 g_assert (node->info == NULL || G_IS_FILE_INFO (node->info));
1545 * _gtk_file_system_model_get_file:
1546 * @model: a #GtkFileSystemModel
1547 * @iter: a #GtkTreeIter pointing to a row of @model
1549 * Gets the file for a particular row in @model.
1551 * Return value: the file. This object is owned by @model and
1552 * or freed. If you want to save the path for later use,
1553 * you must take a ref, since the object may be freed
1554 * on later changes to the file system.
1557 _gtk_file_system_model_get_file (GtkFileSystemModel *model,
1560 FileModelNode *node;
1562 g_return_val_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model), NULL);
1564 node = get_node (model, ITER_INDEX (iter));
1569 * _gtk_file_system_model_get_value:
1570 * @model: a #GtkFileSystemModel
1571 * @iter: a #GtkTreeIter pointing to a row of @model
1572 * @column: the column to get the value for
1574 * Gets the value associated with the given row @iter and @column.
1575 * If no value is available yet and the default value should be used,
1576 * %NULL is returned.
1577 * This is a performance optimization for the calls
1578 * gtk_tree_model_get() or gtk_tree_model_get_value(), which copy
1579 * the value and spend a considerable amount of time in iterator
1580 * lookups. Both of which are slow.
1582 * Returns: a pointer to the actual value as stored in @model or %NULL
1583 * if no value available yet.
1586 _gtk_file_system_model_get_value (GtkFileSystemModel *model,
1590 FileModelNode *node;
1592 g_return_val_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model), NULL);
1593 g_return_val_if_fail (column >= 0 && (guint) column < model->n_columns, NULL);
1595 node = get_node (model, ITER_INDEX (iter));
1597 if (!G_VALUE_TYPE (&node->values[column]))
1599 g_value_init (&node->values[column], model->column_types[column]);
1600 if (!model->get_func (model,
1604 &node->values[column],
1607 g_value_unset (&node->values[column]);
1612 return &node->values[column];
1616 node_get_for_file (GtkFileSystemModel *model,
1621 i = GPOINTER_TO_UINT (g_hash_table_lookup (model->file_lookup, file));
1625 /* Node 0 is the editable row and has no associated file or entry in the table, so we start counting from 1.
1627 * The invariant here is that the files in model->files[n] for n < g_hash_table_size (model->file_lookup)
1628 * are already added to the hash table. The table can get cleared when we re-sort; this loop merely rebuilds
1629 * our (file -> index) mapping on demand.
1631 * If we exit the loop, the next pending batch of mappings will be resolved when this function gets called again
1632 * with another file that is not yet in the mapping.
1634 for (i = g_hash_table_size (model->file_lookup) + 1; i < model->files->len; i++)
1636 FileModelNode *node = get_node (model, i);
1638 g_hash_table_insert (model->file_lookup, node->file, GUINT_TO_POINTER (i));
1639 if (g_file_equal (node->file, file))
1647 * _gtk_file_system_model_get_iter_for_file:
1649 * @iter: the iterator to be initialized
1650 * @file: the file to look up
1652 * Initializes @iter to point to the row used for @file, if @file is part
1653 * of the model. Note that upon successful return, @iter may point to an
1654 * invisible row in the @model. Use
1655 * _gtk_file_system_model_iter_is_visible() to make sure it is visible to
1658 * Returns: %TRUE if file is part of the model and @iter was initialized
1661 _gtk_file_system_model_get_iter_for_file (GtkFileSystemModel *model,
1667 g_return_val_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model), FALSE);
1668 g_return_val_if_fail (iter != NULL, FALSE);
1669 g_return_val_if_fail (G_IS_FILE (file), FALSE);
1671 i = node_get_for_file (model, file);
1676 ITER_INIT_FROM_INDEX (model, iter, i);
1683 * @file: the file to add
1684 * @info: the information to associate with the file
1686 * Adds the given @file with its associated @info to the @model.
1687 * If the model is frozen, the file will only show up after it is thawn.
1690 add_file (GtkFileSystemModel *model,
1694 FileModelNode *node;
1696 g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
1697 g_return_if_fail (G_IS_FILE (file));
1698 g_return_if_fail (G_IS_FILE_INFO (info));
1700 node = g_slice_alloc0 (model->node_size);
1701 node->file = g_object_ref (file);
1703 node->info = g_object_ref (info);
1704 node->frozen_add = model->frozen ? TRUE : FALSE;
1706 g_array_append_vals (model->files, node, 1);
1707 g_slice_free1 (model->node_size, node);
1710 node_set_visible (model, model->files->len -1,
1711 node_should_be_visible (model, model->files->len - 1));
1712 gtk_file_system_model_sort_node (model, model->files->len -1);
1718 * @file: file to remove from the model. The file must have been
1719 * added to the model previously
1721 * Removes the given file from the model. If the file is not part of
1722 * @model, this function does nothing.
1725 remove_file (GtkFileSystemModel *model,
1728 FileModelNode *node;
1731 g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
1732 g_return_if_fail (G_IS_FILE (file));
1734 id = node_get_for_file (model, file);
1738 node = get_node (model, id);
1739 node_set_visible (model, id, FALSE);
1741 g_hash_table_remove (model->file_lookup, file);
1742 g_object_unref (node->file);
1745 g_object_unref (node->info);
1747 g_array_remove_index (model->files, id);
1748 /* We don't need to resort, as removing a row doesn't change the sorting order */
1752 * _gtk_file_system_model_update_file:
1755 * @info: the new file info
1756 * @requires_resort: FIXME: get rid of this argument
1758 * Tells the file system model that the file changed and that the
1759 * new @info should be used for it now. If the file is not part of
1760 * @model, it will get added automatically.
1763 _gtk_file_system_model_update_file (GtkFileSystemModel *model,
1766 gboolean requires_resort)
1768 FileModelNode *node;
1770 GFileInfo *old_info;
1772 g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
1773 g_return_if_fail (G_IS_FILE (file));
1774 g_return_if_fail (G_IS_FILE_INFO (info));
1776 id = node_get_for_file (model, file);
1778 add_file (model, file, info);
1780 node = get_node (model, id);
1782 old_info = node->info;
1783 node->info = g_object_ref (info);
1785 g_object_unref (old_info);
1787 for (i = 0; i < model->n_columns; i++)
1789 if (G_VALUE_TYPE (&node->values[i]))
1790 g_value_unset (&node->values[i]);
1794 emit_row_changed_for_node (model, id);
1796 if (requires_resort)
1797 gtk_file_system_model_sort_node (model, id);
1801 * _gtk_file_system_model_set_filter:
1802 * @mode: a #GtkFileSystemModel
1803 * @filter: %NULL or filter to use
1805 * Sets a filter to be used for deciding if a row should be visible or not.
1806 * Directories are always visible.
1809 _gtk_file_system_model_set_filter (GtkFileSystemModel *model,
1810 GtkFileFilter * filter)
1812 GtkFileFilter *old_filter;
1814 g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
1815 g_return_if_fail (filter == NULL || GTK_IS_FILE_FILTER (filter));
1818 g_object_ref (filter);
1820 old_filter = model->filter;
1821 model->filter = filter;
1824 g_object_unref (old_filter);
1826 gtk_file_system_model_refilter_all (model);
1830 * _gtk_file_system_model_add_editable:
1831 * @model: a #GtkFileSystemModel
1832 * @iter: Location to return the iter corresponding to the editable row
1834 * Adds an "empty" row at the beginning of the model. This does not refer to
1835 * any file, but is a temporary placeholder for a file name that the user will
1836 * type when a corresponding cell is made editable. When your code is done
1837 * using this temporary row, call _gtk_file_system_model_remove_editable().
1840 _gtk_file_system_model_add_editable (GtkFileSystemModel *model, GtkTreeIter *iter)
1842 g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
1843 g_return_if_fail (!get_node (model, 0)->visible);
1845 node_set_visible (model, 0, TRUE);
1846 ITER_INIT_FROM_INDEX (model, iter, 0);
1850 * _gtk_file_system_model_remove_editable:
1851 * @model: a #GtkFileSystemModel
1853 * Removes the "empty" row at the beginning of the model that was
1854 * created with _gtk_file_system_model_add_editable(). You should call
1855 * this function when your code is finished editing this temporary row.
1858 _gtk_file_system_model_remove_editable (GtkFileSystemModel *model)
1860 g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
1861 g_return_if_fail (get_node (model, 0)->visible);
1863 node_set_visible (model, 0, FALSE);
1867 * _gtk_file_system_model_freeze_updates:
1868 * @model: a #GtkFileSystemModel
1870 * Freezes most updates on the model, so that performing multiple
1871 * operations on the files in the model do not cause any events.
1872 * Use _gtk_file_system_model_thaw_updates() to resume proper
1873 * operations. It is fine to call this function multiple times as
1874 * long as freeze and thaw calls are balanced.
1877 _gtk_file_system_model_freeze_updates (GtkFileSystemModel *model)
1879 g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
1885 * _gtk_file_system_model_thaw_updates:
1886 * @model: a #GtkFileSystemModel
1888 * Undoes the effect of a previous call to
1889 * _gtk_file_system_model_freeze_updates()
1892 _gtk_file_system_model_thaw_updates (GtkFileSystemModel *model)
1894 gboolean stuff_added;
1896 g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
1897 g_return_if_fail (model->frozen > 0);
1900 if (model->frozen > 0)
1903 stuff_added = get_node (model, model->files->len - 1)->frozen_add;
1905 if (model->filter_on_thaw)
1906 gtk_file_system_model_refilter_all (model);
1907 if (model->sort_on_thaw)
1908 gtk_file_system_model_sort (model);
1913 for (i = 0; i < model->files->len; i++)
1915 FileModelNode *node = get_node (model, i);
1917 if (!node->frozen_add)
1919 node->frozen_add = FALSE;
1920 node_set_visible (model, i, node_should_be_visible (model, i));
1926 * _gtk_file_system_model_clear_cache:
1927 * @model: a #GtkFileSystemModel
1928 * @column: the column to clear or -1 for all columns
1930 * Clears the cached values in the model for the given @column. Use
1931 * this function whenever your get_value function would return different
1932 * values for a column.
1933 * The file chooser uses this for example when the icon theme changes to
1934 * invalidate the cached pixbufs.
1937 _gtk_file_system_model_clear_cache (GtkFileSystemModel *model,
1944 g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
1945 g_return_if_fail (column >= -1 && (guint) column < model->n_columns);
1955 end = model->n_columns;
1958 for (i = 0; i < model->files->len; i++)
1960 FileModelNode *node = get_node (model, i);
1962 for (column = start; column < end; column++)
1964 if (!G_VALUE_TYPE (&node->values[column]))
1967 g_value_unset (&node->values[column]);
1971 if (changed && node->visible)
1972 emit_row_changed_for_node (model, i);
1975 /* FIXME: resort? */
1979 * _gtk_file_system_model_add_and_query_file:
1980 * @model: a #GtkFileSystemModel
1981 * @file: the file to add
1982 * @attributes: attributes to query before adding the file
1984 * This is a conenience function that calls g_file_query_info_async() on
1985 * the given file, and when successful, adds it to the model.
1986 * Upon failure, the @file is discarded.
1989 _gtk_file_system_model_add_and_query_file (GtkFileSystemModel *model,
1991 const char * attributes)
1993 g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
1994 g_return_if_fail (G_IS_FILE (file));
1995 g_return_if_fail (attributes != NULL);
1997 g_file_query_info_async (file,
1999 G_FILE_QUERY_INFO_NONE,
2002 gtk_file_system_model_query_done,