summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2003-07-23 15:31:10 +0000
committerOwen Taylor <otaylor@src.gnome.org>2003-07-23 15:31:10 +0000
commit733f4489ade5b79227af871e1cbe694806ec367e (patch)
treecb11e44251dfd274d38a2ef88d2cd7f3bb8619f1 /gtk
parent96ba7bb65e02858e08f78922f4d837ac7d1a65a0 (diff)
downloadgdk-pixbuf-733f4489ade5b79227af871e1cbe694806ec367e.tar.gz
File filter objects.
Wed Jul 23 11:23:43 2003 Owen Taylor <otaylor@redhat.com> * gtkfilefilter.[ch]: File filter objects. * gtkfilechooser.[ch] gtkfilechooserutils.[ch]: Add file filtering to API. * gtkfilechooserimpldefault.c: Implement file filters. * testfilechooser.c: Try out the filter functionality. * gtkfilesystemmodel.c: Add _gtk_file_system_model_set_filter() to set a callback function for filtering. * gtkfilechooserutils.c: Propagate property notification to the receiver. * fnmatch.c: Copy this from GTK+ temporarily to get UTF-8 pattern matching functionality.
Diffstat (limited to 'gtk')
-rw-r--r--gtk/gtkfilechooser.c117
-rw-r--r--gtk/gtkfilechooser.h33
-rw-r--r--gtk/gtkfilechooserdefault.c295
-rw-r--r--gtk/gtkfilechooserprivate.h18
-rw-r--r--gtk/gtkfilechooserutils.c50
-rw-r--r--gtk/gtkfilechooserutils.h7
-rw-r--r--gtk/gtkfilefilter.c372
-rw-r--r--gtk/gtkfilefilter.h78
-rw-r--r--gtk/gtkfilesystemmodel.c62
-rw-r--r--gtk/gtkfilesystemmodel.h8
10 files changed, 978 insertions, 62 deletions
diff --git a/gtk/gtkfilechooser.c b/gtk/gtkfilechooser.c
index 8daedd812..d1a6651d8 100644
--- a/gtk/gtkfilechooser.c
+++ b/gtk/gtkfilechooser.c
@@ -92,6 +92,12 @@ gtk_file_chooser_base_init (gpointer g_iface)
GTK_TYPE_FILE_SYSTEM,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
g_object_interface_install_property (g_iface,
+ g_param_spec_object ("filter",
+ _("Filter"),
+ _("The current filter for selecting which files are displayed"),
+ GTK_TYPE_FILE_FILTER,
+ G_PARAM_READWRITE));
+ g_object_interface_install_property (g_iface,
g_param_spec_boolean ("folder-mode",
_("Folder Mode"),
_("Whether to select folders rather than files"),
@@ -932,6 +938,13 @@ gtk_file_chooser_get_preview_widget (GtkFileChooser *chooser)
g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
g_object_get (chooser, "preview-widget", &preview_widget, NULL);
+
+ /* Horrid hack; g_object_get() refs returned objects but
+ * that contradicts the memory management conventions
+ * for accessors.
+ */
+ if (preview_widget)
+ g_object_unref (preview_widget);
return preview_widget;
}
@@ -1046,3 +1059,107 @@ gtk_file_chooser_get_preview_uri (GtkFileChooser *chooser)
return result;
}
+
+/**
+ * gtk_file_chooser_add_filter:
+ * @chooser: a #GtkFileChooser
+ * @filter: a #GtkFileFilter
+ *
+ * Adds @filter to the list of filters that the user can select between.
+ * When a filter is selected, only files that are passed by that
+ * filter are displayed.
+ **/
+void
+gtk_file_chooser_add_filter (GtkFileChooser *chooser,
+ GtkFileFilter *filter)
+{
+ g_return_if_fail (GTK_IS_FILE_CHOOSER (chooser));
+
+ GTK_FILE_CHOOSER_GET_IFACE (chooser)->add_filter (chooser, filter);
+}
+
+/**
+ * gtk_file_chooser_add_filter:
+ * @chooser: a #GtkFileChooser
+ * @filter: a #GtkFileFilter
+ *
+ * Removes @filter from the list of filters that the user can select between.
+ **/
+void
+gtk_file_chooser_remove_filter (GtkFileChooser *chooser,
+ GtkFileFilter *filter)
+{
+ g_return_if_fail (GTK_IS_FILE_CHOOSER (chooser));
+
+ GTK_FILE_CHOOSER_GET_IFACE (chooser)->remove_filter (chooser, filter);
+}
+
+/**
+ * gtk_file_chooser_list_filters:
+ * @choooser: a #GtkFileChooser
+ *
+ * Lists the current set of user-selectable filters; see
+ * gtk_file_chooser_add_filter(), gtk_file_chooser_remove_filter().
+ *
+ * Return value: a #GSList containing the current set of
+ * user selectable filters. The contents of the list are
+ * owned by GTK+, but you must free the list itself with
+ * g_slist_free() when you are done with it.
+ **/
+GSList *
+gtk_file_chooser_list_filters (GtkFileChooser *chooser)
+{
+ g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
+
+ return GTK_FILE_CHOOSER_GET_IFACE (chooser)->list_filters (chooser);
+}
+
+/**
+ * gtk_file_chooser_set_filter:
+ * @chooser: a #GtkFileChooser
+ * @filter: a #GtkFileFilter
+ *
+ * Sets the current filter; only the files that pass the
+ * filter will be displayed. If the user-selectable list of filters
+ * is non-empty, then the filter should be one of the filters
+ * in that list. Setting the current filter when the list of
+ * filters is empty is useful if you want to restrict the displayed
+ * set of files without letting the user change it.
+ **/
+void
+gtk_file_chooser_set_filter (GtkFileChooser *chooser,
+ GtkFileFilter *filter)
+{
+ g_return_if_fail (GTK_IS_FILE_CHOOSER (chooser));
+ g_return_if_fail (GTK_IS_FILE_FILTER (filter));
+
+ g_object_set (chooser, "filter", filter, NULL);
+}
+
+/**
+ * gtk_file_chooser_get_filter:
+ * @chooser: a #GtkFileChooser
+ *
+ * Gets the current filter; see gtk_file_chooser_set_filter().
+ *
+ * Return value: the current filter, or %NULL
+ **/
+GtkFileFilter *
+gtk_file_chooser_get_filter (GtkFileChooser *chooser)
+{
+ GtkFileFilter *filter;
+
+ g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
+
+ g_object_get (chooser, "filter", &filter, NULL);
+ /* Horrid hack; g_object_get() refs returned objects but
+ * that contradicts the memory management conventions
+ * for accessors.
+ */
+ if (filter)
+ g_object_unref (filter);
+
+ return filter;
+}
+
+
diff --git a/gtk/gtkfilechooser.h b/gtk/gtkfilechooser.h
index 145cb2c1f..1b708713d 100644
--- a/gtk/gtkfilechooser.h
+++ b/gtk/gtkfilechooser.h
@@ -21,6 +21,7 @@
#ifndef __GTK_FILE_CHOOSER_H__
#define __GTK_FILE_CHOOSER_H__
+#include "gtkfilefilter.h"
#include <gtk/gtkwidget.h>
G_BEGIN_DECLS
@@ -100,29 +101,19 @@ gboolean gtk_file_chooser_get_preview_widget_active (GtkFileChooser *chooser);
const char *gtk_file_chooser_get_preview_filename (GtkFileChooser *file_chooser);
const char *gtk_file_chooser_get_preview_uri (GtkFileChooser *file_chooser);
-
-#if 0
-/* Filters
+/* List of user selectable filters
*/
-void gtk_file_chooser_add_filter (GtkFileChooser *chooser,
- GtkFileFilter *filter);
-void gtk_file_chooser_remove_filter (GtkFileChooser *chooser,
- GtkFileFilter *filter);
-GList *gtk_file_chooser_get_filters (GtkFileChooser *chooser);
-
-
-/************************************************/
+void gtk_file_chooser_add_filter (GtkFileChooser *chooser,
+ GtkFileFilter *filter);
+void gtk_file_chooser_remove_filter (GtkFileChooser *chooser,
+ GtkFileFilter *filter);
+GSList *gtk_file_chooser_list_filters (GtkFileChooser *chooser);
-static gboolean (*GtkFileFilterFunc) (const char *uri,
- const char *filename,
- gpointer data);
-
-GtkFileFilter *gtk_file_filter_new_pattern (const char *pattern);
-GtkFileFilter *gtk_file_filter_new_mime_type (const char *mime_type);
-GtkFileFilter *gtk_file_filter_new_callback (GtkFileFilterFunction *func,
- gpointer data,
- GDestroyNotify notify);
-#endif
+/* Current filter
+ */
+void gtk_file_chooser_set_filter (GtkFileChooser *chooser,
+ GtkFileFilter *filter);
+GtkFileFilter *gtk_file_chooser_get_filter (GtkFileChooser *chooser);
G_END_DECLS
diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
index 9c5222e79..3a3c378e4 100644
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@ -25,6 +25,7 @@
#include "gtkfilechooser.h"
#include "gtkfilesystemmodel.h"
+#include <gtk/gtkalignment.h>
#include <gtk/gtkcellrendererpixbuf.h>
#include <gtk/gtkcellrenderertext.h>
#include <gtk/gtkentry.h>
@@ -32,6 +33,8 @@
#include <gtk/gtkhpaned.h>
#include <gtk/gtkicontheme.h>
#include <gtk/gtklabel.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkoptionmenu.h>
#include <gtk/gtkscrolledwindow.h>
#include <gtk/gtktreeview.h>
#include <gtk/gtktreemodelsort.h>
@@ -62,6 +65,9 @@ struct _GtkFileChooserImplDefault
GtkFileChooserAction action;
+ GtkFileFilter *current_filter;
+ GSList *filters;
+
GtkFilePath *current_folder;
guint folder_mode : 1;
@@ -70,6 +76,8 @@ struct _GtkFileChooserImplDefault
guint select_multiple : 1;
guint show_hidden : 1;
+ GtkWidget *filter_alignment;
+ GtkWidget *filter_option_menu;
GtkWidget *tree_scrollwin;
GtkWidget *tree;
GtkWidget *list_scrollwin;
@@ -94,6 +102,7 @@ static void gtk_file_chooser_impl_default_get_property (GObject
guint prop_id,
GValue *value,
GParamSpec *pspec);
+static void gtk_file_chooser_impl_default_show_all (GtkWidget *widget);
static void gtk_file_chooser_impl_default_set_current_folder (GtkFileChooser *chooser,
const GtkFilePath *path);
@@ -108,13 +117,23 @@ static void gtk_file_chooser_impl_default_select_all (GtkFileC
static void gtk_file_chooser_impl_default_unselect_all (GtkFileChooser *chooser);
static GSList * gtk_file_chooser_impl_default_get_paths (GtkFileChooser *chooser);
static GtkFileSystem *gtk_file_chooser_impl_default_get_file_system (GtkFileChooser *chooser);
-
-static void tree_selection_changed (GtkTreeSelection *tree_selection,
- GtkFileChooserImplDefault *impl);
-static void list_selection_changed (GtkTreeSelection *tree_selection,
- GtkFileChooserImplDefault *impl);
-static void entry_activate (GtkEntry *entry,
- GtkFileChooserImplDefault *impl);
+static void gtk_file_chooser_impl_default_add_filter (GtkFileChooser *chooser,
+ GtkFileFilter *filter);
+static void gtk_file_chooser_impl_default_remove_filter (GtkFileChooser *chooser,
+ GtkFileFilter *filter);
+static GSList * gtk_file_chooser_impl_default_list_filters (GtkFileChooser *chooser);
+
+static void set_current_filter (GtkFileChooserImplDefault *impl,
+ GtkFileFilter *filter);
+
+static void filter_option_menu_changed (GtkOptionMenu *option_menu,
+ GtkFileChooserImplDefault *impl);
+static void tree_selection_changed (GtkTreeSelection *tree_selection,
+ GtkFileChooserImplDefault *impl);
+static void list_selection_changed (GtkTreeSelection *tree_selection,
+ GtkFileChooserImplDefault *impl);
+static void entry_activate (GtkEntry *entry,
+ GtkFileChooserImplDefault *impl);
static void tree_name_data_func (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
@@ -180,6 +199,7 @@ static void
gtk_file_chooser_impl_default_class_init (GtkFileChooserImplDefaultClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
parent_class = g_type_class_peek_parent (class);
@@ -188,6 +208,8 @@ gtk_file_chooser_impl_default_class_init (GtkFileChooserImplDefaultClass *class)
gobject_class->set_property = gtk_file_chooser_impl_default_set_property;
gobject_class->get_property = gtk_file_chooser_impl_default_get_property;
+ widget_class->show_all = gtk_file_chooser_impl_default_show_all;
+
_gtk_file_chooser_install_properties (gobject_class);
}
@@ -203,6 +225,9 @@ gtk_file_chooser_impl_default_iface_init (GtkFileChooserIface *iface)
iface->set_current_folder = gtk_file_chooser_impl_default_set_current_folder;
iface->get_current_folder = gtk_file_chooser_impl_default_get_current_folder;
iface->set_current_name = gtk_file_chooser_impl_default_set_current_name;
+ iface->add_filter = gtk_file_chooser_impl_default_add_filter;
+ iface->remove_filter = gtk_file_chooser_impl_default_remove_filter;
+ iface->list_filters = gtk_file_chooser_impl_default_list_filters;
}
static void
@@ -274,6 +299,30 @@ gtk_file_chooser_impl_default_constructor (GType type,
gtk_widget_push_composite_child ();
+ impl->filter_alignment = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (impl->filter_alignment), 0, 6, 0, 0);
+ gtk_box_pack_start (GTK_BOX (impl), impl->filter_alignment, FALSE, FALSE, 0);
+ /* Don't show filter initially */
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_container_add (GTK_CONTAINER (impl->filter_alignment), hbox);
+ gtk_widget_show (hbox);
+
+ label = gtk_label_new_with_mnemonic ("Files of _type:");
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ impl->filter_option_menu = gtk_option_menu_new ();
+ gtk_option_menu_set_menu (GTK_OPTION_MENU (impl->filter_option_menu),
+ gtk_menu_new ());
+ gtk_box_pack_start (GTK_BOX (hbox), impl->filter_option_menu, FALSE, FALSE, 0);
+ gtk_widget_show (impl->filter_option_menu);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), impl->filter_option_menu);
+
+ g_signal_connect (impl->filter_option_menu, "changed",
+ G_CALLBACK (filter_option_menu_changed), impl);
+
hpaned = gtk_hpaned_new ();
gtk_box_pack_start (GTK_BOX (impl), hpaned, TRUE, TRUE, 0);
gtk_widget_show (hpaned);
@@ -415,6 +464,9 @@ gtk_file_chooser_impl_default_set_property (GObject *object,
}
}
break;
+ case GTK_FILE_CHOOSER_PROP_FILTER:
+ set_current_filter (impl, g_value_get_object (value));
+ break;
case GTK_FILE_CHOOSER_PROP_FOLDER_MODE:
{
gboolean folder_mode = g_value_get_boolean (value);
@@ -481,6 +533,9 @@ gtk_file_chooser_impl_default_get_property (GObject *object,
case GTK_FILE_CHOOSER_PROP_ACTION:
g_value_set_enum (value, impl->action);
break;
+ case GTK_FILE_CHOOSER_PROP_FILTER:
+ g_value_set_object (value, impl->current_filter);
+ break;
case GTK_FILE_CHOOSER_PROP_FOLDER_MODE:
g_value_set_boolean (value, impl->folder_mode);
break;
@@ -505,6 +560,16 @@ gtk_file_chooser_impl_default_get_property (GObject *object,
}
}
+/* We override show-all since we have internal widgets that
+ * shouldn't be shown when you call show_all(), like the filter
+ * option menu.
+ */
+static void
+gtk_file_chooser_impl_default_show_all (GtkWidget *widget)
+{
+ gtk_widget_show (widget);
+}
+
static void
expand_and_select_func (GtkFileSystemModel *model,
GtkTreePath *path,
@@ -587,7 +652,7 @@ gtk_file_chooser_impl_default_select_path (GtkFileChooser *chooser,
_gtk_file_chooser_set_current_folder_path (chooser, parent_path);
gtk_file_path_free (parent_path);
_gtk_file_system_model_path_do (impl->list_model, path,
- select_func, impl);
+ select_func, impl);
}
}
@@ -691,6 +756,209 @@ gtk_file_chooser_impl_default_get_file_system (GtkFileChooser *chooser)
return impl->file_system;
}
+static GtkWidget *
+find_filter_menu_item (GtkFileChooserImplDefault *impl,
+ GtkFileFilter *filter,
+ gint *index_return)
+{
+ GtkWidget *menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (impl->filter_option_menu));
+ GList *children = gtk_container_get_children (GTK_CONTAINER (menu));
+ GList *tmp_list;
+ int index = 0;
+
+ if (index_return)
+ *index_return = -1;
+
+ for (tmp_list = children; tmp_list; tmp_list = tmp_list->next)
+ {
+ if (g_object_get_data (tmp_list->data, "gtk-file-filter") == filter)
+ {
+ if (index_return)
+ *index_return = index;
+ return tmp_list->data;
+ }
+ index++;
+ }
+
+ g_list_free (children);
+
+ return NULL;
+}
+
+static void
+gtk_file_chooser_impl_default_add_filter (GtkFileChooser *chooser,
+ GtkFileFilter *filter)
+{
+ GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
+ GtkWidget *menu;
+ GtkWidget *menu_item;
+ const gchar *name;
+
+ if (g_slist_find (impl->filters, filter))
+ {
+ g_warning ("gtk_file_chooser_add_filter() called on filter already in list\n");
+ return;
+ }
+
+ g_object_ref (filter);
+ gtk_object_sink (GTK_OBJECT (filter));
+ impl->filters = g_slist_append (impl->filters, filter);
+
+ name = gtk_file_filter_get_name (filter);
+ if (!name)
+ name = "Untitled filter"; /* Place-holder, doesn't need to be marked for translation */
+
+ menu_item = gtk_menu_item_new_with_label (name);
+ g_object_set_data (G_OBJECT (menu_item), "gtk-file-filter", filter);
+ gtk_widget_show (menu_item);
+
+ menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (impl->filter_option_menu));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+ /* Option menus don't react to menu size changes properly */
+ gtk_widget_size_request (menu, NULL);
+
+ if (!g_slist_find (impl->filters, impl->current_filter))
+ set_current_filter (impl, filter);
+
+ gtk_widget_show (impl->filter_alignment);
+}
+
+static void
+gtk_file_chooser_impl_default_remove_filter (GtkFileChooser *chooser,
+ GtkFileFilter *filter)
+{
+ GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
+ GtkWidget *menu;
+ GtkWidget *menu_item;
+
+ if (!g_slist_find (impl->filters, filter))
+ {
+ g_warning ("gtk_file_chooser_remove_filter() called on filter not in list\n");
+ return;
+ }
+
+ impl->filters = g_slist_remove (impl->filters, filter);
+
+ if (filter == impl->current_filter)
+ {
+ if (impl->filters)
+ set_current_filter (impl, impl->filters->data);
+ else
+ set_current_filter (impl, NULL);
+ }
+
+ menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (impl->filter_option_menu));
+ menu_item = find_filter_menu_item (impl, filter, NULL);
+ g_assert (menu_item);
+ gtk_widget_destroy (menu_item);
+ /* Option menus don't react to menu size changes properly */
+ gtk_widget_size_request (menu, NULL);
+
+ g_object_unref (filter);
+
+ if (!impl->filters)
+ gtk_widget_hide (impl->filter_alignment);
+}
+
+static GSList *
+gtk_file_chooser_impl_default_list_filters (GtkFileChooser *chooser)
+{
+ GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
+
+ return g_slist_copy (impl->filters);
+}
+
+static gboolean
+list_model_filter_func (GtkFileSystemModel *model,
+ GtkFilePath *path,
+ const GtkFileInfo *file_info,
+ gpointer user_data)
+{
+ GtkFileChooserImplDefault *impl = user_data;
+ GtkFileFilterInfo filter_info;
+ GtkFileFilterFlags needed;
+ gboolean result;
+
+ if (!impl->current_filter)
+ return TRUE;
+
+ filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
+
+ needed = gtk_file_filter_get_needed (impl->current_filter);
+
+ filter_info.display_name = gtk_file_info_get_display_name (file_info);
+ filter_info.mime_type = gtk_file_info_get_mime_type (file_info);
+
+ if (needed & GTK_FILE_FILTER_FILENAME)
+ {
+ filter_info.filename = gtk_file_system_path_to_filename (impl->file_system, path);
+ if (filter_info.filename)
+ filter_info.contains |= GTK_FILE_FILTER_FILENAME;
+ }
+ else
+ filter_info.filename = NULL;
+
+ if (needed & GTK_FILE_FILTER_URI)
+ {
+ filter_info.uri = gtk_file_system_path_to_uri (impl->file_system, path);
+ if (filter_info.filename)
+ filter_info.contains |= GTK_FILE_FILTER_URI;
+ }
+ else
+ filter_info.uri = NULL;
+
+ result = gtk_file_filter_filter (impl->current_filter, &filter_info);
+
+ if (filter_info.filename)
+ g_free ((gchar *)filter_info.filename);
+ if (filter_info.uri)
+ g_free ((gchar *)filter_info.uri);
+
+ return result;
+}
+
+static void
+install_list_model_filter (GtkFileChooserImplDefault *impl)
+{
+ if (impl->current_filter)
+ _gtk_file_system_model_set_filter (impl->list_model,
+ list_model_filter_func,
+ impl);
+}
+
+static void
+set_current_filter (GtkFileChooserImplDefault *impl,
+ GtkFileFilter *filter)
+{
+ if (impl->current_filter != filter)
+ {
+ int menu_item_index;
+
+ /* If we have filters, new filter must be one of them
+ */
+ find_filter_menu_item (impl, filter, &menu_item_index);
+ if (impl->filters && menu_item_index < 0)
+ return;
+
+ if (impl->current_filter)
+ g_object_unref (impl->current_filter);
+ impl->current_filter = filter;
+ if (impl->current_filter)
+ {
+ g_object_ref (impl->current_filter);
+ gtk_object_sink (GTK_OBJECT (filter));
+ }
+
+ if (impl->filters)
+ gtk_option_menu_set_history (GTK_OPTION_MENU (impl->filter_option_menu),
+ menu_item_index);
+
+ install_list_model_filter (impl);
+
+ g_object_notify (G_OBJECT (impl), "filter");
+ }
+}
+
static gint
name_sort_func (GtkTreeModel *model,
GtkTreeIter *a,
@@ -798,6 +1066,16 @@ update_chooser_entry (GtkFileChooserImplDefault *impl)
}
static void
+filter_option_menu_changed (GtkOptionMenu *option_menu,
+ GtkFileChooserImplDefault *impl)
+{
+ gint new_index = gtk_option_menu_get_history (GTK_OPTION_MENU (option_menu));
+ GtkFileFilter *new_filter = g_slist_nth_data (impl->filters, new_index);
+
+ set_current_filter (impl, new_filter);
+}
+
+static void
tree_selection_changed (GtkTreeSelection *selection,
GtkFileChooserImplDefault *impl)
{
@@ -843,6 +1121,7 @@ tree_selection_changed (GtkTreeSelection *selection,
GTK_FILE_INFO_DISPLAY_NAME |
GTK_FILE_INFO_SIZE);
_gtk_file_system_model_set_show_folders (impl->list_model, FALSE);
+ install_list_model_filter (impl);
impl->sort_model = (GtkTreeModelSort *)gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (impl->list_model));
gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), 0, name_sort_func, impl, NULL);
diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h
index d3b73f1ec..6511b6903 100644
--- a/gtk/gtkfilechooserprivate.h
+++ b/gtk/gtkfilechooserprivate.h
@@ -34,18 +34,6 @@ struct _GtkFileChooserIface
{
GTypeInterface base_iface;
- /* GtkFileChooser interface has the following properties:
- *
- * action: GtkFileChooserAction
- * folder_mode: boolean
- * select_multiple: boolean
- * show_hidden: boolean
- * local_only: boolean
- *
- * preview_widget: GtkWidget
- * preview_widget_active: boolean
- */
-
/* Methods
*/
void (*set_current_folder) (GtkFileChooser *chooser,
@@ -61,6 +49,12 @@ struct _GtkFileChooserIface
void (*unselect_all) (GtkFileChooser *chooser);
GSList * (*get_paths) (GtkFileChooser *chooser);
GtkFileSystem *(*get_file_system) (GtkFileChooser *chooser);
+ void (*add_filter) (GtkFileChooser *chooser,
+ GtkFileFilter *filter);
+ void (*remove_filter) (GtkFileChooser *chooser,
+ GtkFileFilter *filter);
+ GSList * (*list_filters) (GtkFileChooser *chooser);
+
/* Signals
*/
diff --git a/gtk/gtkfilechooserutils.c b/gtk/gtkfilechooserutils.c
index 9c0e51ced..b6648f21c 100644
--- a/gtk/gtkfilechooserutils.c
+++ b/gtk/gtkfilechooserutils.c
@@ -37,6 +37,14 @@ static void delegate_select_all (GtkFileChooser *choose
static void delegate_unselect_all (GtkFileChooser *chooser);
static GSList * delegate_get_paths (GtkFileChooser *chooser);
static GtkFileSystem *delegate_get_file_system (GtkFileChooser *chooser);
+static void delegate_add_filter (GtkFileChooser *chooser,
+ GtkFileFilter *filter);
+static void delegate_remove_filter (GtkFileChooser *chooser,
+ GtkFileFilter *filter);
+static GSList * delegate_list_filters (GtkFileChooser *chooser);
+static void delegate_notify (GObject *object,
+ GParamSpec *pspec,
+ gpointer data);
static void delegate_current_folder_changed (GtkFileChooser *chooser,
gpointer data);
static void delegate_selection_changed (GtkFileChooser *chooser,
@@ -67,6 +75,11 @@ _gtk_file_chooser_install_properties (GObjectClass *klass)
GTK_TYPE_FILE_SYSTEM,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (klass,
+ GTK_FILE_CHOOSER_PROP_FILTER,
+ g_param_spec_override ("filter",
+ GTK_TYPE_FILE_FILTER,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (klass,
GTK_FILE_CHOOSER_PROP_FOLDER_MODE,
g_param_spec_override ("folder-mode",
G_TYPE_BOOLEAN,
@@ -121,6 +134,9 @@ _gtk_file_chooser_delegate_iface_init (GtkFileChooserIface *iface)
iface->unselect_all = delegate_unselect_all;
iface->get_paths = delegate_get_paths;
iface->get_file_system = delegate_get_file_system;
+ iface->add_filter = delegate_add_filter;
+ iface->remove_filter = delegate_remove_filter;
+ iface->list_filters = delegate_list_filters;
}
/**
@@ -143,6 +159,8 @@ _gtk_file_chooser_set_delegate (GtkFileChooser *receiver,
g_object_set_data (G_OBJECT (receiver), "gtk-file-chooser-delegate", delegate);
+ g_signal_connect (delegate, "notify",
+ G_CALLBACK (delegate_notify), receiver);
g_signal_connect (delegate, "current-folder-changed",
G_CALLBACK (delegate_current_folder_changed), receiver);
g_signal_connect (delegate, "selection-changed",
@@ -194,6 +212,26 @@ delegate_get_file_system (GtkFileChooser *chooser)
}
static void
+delegate_add_filter (GtkFileChooser *chooser,
+ GtkFileFilter *filter)
+{
+ gtk_file_chooser_add_filter (get_delegate (chooser), filter);
+}
+
+static void
+delegate_remove_filter (GtkFileChooser *chooser,
+ GtkFileFilter *filter)
+{
+ gtk_file_chooser_remove_filter (get_delegate (chooser), filter);
+}
+
+static GSList *
+delegate_list_filters (GtkFileChooser *chooser)
+{
+ return gtk_file_chooser_list_filters (get_delegate (chooser));
+}
+
+static void
delegate_set_current_folder (GtkFileChooser *chooser,
const GtkFilePath *path)
{
@@ -214,6 +252,18 @@ delegate_set_current_name (GtkFileChooser *chooser,
}
static void
+delegate_notify (GObject *object,
+ GParamSpec *pspec,
+ gpointer data)
+{
+ if (pspec->param_id >= GTK_FILE_CHOOSER_PROP_FIRST &&
+ pspec->param_id <= GTK_FILE_CHOOSER_PROP_LAST)
+ {
+ g_object_notify (data, pspec->name);
+ }
+}
+
+static void
delegate_selection_changed (GtkFileChooser *chooser,
gpointer data)
{
diff --git a/gtk/gtkfilechooserutils.h b/gtk/gtkfilechooserutils.h
index 56e47d55d..874e56da3 100644
--- a/gtk/gtkfilechooserutils.h
+++ b/gtk/gtkfilechooserutils.h
@@ -27,14 +27,17 @@
G_BEGIN_DECLS
typedef enum {
- GTK_FILE_CHOOSER_PROP_ACTION = 0x1000,
+ GTK_FILE_CHOOSER_PROP_FIRST = 0x1000,
+ GTK_FILE_CHOOSER_PROP_ACTION = GTK_FILE_CHOOSER_PROP_FIRST,
GTK_FILE_CHOOSER_PROP_FILE_SYSTEM,
+ GTK_FILE_CHOOSER_PROP_FILTER,
GTK_FILE_CHOOSER_PROP_FOLDER_MODE,
GTK_FILE_CHOOSER_PROP_LOCAL_ONLY,
GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET,
GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE,
GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE,
- GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN
+ GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN,
+ GTK_FILE_CHOOSER_PROP_LAST = GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN,
} GtkFileChooserProp;
void _gtk_file_chooser_install_properties (GObjectClass *klass);
diff --git a/gtk/gtkfilefilter.c b/gtk/gtkfilefilter.c
new file mode 100644
index 000000000..b57bf2557
--- /dev/null
+++ b/gtk/gtkfilefilter.c
@@ -0,0 +1,372 @@
+/* GTK - The GIMP Toolkit
+ * gtkfilefilter.c: Filters for selecting a file subset
+ * Copyright (C) 2003, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkfilefilter.h"
+
+#include <gtk/gtkobject.h>
+
+#include <string.h>
+
+typedef struct _GtkFileFilterClass GtkFileFilterClass;
+typedef struct _FilterRule FilterRule;
+
+#define GTK_FILE_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_FILTER, GtkFileFilterClass))
+#define GTK_IS_FILE_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_FILTER))
+#define GTK_FILE_FILTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_FILTER, GtkFileFilterClass))
+
+typedef enum {
+ FILTER_RULE_PATTERN,
+ FILTER_RULE_MIME_TYPE,
+ FILTER_RULE_CUSTOM,
+} FilterRuleType;
+
+struct _GtkFileFilterClass
+{
+ GtkObjectClass parent_class;
+};
+
+struct _GtkFileFilter
+{
+ GtkObject parent_instance;
+
+ gchar *name;
+ GSList *rules;
+
+ GtkFileFilterFlags needed;
+};
+
+struct _FilterRule
+{
+ FilterRuleType type;
+ GtkFileFilterFlags needed;
+
+ union {
+ gchar *pattern;
+ gchar *mime_type;
+ struct {
+ GtkFileFilterFunc func;
+ gpointer data;
+ GDestroyNotify notify;
+ } custom;
+ } u;
+};
+
+static void gtk_file_filter_class_init (GtkFileFilterClass *class);
+static void gtk_file_filter_finalize (GObject *object);
+
+static GObjectClass *parent_class;
+
+GType
+gtk_file_filter_get_type (void)
+{
+ static GType file_filter_type = 0;
+
+ if (!file_filter_type)
+ {
+ static const GTypeInfo file_filter_info =
+ {
+ sizeof (GtkFileFilterClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) gtk_file_filter_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GtkFileFilter),
+ 0, /* n_preallocs */
+ NULL /* init */
+ };
+
+ file_filter_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkFileFilter",
+ &file_filter_info, 0);
+ }
+
+ return file_filter_type;
+}
+
+static void
+gtk_file_filter_class_init (GtkFileFilterClass *class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+ parent_class = g_type_class_peek_parent (class);
+
+ gobject_class->finalize = gtk_file_filter_finalize;
+}
+
+static void
+filter_rule_free (FilterRule *rule)
+{
+ switch (rule->type)
+ {
+ case FILTER_RULE_MIME_TYPE:
+ g_free (rule->u.mime_type);
+ break;
+ case FILTER_RULE_PATTERN:
+ g_free (rule->u.pattern);
+ break;
+ case FILTER_RULE_CUSTOM:
+ if (rule->u.custom.notify)
+ rule->u.custom.notify (rule->u.custom.data);
+ break;
+ }
+
+ g_free (rule);
+}
+
+static void
+gtk_file_filter_finalize (GObject *object)
+{
+ GtkFileFilter *filter = GTK_FILE_FILTER (filter);
+
+ g_slist_foreach (filter->rules, (GFunc)filter_rule_free, NULL);
+
+ parent_class->finalize (object);
+}
+
+/**
+ * gtk_file_filter_new:
+ *
+ * Creates a new #GtkFileFilter with no rules added to it.
+ * Such a filter doesn't accept any files, so is not
+ * particularly useful until you add rules with
+ * gtk_file_filter_add_mime_type(), gtk_file_filter_add_pattern(),
+ * or gtk_file_filter_add_custom(). To create a filter
+ * that accepts any file, use:
+ *
+ * <informalexample><programlisting>
+ * GtkFileFilter *filter = gtk_file_filter_new ();
+ * gtk_file_filter_add_pattern (filter, "*");
+ * </programlisting></programlisting>
+ *
+ * Return value: a new #GtkFileFilter
+ **/
+GtkFileFilter *
+gtk_file_filter_new (void)
+{
+ return g_object_new (GTK_TYPE_FILE_FILTER, NULL);
+}
+
+/**
+ * gtk_file_filter_set_name:
+ * @filter: a #GtkFileFilter
+ * @name: the human-readable-name for the filter, or %NULL
+ * to remove any existing name.
+ *
+ * Sets the human-readable name of the filter; this is the string
+ * that will be displayed in the file selector user interface if
+ * there is a selectable list of filters.
+ **/
+void
+gtk_file_filter_set_name (GtkFileFilter *filter,
+ const gchar *name)
+{
+ g_return_if_fail (GTK_IS_FILE_FILTER (filter));
+
+ if (filter->name)
+ g_free (filter->name);
+
+ filter->name = g_strdup (name);
+}
+
+/**
+ * gtk_file_filter_get_name:
+ * @filter: a #GtkFileFilter
+ *
+ * Gets the human-readable name for the filter. See gtk_file_filter_set_name().
+ *
+ * Return value: The human-readable name of the filter,
+ * or %NULL. This value is owned by GTK+ and must not
+ * be modified or freed.
+ **/
+G_CONST_RETURN gchar *
+gtk_file_filter_get_name (GtkFileFilter *filter)
+{
+ g_return_val_if_fail (GTK_IS_FILE_FILTER (filter), NULL);
+
+ return filter->name;
+}
+
+static void
+file_filter_add_rule (GtkFileFilter *filter,
+ FilterRule *rule)
+{
+ filter->needed |= rule->needed;
+ filter->rules = g_slist_append (filter->rules, rule);
+}
+
+/**
+ * gtk_file_filter_add_mime_type:
+ * @filter: A #GtkFileFilter
+ * @mime_type: name of a MIME type
+ *
+ * Adds a rule allowing a given mime type to @filter.
+ **/
+void
+gtk_file_filter_add_mime_type (GtkFileFilter *filter,
+ const gchar *mime_type)
+{
+ FilterRule *rule;
+
+ g_return_if_fail (GTK_IS_FILE_FILTER (filter));
+ g_return_if_fail (mime_type != NULL);
+
+ rule = g_new (FilterRule, 1);
+ rule->type = FILTER_RULE_MIME_TYPE;
+ rule->needed = GTK_FILE_FILTER_MIME_TYPE;
+ rule->u.mime_type = g_strdup (mime_type);
+
+ file_filter_add_rule (filter, rule);
+}
+
+/**
+ * gtk_file_filter_add_pattern:
+ * @filter: a #GtkFileFilter
+ * @pattern: a shell style glob
+ *
+ * Adds a rule allowing a shell style glob to a filter.
+ **/
+void
+gtk_file_filter_add_pattern (GtkFileFilter *filter,
+ const gchar *pattern)
+{
+ FilterRule *rule;
+
+ g_return_if_fail (GTK_IS_FILE_FILTER (filter));
+ g_return_if_fail (pattern != NULL);
+
+ rule = g_new (FilterRule, 1);
+ rule->type = FILTER_RULE_PATTERN;
+ rule->needed = GTK_FILE_FILTER_DISPLAY_NAME;
+ rule->u.pattern = g_strdup (pattern);
+
+ file_filter_add_rule (filter, rule);
+}
+
+/**
+ * gtk_file_filter_add_custom:
+ * @filter: a #GtkFileFilter
+ * @needed: bitfield of flags indicating the information that the custom
+ * filter function needs.
+ * @func: callback function; if the function returns %TRUE, then
+ * the file will be displayed.
+ * @data: data to pass to @func
+ * @notify: function to call to free @data when it is no longer needed.
+ *
+ * Adds rule to a filter that allows files based on a custom callback
+ * function. The bitfield @needed which is passed in provides information
+ * about what sorts of information that the filter function needs;
+ * this allows GTK+ to avoid retrieving expensive information when
+ * it isn't needed by the filter.
+ **/
+void
+gtk_file_filter_add_custom (GtkFileFilter *filter,
+ GtkFileFilterFlags needed,
+ GtkFileFilterFunc func,
+ gpointer data,
+ GDestroyNotify notify)
+{
+ FilterRule *rule;
+
+ g_return_if_fail (GTK_IS_FILE_FILTER (filter));
+ g_return_if_fail (func != NULL);
+
+ rule = g_new (FilterRule, 1);
+ rule->type = FILTER_RULE_CUSTOM;
+ rule->needed = needed;
+ rule->u.custom.func = func;
+ rule->u.custom.data = data;
+ rule->u.custom.notify = notify;
+
+ file_filter_add_rule (filter, rule);
+}
+
+/**
+ * gtk_file_filter_get_needed:
+ * @filter: a #GtkFileFilter
+ *
+ * Gets the fields that need to be filled in for the structure
+ * passed to gtk_file_filter_filter()
+ *
+ * This function will not typically be used by applications; it
+ * is intended principally for use in the implementation of
+ * #GtkFileChooser.
+ *
+ * Return value: bitfield of flags indicating needed fields when
+ * calling gtk_file_filter_filter()
+ **/
+GtkFileFilterFlags
+gtk_file_filter_get_needed (GtkFileFilter *filter)
+{
+ return filter->needed;
+}
+
+/* Remove once we merge into GTK+ and use _gtk_fnmatch().
+ */
+gboolean _gtk_file_chooser_fnmatch (const char *pattern,
+ const char *string);
+
+/**
+ * gtk_file_filter_filter:
+ * @filter: a #GtkFileFilter
+ * @filter_info: a #GtkFileFilterInfo structure containing information
+ * about a file.
+ *
+ * Tests whether a file should be displayed according to @filter.
+ * The #GtkFileFilterInfo structure @filter_info should include
+ * the fields returned feom gtk_file_filter_get_needed().
+ *
+ * This function will not typically be used by applications; it
+ * is intended principally for use in the implementation of
+ * #GtkFileChooser.
+ *
+ * Return value: %TRUE if the file should be displayed
+ **/
+gboolean
+gtk_file_filter_filter (GtkFileFilter *filter,
+ const GtkFileFilterInfo *filter_info)
+{
+ GSList *tmp_list;
+
+ for (tmp_list = filter->rules; tmp_list; tmp_list = tmp_list->next)
+ {
+ FilterRule *rule = tmp_list->data;
+
+ if ((filter_info->contains & rule->needed) != rule->needed)
+ continue;
+
+ switch (rule->type)
+ {
+ case FILTER_RULE_MIME_TYPE:
+ if (strcmp (rule->u.mime_type, filter_info->mime_type) == 0)
+ return TRUE;
+ break;
+ case FILTER_RULE_PATTERN:
+ if (_gtk_file_chooser_fnmatch (rule->u.pattern, filter_info->display_name))
+ return TRUE;
+ break;
+ case FILTER_RULE_CUSTOM:
+ if (rule->u.custom.func (filter_info, rule->u.custom.data))
+ return TRUE;
+ break;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/gtk/gtkfilefilter.h b/gtk/gtkfilefilter.h
new file mode 100644
index 000000000..01b70b3ba
--- /dev/null
+++ b/gtk/gtkfilefilter.h
@@ -0,0 +1,78 @@
+/* GTK - The GIMP Toolkit
+ * gtkfilefilter.h: Filters for selecting a file subset
+ * Copyright (C) 2003, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_FILE_FILTER_H__
+#define __GTK_FILE_FILTER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_FILE_FILTER (gtk_file_filter_get_type ())
+#define GTK_FILE_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_FILTER, GtkFileFilter))
+#define GTK_IS_FILE_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FILTER))
+
+typedef struct _GtkFileFilter GtkFileFilter;
+typedef struct _GtkFileFilterInfo GtkFileFilterInfo;
+
+typedef enum {
+ GTK_FILE_FILTER_FILENAME = 1 << 0,
+ GTK_FILE_FILTER_URI = 1 << 1,
+ GTK_FILE_FILTER_DISPLAY_NAME = 1 << 2,
+ GTK_FILE_FILTER_MIME_TYPE = 1 << 3
+} GtkFileFilterFlags;
+
+typedef gboolean (*GtkFileFilterFunc) (const GtkFileFilterInfo *filter_info,
+ gpointer data);
+
+struct _GtkFileFilterInfo
+{
+ GtkFileFilterFlags contains;
+
+ const gchar *filename;
+ const gchar *uri;
+ const gchar *display_name;
+ const gchar *mime_type;
+};
+
+GType gtk_file_filter_get_type (void);
+
+GtkFileFilter * gtk_file_filter_new (void);
+void gtk_file_filter_set_name (GtkFileFilter *filter,
+ const gchar *name);
+G_CONST_RETURN gchar *gtk_file_filter_get_name (GtkFileFilter *filter);
+
+void gtk_file_filter_add_mime_type (GtkFileFilter *filter,
+ const gchar *mime_type);
+void gtk_file_filter_add_pattern (GtkFileFilter *filter,
+ const gchar *pattern);
+void gtk_file_filter_add_custom (GtkFileFilter *filter,
+ GtkFileFilterFlags needed,
+ GtkFileFilterFunc func,
+ gpointer data,
+ GDestroyNotify notify);
+
+GtkFileFilterFlags gtk_file_filter_get_needed (GtkFileFilter *filter);
+gboolean gtk_file_filter_filter (GtkFileFilter *filter,
+ const GtkFileFilterInfo *filter_info);
+
+G_END_DECLS
+
+#endif /* __GTK_FILE_FILTER_H__ */
diff --git a/gtk/gtkfilesystemmodel.c b/gtk/gtkfilesystemmodel.c
index ed738481b..2a28d4415 100644
--- a/gtk/gtkfilesystemmodel.c
+++ b/gtk/gtkfilesystemmodel.c
@@ -44,6 +44,9 @@ struct _GtkFileSystemModel
FileModelNode *roots;
GtkFileFolder *root_folder;
+ GtkFileSystemModelFilter filter_func;
+ gpointer filter_data;
+
GSList *idle_clears;
GSource *idle_clear_source;
@@ -561,7 +564,8 @@ _gtk_file_system_model_new (GtkFileSystem *file_system,
GtkFileInfoType types)
{
GtkFileSystemModel *model;
- GSList *roots, *tmp_list;
+ GSList *roots = NULL;
+ GSList *tmp_list;
g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
@@ -686,6 +690,16 @@ model_refilter_recurse (GtkFileSystemModel *model,
}
}
+static void
+model_refilter_all (GtkFileSystemModel *model)
+{
+ GtkTreePath *path;
+
+ path = gtk_tree_path_new ();
+ model_refilter_recurse (model, NULL, path);
+ gtk_tree_path_free (path);
+}
+
/**
* _gtk_file_system_model_set_show_hidden:
* @model: a #GtkFileSystemModel
@@ -702,13 +716,8 @@ _gtk_file_system_model_set_show_hidden (GtkFileSystemModel *model,
if (show_hidden != model->show_hidden)
{
- GtkTreePath *path;
-
model->show_hidden = show_hidden;
-
- path = gtk_tree_path_new ();
- model_refilter_recurse (model, NULL, path);
- gtk_tree_path_free (path);
+ model_refilter_all (model);
}
}
@@ -728,13 +737,8 @@ _gtk_file_system_model_set_show_folders (GtkFileSystemModel *model,
if (show_folders != model->show_folders)
{
- GtkTreePath *path;
-
model->show_folders = show_folders;
-
- path = gtk_tree_path_new ();
- model_refilter_recurse (model, NULL, path);
- gtk_tree_path_free (path);
+ model_refilter_all (model);
}
}
@@ -755,13 +759,8 @@ _gtk_file_system_model_set_show_files (GtkFileSystemModel *model,
if (show_files != model->show_files)
{
- GtkTreePath *path;
-
model->show_files = show_files;
-
- path = gtk_tree_path_new ();
- model_refilter_recurse (model, NULL, path);
- gtk_tree_path_free (path);
+ model_refilter_all (model);
}
}
@@ -898,6 +897,29 @@ find_and_ref_path (GtkFileSystemModel *model,
}
/**
+ * _gtk_file_system_model_set_filter:
+ * @mode: a #GtkFileSystemModel
+ * @filter: function to be called for each file
+ * @user_data: data to pass to @filter
+ *
+ * Sets a callback called for each file/directory to see whether
+ * it should be included in model. If this function was made
+ * public, we'd want to include a GDestroyNotify as well.
+ **/
+void
+_gtk_file_system_model_set_filter (GtkFileSystemModel *model,
+ GtkFileSystemModelFilter filter,
+ gpointer user_data)
+{
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+
+ model->filter_func = filter;
+ model->filter_data = user_data;
+
+ model_refilter_all (model);
+}
+
+/**
* _gtk_file_system_model_path_do:
* @model: a #GtkFileSystemModel
* @path: a path pointing to a file in the filesystem
@@ -1024,6 +1046,8 @@ file_model_node_is_visible (GtkFileSystemModel *model,
return FALSE;
if (!model->show_hidden && gtk_file_info_get_is_hidden (info))
return FALSE;
+ if (model->filter_func && !model->filter_func (model, node->path, info, model->filter_data))
+ return FALSE;
return TRUE;
}
diff --git a/gtk/gtkfilesystemmodel.h b/gtk/gtkfilesystemmodel.h
index e84d004de..759c1ab3c 100644
--- a/gtk/gtkfilesystemmodel.h
+++ b/gtk/gtkfilesystemmodel.h
@@ -56,6 +56,14 @@ void _gtk_file_system_model_set_show_folders (GtkFileSystemModel
void _gtk_file_system_model_set_show_files (GtkFileSystemModel *model,
gboolean show_files);
+typedef gboolean (*GtkFileSystemModelFilter) (GtkFileSystemModel *model,
+ GtkFilePath *path,
+ const GtkFileInfo *info,
+ gpointer user_data);
+
+void _gtk_file_system_model_set_filter (GtkFileSystemModel *model,
+ GtkFileSystemModelFilter filter,
+ gpointer user_data);
typedef void (*GtkFileSystemModelPathFunc) (GtkFileSystemModel *model,
GtkTreePath *path,