medit/moo/mooutils/moofiltermgr.c

1124 lines
31 KiB
C
Raw Normal View History

2005-09-06 09:21:05 -07:00
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*-
2005-08-25 02:29:01 -07:00
* moofiltermgr.c
*
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
2005-08-25 02:29:01 -07:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* See COPYING file that comes with this distribution.
*/
#include "mooutils/moofiltermgr.h"
2005-09-04 23:30:18 -07:00
#include "mooutils/mooprefs.h"
2005-08-25 02:29:01 -07:00
#include <string.h>
#include <gtk/gtk.h>
2005-08-25 02:29:01 -07:00
#define NUM_USER_FILTERS 5
#define ALL_FILES_GLOB "*"
2005-08-25 02:29:01 -07:00
typedef struct {
GtkFileFilter *filter;
GtkFileFilter *aux;
char *description;
char *glob;
gboolean user;
} Filter;
static Filter *filter_new (const char *description,
const char *glob,
gboolean user);
static void filter_free (Filter *filter);
2005-08-25 02:29:01 -07:00
static const char *filter_get_glob (Filter *filter);
static const char *filter_get_description (Filter *filter);
static GtkFileFilter *filter_get_gtk_filter (Filter *filter);
2005-08-25 02:29:01 -07:00
typedef struct {
GtkListStore *filters;
Filter *last_filter;
guint num_user;
guint num_builtin;
gboolean has_separator;
guint max_num_user;
} FilterStore;
2005-09-04 23:30:18 -07:00
static FilterStore *filter_store_new (MooFilterMgr *mgr);
static void filter_store_free (FilterStore *store);
2005-09-04 23:30:18 -07:00
static void filter_store_add_builtin (FilterStore *store,
Filter *filter,
int position);
static void filter_store_add_user (FilterStore *store,
Filter *filter);
static Filter *filter_store_get_last (FilterStore *store);
static GSList *filter_store_list_user_filters (FilterStore *store);
2005-08-25 02:29:01 -07:00
struct _MooFilterMgrPrivate {
FilterStore *default_store;
GHashTable *named_stores; /* user_id -> FilterStore* */
GHashTable *filters; /* glob -> Filter* */
2005-09-04 23:30:18 -07:00
gboolean loaded;
guint save_idle_id;
2005-08-25 02:29:01 -07:00
};
enum {
COLUMN_DESCRIPTION,
COLUMN_FILTER,
NUM_COLUMNS
};
static void moo_filter_mgr_class_init (MooFilterMgrClass *klass);
static void moo_filter_mgr_init (MooFilterMgr *mgr);
static void moo_filter_mgr_finalize (GObject *object);
static gboolean combo_row_separator_func (GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data);
static FilterStore *mgr_get_store (MooFilterMgr *mgr,
const char *user_id,
gboolean create);
static Filter *mgr_get_null_filter (MooFilterMgr *mgr);
static Filter *mgr_new_filter (MooFilterMgr *mgr,
const char *description,
const char *glob,
gboolean user);
static Filter *mgr_get_last_filter (MooFilterMgr *mgr,
const char *user_id);
static void mgr_set_last_filter (MooFilterMgr *mgr,
const char *user_id,
Filter *filter);
static Filter *mgr_new_user_filter (MooFilterMgr *mgr,
const char *glob,
const char *user_id);
2005-09-04 23:30:18 -07:00
static GSList *mgr_list_user_ids (MooFilterMgr *mgr);
static void mgr_load (MooFilterMgr *mgr);
static void mgr_save (MooFilterMgr *mgr);
2005-08-25 02:29:01 -07:00
/* MOO_TYPE_FILTER_MGR */
G_DEFINE_TYPE (MooFilterMgr, moo_filter_mgr, G_TYPE_OBJECT)
static void
moo_filter_mgr_class_init (MooFilterMgrClass *klass)
2005-08-25 02:29:01 -07:00
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = moo_filter_mgr_finalize;
}
static void
moo_filter_mgr_init (MooFilterMgr *mgr)
2005-08-25 02:29:01 -07:00
{
mgr->priv = g_new0 (MooFilterMgrPrivate, 1);
mgr->priv->filters =
g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) filter_free);
g_hash_table_insert (mgr->priv->filters,
g_strdup (ALL_FILES_GLOB),
filter_new ("All Files", ALL_FILES_GLOB, FALSE));
mgr->priv->default_store = NULL;
mgr->priv->named_stores =
g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) filter_store_free);
2005-08-25 02:29:01 -07:00
}
static void
moo_filter_mgr_finalize (GObject *object)
2005-08-25 02:29:01 -07:00
{
MooFilterMgr *mgr = MOO_FILTER_MGR (object);
2005-09-04 23:30:18 -07:00
if (mgr->priv->save_idle_id)
g_source_remove (mgr->priv->save_idle_id);
filter_store_free (mgr->priv->default_store);
g_hash_table_destroy (mgr->priv->named_stores);
g_hash_table_destroy (mgr->priv->filters);
2005-08-25 02:29:01 -07:00
g_free (mgr->priv);
2005-08-25 02:29:01 -07:00
G_OBJECT_CLASS (moo_filter_mgr_parent_class)->finalize (object);
}
MooFilterMgr*
moo_filter_mgr_new (void)
2005-08-25 02:29:01 -07:00
{
return g_object_new (MOO_TYPE_FILTER_MGR, NULL);
2005-08-25 02:29:01 -07:00
}
void
moo_filter_mgr_init_filter_combo (MooFilterMgr *mgr,
MooCombo *combo,
const char *user_id)
2005-08-25 02:29:01 -07:00
{
FilterStore *store;
2005-08-25 02:29:01 -07:00
g_return_if_fail (MOO_IS_FILTER_MGR (mgr));
g_return_if_fail (MOO_IS_COMBO (combo));
2005-08-25 02:29:01 -07:00
2005-09-04 23:30:18 -07:00
mgr_load (mgr);
store = mgr_get_store (mgr, user_id, TRUE);
g_return_if_fail (store != NULL);
moo_combo_set_model (combo, GTK_TREE_MODEL (store->filters));
moo_combo_set_row_separator_func (combo, combo_row_separator_func, NULL);
2005-08-25 02:29:01 -07:00
moo_combo_set_text_column (combo, COLUMN_DESCRIPTION);
2005-08-25 02:29:01 -07:00
}
static gboolean
combo_row_separator_func (GtkTreeModel *model,
GtkTreeIter *iter,
G_GNUC_UNUSED gpointer data)
2005-08-25 02:29:01 -07:00
{
Filter *filter = NULL;
gtk_tree_model_get (model, iter, COLUMN_FILTER, &filter, -1);
return !filter;
}
static FilterStore*
mgr_get_store (MooFilterMgr *mgr,
const char *user_id,
gboolean create)
{
FilterStore *store;
if (!user_id)
2005-08-25 02:29:01 -07:00
{
if (!mgr->priv->default_store && create)
mgr->priv->default_store = filter_store_new (mgr);
return mgr->priv->default_store;
2005-08-25 02:29:01 -07:00
}
store = g_hash_table_lookup (mgr->priv->named_stores, user_id);
if (!store && create)
{
g_return_val_if_fail (g_utf8_validate (user_id, -1, NULL), NULL);
store = filter_store_new (mgr);
g_hash_table_insert (mgr->priv->named_stores,
g_strdup (user_id),
store);
}
return store;
2005-08-25 02:29:01 -07:00
}
2005-09-04 23:30:18 -07:00
static void
prepend_id (const char *user_id,
G_GNUC_UNUSED gpointer store,
GSList **list)
{
*list = g_slist_prepend (*list, g_strdup (user_id));
}
static GSList*
mgr_list_user_ids (MooFilterMgr *mgr)
{
GSList *list = NULL;
g_hash_table_foreach (mgr->priv->named_stores, (GHFunc) prepend_id, &list);
return g_slist_reverse (list);
}
GtkFileFilter*
moo_filter_mgr_get_filter (MooFilterMgr *mgr,
GtkTreeIter *iter,
const char *user_id)
2005-08-25 02:29:01 -07:00
{
FilterStore *store;
Filter *filter = NULL;
2005-08-25 02:29:01 -07:00
g_return_val_if_fail (MOO_IS_FILTER_MGR (mgr), NULL);
g_return_val_if_fail (iter != NULL, NULL);
2005-09-04 23:30:18 -07:00
mgr_load (mgr);
store = mgr_get_store (mgr, user_id, FALSE);
g_return_val_if_fail (store != NULL, NULL);
2005-09-04 23:30:18 -07:00
gtk_tree_model_get (GTK_TREE_MODEL (store->filters), iter,
COLUMN_FILTER, &filter, -1);
return filter_get_gtk_filter (filter);
2005-08-25 02:29:01 -07:00
}
2005-09-04 23:30:18 -07:00
void
moo_filter_mgr_set_last_filter (MooFilterMgr *mgr,
GtkTreeIter *iter,
const char *user_id)
{
FilterStore *store;
Filter *filter = NULL;
g_return_if_fail (MOO_IS_FILTER_MGR (mgr));
g_return_if_fail (iter != NULL);
mgr_load (mgr);
store = mgr_get_store (mgr, user_id, FALSE);
g_return_if_fail (store != NULL);
gtk_tree_model_get (GTK_TREE_MODEL (store->filters), iter,
COLUMN_FILTER, &filter, -1);
g_return_if_fail (filter != NULL);
mgr_set_last_filter (mgr, user_id, filter);
}
GtkFileFilter*
moo_filter_mgr_get_null_filter (MooFilterMgr *mgr)
2005-08-25 02:29:01 -07:00
{
g_return_val_if_fail (MOO_IS_FILTER_MGR (mgr), NULL);
return mgr_get_null_filter(mgr)->filter;
2005-08-25 02:29:01 -07:00
}
static Filter*
mgr_get_null_filter (MooFilterMgr *mgr)
{
return g_hash_table_lookup (mgr->priv->filters, ALL_FILES_GLOB);
}
GtkFileFilter*
moo_filter_mgr_get_last_filter (MooFilterMgr *mgr,
const char *user_id)
2005-08-25 02:29:01 -07:00
{
g_return_val_if_fail (MOO_IS_FILTER_MGR (mgr), NULL);
2005-09-04 23:30:18 -07:00
mgr_load (mgr);
return filter_get_gtk_filter (mgr_get_last_filter (mgr, user_id));
}
static Filter*
mgr_get_last_filter (MooFilterMgr *mgr,
const char *user_id)
{
FilterStore *store;
g_return_val_if_fail (MOO_IS_FILTER_MGR (mgr), NULL);
store = mgr_get_store (mgr, user_id, FALSE);
if (store)
return filter_store_get_last (store);
2005-08-25 02:29:01 -07:00
else
return NULL;
}
static void
mgr_set_last_filter (MooFilterMgr *mgr,
const char *user_id,
Filter *filter)
2005-08-25 02:29:01 -07:00
{
FilterStore *store;
g_return_if_fail (MOO_IS_FILTER_MGR (mgr));
store = mgr_get_store (mgr, user_id, TRUE);
store->last_filter = filter;
2005-09-04 23:30:18 -07:00
mgr_save (mgr);
2005-08-25 02:29:01 -07:00
}
GtkFileFilter*
moo_filter_mgr_new_user_filter (MooFilterMgr *mgr,
const char *glob,
const char *user_id)
2005-08-25 02:29:01 -07:00
{
g_return_val_if_fail (MOO_IS_FILTER_MGR (mgr), NULL);
g_return_val_if_fail (glob != NULL, NULL);
2005-09-04 23:30:18 -07:00
mgr_load (mgr);
return filter_get_gtk_filter (mgr_new_user_filter (mgr, glob, user_id));
}
static Filter*
mgr_new_user_filter (MooFilterMgr *mgr,
const char *glob,
const char *user_id)
{
FilterStore *store;
2005-08-25 02:29:01 -07:00
Filter *filter;
filter = mgr_new_filter (mgr, glob, glob, TRUE);
g_return_val_if_fail (filter != NULL, NULL);
store = mgr_get_store (mgr, user_id, TRUE);
filter_store_add_user (store, filter);
2005-09-04 23:30:18 -07:00
mgr_save (mgr);
return filter;
}
GtkFileFilter*
moo_filter_mgr_new_builtin_filter (MooFilterMgr *mgr,
const char *description,
const char *glob,
const char *user_id,
int position)
{
FilterStore *store;
Filter *filter;
g_return_val_if_fail (MOO_IS_FILTER_MGR (mgr), NULL);
g_return_val_if_fail (glob != NULL, NULL);
g_return_val_if_fail (description != NULL, NULL);
2005-09-04 23:30:18 -07:00
mgr_load (mgr);
filter = mgr_new_filter (mgr, description, glob, FALSE);
g_return_val_if_fail (filter != NULL, NULL);
store = mgr_get_store (mgr, user_id, TRUE);
filter_store_add_builtin (store, filter, position);
2005-09-04 23:30:18 -07:00
return filter->filter;
}
static Filter*
mgr_new_filter (MooFilterMgr *mgr,
const char *description,
const char *glob,
gboolean user)
{
Filter *filter;
g_return_val_if_fail (description != NULL, NULL);
g_return_val_if_fail (glob != NULL, NULL);
filter = g_hash_table_lookup (mgr->priv->filters, glob);
if (!filter)
{
filter = filter_new (description, glob, user);
g_return_val_if_fail (filter != NULL, NULL);
g_hash_table_insert (mgr->priv->filters,
g_strdup (glob), filter);
}
return filter;
}
/*****************************************************************************/
/* Filechooser
*/
static void
dialog_set_filter (MooFilterMgr *mgr,
GtkFileChooser *dialog,
Filter *filter)
{
GtkEntry *entry = g_object_get_data (G_OBJECT (dialog),
"moo-filter-entry");
gtk_entry_set_text (entry, filter_get_description (filter));
gtk_file_chooser_set_filter (dialog, filter_get_gtk_filter (filter));
mgr_set_last_filter (mgr,
g_object_get_data (G_OBJECT (dialog), "moo-filter-user-id"),
filter);
}
static void
filter_entry_activated (GtkEntry *entry,
GtkFileChooser *dialog)
{
const char *text;
Filter *filter = NULL;
MooFilterMgr *mgr;
mgr = g_object_get_data (G_OBJECT (dialog), "moo-filter-mgr");
g_return_if_fail (MOO_IS_FILTER_MGR (mgr));
text = gtk_entry_get_text (entry);
if (text && text[0])
filter = mgr_new_user_filter (mgr, text,
g_object_get_data (G_OBJECT (dialog),
"moo-filter-user-id"));
if (!filter)
filter = mgr_get_null_filter (mgr);
dialog_set_filter (mgr, dialog, filter);
}
static void
combo_changed (MooCombo *combo,
GtkFileChooser *dialog)
{
GtkTreeIter iter;
Filter *filter;
MooFilterMgr *mgr;
FilterStore *store;
if (!moo_combo_get_active_iter (combo, &iter))
return;
mgr = g_object_get_data (G_OBJECT (dialog), "moo-filter-mgr");
g_return_if_fail (MOO_IS_FILTER_MGR (mgr));
store = mgr_get_store (mgr,
g_object_get_data (G_OBJECT (dialog),
"moo-filter-user-id"),
FALSE);
g_return_if_fail (store != NULL);
gtk_tree_model_get (GTK_TREE_MODEL (store->filters), &iter,
COLUMN_FILTER, &filter, -1);
g_return_if_fail (filter != NULL);
dialog_set_filter (mgr, dialog, filter);
}
void
moo_filter_mgr_attach (MooFilterMgr *mgr,
GtkFileChooser *dialog,
const char *user_id)
{
GtkWidget *alignment;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *combo;
GtkWidget *entry;
Filter *filter;
g_return_if_fail (MOO_IS_FILTER_MGR (mgr));
g_return_if_fail (GTK_IS_FILE_CHOOSER (dialog));
2005-09-04 23:30:18 -07:00
mgr_load (mgr);
alignment = gtk_alignment_new (1, 0.5, 0, 1);
gtk_widget_show (alignment);
gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), alignment);
hbox = gtk_hbox_new (FALSE, 0);
gtk_widget_show (hbox);
gtk_container_add (GTK_CONTAINER (alignment), hbox);
label = gtk_label_new_with_mnemonic ("_Filter:");
gtk_widget_show (label);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
combo = moo_combo_new ();
moo_filter_mgr_init_filter_combo (mgr, MOO_COMBO (combo), user_id);
gtk_widget_show (combo);
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
entry = MOO_COMBO(combo)->entry;
gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
g_signal_connect (entry, "activate",
G_CALLBACK (filter_entry_activated),
dialog);
g_signal_connect (combo, "changed",
G_CALLBACK (combo_changed),
dialog);
g_object_set_data (G_OBJECT (dialog), "moo-filter-combo", combo);
g_object_set_data (G_OBJECT (dialog), "moo-filter-entry", entry);
g_object_set_data_full (G_OBJECT (dialog), "moo-filter-mgr",
g_object_ref (mgr), g_object_unref);
g_object_set_data_full (G_OBJECT (dialog), "moo-filter-user-id",
g_strdup (user_id), g_free);
filter = mgr_get_last_filter (mgr, user_id);
2005-08-25 02:29:01 -07:00
if (filter)
dialog_set_filter (mgr, GTK_FILE_CHOOSER (dialog), filter);
}
/*****************************************************************************/
/* FilterStore
*/
static FilterStore*
filter_store_new (MooFilterMgr *mgr)
{
FilterStore *store = g_new0 (FilterStore, 1);
store->filters = gtk_list_store_new (NUM_COLUMNS,
G_TYPE_STRING,
G_TYPE_POINTER);
store->last_filter = NULL;
store->num_user = 0;
store->num_builtin = 0;
store->has_separator = FALSE;
store->max_num_user = NUM_USER_FILTERS;
filter_store_add_builtin (store, mgr_get_null_filter (mgr), -1);
return store;
}
static void
filter_store_free (FilterStore *store)
{
if (store)
{
g_object_unref (store->filters);
g_free (store);
}
}
2005-09-04 23:30:18 -07:00
static GSList*
filter_store_list_user_filters (FilterStore *store)
{
GSList *list = NULL;
GtkTreeIter iter;
guint offset;
g_return_val_if_fail (store != NULL, NULL);
if (!store->num_user)
return NULL;
offset = store->num_builtin + (store->has_separator ? 1 : 0);
if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store->filters), &iter, NULL, offset))
g_return_val_if_reached (NULL);
do
{
Filter *filter = NULL;
gtk_tree_model_get (GTK_TREE_MODEL (store->filters), &iter,
COLUMN_FILTER, &filter, -1);
list = g_slist_prepend (list, filter);
}
while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store->filters), &iter));
return g_slist_reverse (list);
}
static gboolean
filter_store_find_builtin (FilterStore *store,
Filter *filter,
GtkTreeIter *iter)
{
guint i;
Filter *filt = NULL;
for (i = 0; i < store->num_builtin; ++i)
{
gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store->filters),
iter, NULL, i);
gtk_tree_model_get (GTK_TREE_MODEL (store->filters), iter,
COLUMN_FILTER, &filt, -1);
if (filter == filt)
return TRUE;
}
return FALSE;
}
static void
filter_store_add_builtin (FilterStore *store,
Filter *filter,
int position)
{
GtkTreeIter iter;
g_return_if_fail (store != NULL);
g_return_if_fail (filter != NULL);
store->last_filter = filter;
2005-09-04 23:30:18 -07:00
if (filter_store_find_builtin (store, filter, &iter))
return;
if (position < 0 || position > (int) store->num_builtin)
position = store->num_builtin;
gtk_list_store_insert (store->filters, &iter, position);
gtk_list_store_set (store->filters, &iter,
COLUMN_DESCRIPTION, filter_get_description (filter),
COLUMN_FILTER, filter, -1);
store->num_builtin++;
if (store->num_user && !store->has_separator)
{
gtk_list_store_insert (store->filters, &iter, store->num_builtin);
store->has_separator = TRUE;
}
}
static gboolean
filter_store_find_user (FilterStore *store,
Filter *filter,
GtkTreeIter *iter)
{
guint i, offset;
Filter *filt = NULL;
offset = store->num_builtin + (store->has_separator ? 1 : 0);
for (i = offset; i < offset + store->num_user; ++i)
{
gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store->filters),
iter, NULL, i);
gtk_tree_model_get (GTK_TREE_MODEL (store->filters), iter,
COLUMN_FILTER, &filt, -1);
if (filter == filt)
return TRUE;
}
2005-08-25 02:29:01 -07:00
return FALSE;
}
static void
filter_store_add_user (FilterStore *store,
Filter *filter)
2005-08-25 02:29:01 -07:00
{
GtkTreeIter iter;
g_return_if_fail (store != NULL);
g_return_if_fail (filter != NULL);
store->last_filter = filter;
if (filter_store_find_builtin (store, filter, &iter))
return;
if (filter_store_find_user (store, filter, &iter))
{
gtk_list_store_remove (store->filters, &iter);
store->num_user--;
}
gtk_list_store_insert (store->filters, &iter,
store->num_builtin + (store->has_separator ? 1 : 0));
gtk_list_store_set (store->filters, &iter,
COLUMN_DESCRIPTION, filter_get_description (filter),
COLUMN_FILTER, filter, -1);
store->num_user++;
if (store->num_builtin && !store->has_separator)
{
gtk_list_store_insert (store->filters, &iter, store->num_builtin);
store->has_separator = TRUE;
}
if (store->num_user > store->max_num_user)
{
gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store->filters),
&iter, NULL,
store->num_builtin +
(store->has_separator ? 1 : 0) +
store->num_user - 1);
gtk_list_store_remove (store->filters, &iter);
store->num_user--;
}
2005-08-25 02:29:01 -07:00
}
static Filter *filter_store_get_last (FilterStore *store)
{
if (!store->last_filter)
{
GtkTreeIter iter;
Filter *filter = NULL;
gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store->filters), &iter);
gtk_tree_model_get (GTK_TREE_MODEL (store->filters), &iter,
COLUMN_FILTER, &filter, -1);
store->last_filter = filter;
}
return store->last_filter;
}
/*****************************************************************************/
/* Filter
*/
2005-08-25 02:29:01 -07:00
#define NEGATE_CHAR '!'
#define GLOB_SEPARATOR ";"
static gboolean
neg_filter_func (const GtkFileFilterInfo *filter_info,
Filter *filter)
2005-08-25 02:29:01 -07:00
{
return !gtk_file_filter_filter (filter->aux, filter_info);
}
static Filter*
filter_new (const char *description,
const char *glob,
gboolean user)
2005-08-25 02:29:01 -07:00
{
Filter *filter;
char **globs, **p;
gboolean negative;
g_return_val_if_fail (description != NULL, NULL);
g_return_val_if_fail (g_utf8_validate (description, -1, NULL), NULL);
g_return_val_if_fail (g_utf8_validate (glob, -1, NULL), NULL);
2005-08-25 02:29:01 -07:00
g_return_val_if_fail (glob != NULL && glob[0] != 0, NULL);
g_return_val_if_fail (glob[0] != NEGATE_CHAR || glob[1] != 0, NULL);
if (glob[0] == NEGATE_CHAR)
{
negative = TRUE;
globs = g_strsplit (glob + 1, GLOB_SEPARATOR, 0);
}
else
{
negative = FALSE;
globs = g_strsplit (glob, GLOB_SEPARATOR, 0);
}
g_return_val_if_fail (globs != NULL, NULL);
filter = g_new0 (Filter, 1);
filter->description = g_strdup (description);
filter->glob = g_strdup (glob);
filter->user = user;
filter->filter = gtk_file_filter_new ();
gtk_object_sink (GTK_OBJECT (g_object_ref (filter->filter)));
gtk_file_filter_set_name (filter->filter, description);
if (negative)
{
filter->aux = gtk_file_filter_new ();
gtk_object_sink (GTK_OBJECT (g_object_ref (filter->aux)));
for (p = globs; *p != NULL; p++)
gtk_file_filter_add_pattern (filter->aux, *p);
gtk_file_filter_add_custom (filter->filter,
gtk_file_filter_get_needed (filter->aux),
(GtkFileFilterFunc) neg_filter_func,
filter, NULL);
}
else
{
for (p = globs; *p != NULL; p++)
gtk_file_filter_add_pattern (filter->filter, *p);
}
g_strfreev (globs);
return filter;
}
static void
filter_free (Filter *filter)
2005-08-25 02:29:01 -07:00
{
if (filter)
{
if (filter->filter)
g_object_unref (filter->filter);
filter->filter = NULL;
if (filter->aux)
g_object_unref (filter->aux);
filter->aux = NULL;
g_free (filter->description);
filter->description = NULL;
g_free (filter->glob);
filter->glob = NULL;
g_free (filter);
}
}
static GtkFileFilter *filter_get_gtk_filter (Filter *filter)
2005-08-25 02:29:01 -07:00
{
g_return_val_if_fail (filter != NULL, NULL);
return filter->filter;
2005-08-25 02:29:01 -07:00
}
2005-09-04 23:30:18 -07:00
static const char*
filter_get_glob (Filter *filter)
{
g_return_val_if_fail (filter != NULL, NULL);
return filter->glob;
}
2005-08-25 02:29:01 -07:00
static const char*
filter_get_description (Filter *filter)
2005-08-25 02:29:01 -07:00
{
g_return_val_if_fail (filter != NULL, NULL);
return filter->description;
2005-08-25 02:29:01 -07:00
}
2005-09-04 23:30:18 -07:00
/***************************************************************************/
/* Loading and saving
*/
#define FILTERS_ROOT "Editor/filters"
#define ELEMENT_DEFAULT "default"
#define ELEMENT_SET "set"
#define ELEMENT_FILTER "filter"
#define ELEMENT_LAST "last"
#define PROP_USER_ID "user-id"
#define PROP_USER "user"
#define PROP_DESCRIPTION "description"
static void
mgr_load_set (MooFilterMgr *mgr,
const char *user_id,
MooMarkupNode *root)
2005-09-04 23:30:18 -07:00
{
MooMarkupNode *elm;
2005-09-04 23:30:18 -07:00
for (elm = root->last; elm != NULL; elm = elm->prev)
2005-09-04 23:30:18 -07:00
{
if (!MOO_MARKUP_IS_ELEMENT (elm))
2005-09-04 23:30:18 -07:00
continue;
if (!strcmp (elm->name, ELEMENT_FILTER))
{
const char *glob = moo_markup_get_content (elm);
2005-09-04 23:30:18 -07:00
if (!glob || !glob[0])
{
g_warning ("%s: empty glob in filter entry", G_STRLOC);
continue;
}
moo_filter_mgr_new_user_filter (mgr, glob, user_id);
}
else if (!strcmp (elm->name, ELEMENT_LAST))
{
const char *glob = moo_markup_get_content (elm);
2005-09-04 23:30:18 -07:00
const char *user_str = moo_markup_get_prop (elm, PROP_USER);
const char *description = moo_markup_get_prop (elm, PROP_DESCRIPTION);
gboolean user;
if (!glob || !glob[0])
{
g_warning ("%s: empty glob in filter entry", G_STRLOC);
continue;
}
if (user_str)
user = strcmp (user_str, "TRUE") ? FALSE : TRUE;
else
user = FALSE;
if (!user && !description)
{
g_warning ("%s: no description in filter entry", G_STRLOC);
continue;
}
/* XXX */
if (user)
{
moo_filter_mgr_new_user_filter (mgr, glob, user_id);
}
else
{
Filter *filter;
moo_filter_mgr_new_builtin_filter (mgr, description, glob, user_id, -1);
filter = mgr_new_filter (mgr, description, glob, FALSE);
g_return_if_fail (filter != NULL);
mgr_set_last_filter (mgr, user_id, filter);
}
}
else
{
g_warning ("%s: invalid '%s' element", G_STRLOC, elm->name);
}
}
}
static void
mgr_load (MooFilterMgr *mgr)
{
MooMarkupDoc *xml;
MooMarkupNode *root, *elm;
2005-09-04 23:30:18 -07:00
if (mgr->priv->loaded)
return;
else
mgr->priv->loaded = TRUE;
xml = moo_prefs_get_markup ();
g_return_if_fail (xml != NULL);
root = moo_markup_get_element (MOO_MARKUP_NODE (xml), FILTERS_ROOT);
if (!root)
return;
for (elm = root->children; elm != NULL; elm = elm->next)
2005-09-04 23:30:18 -07:00
{
if (!MOO_MARKUP_IS_ELEMENT (elm))
2005-09-04 23:30:18 -07:00
continue;
if (!strcmp (elm->name, ELEMENT_DEFAULT))
{
mgr_load_set (mgr, NULL, elm);
}
else if (!strcmp (elm->name, ELEMENT_SET))
{
const char *user_id = moo_markup_get_prop (elm, PROP_USER_ID);
if (!user_id || !user_id[0])
{
g_warning ("%s: empty user id", G_STRLOC);
continue;
}
mgr_load_set (mgr, user_id, elm);
}
else
{
g_warning ("%s: invalid '%s' element", G_STRLOC, elm->name);
}
}
}
/* XXX */
static void
mgr_save_set (MooFilterMgr *mgr,
const char *user_id,
MooMarkupNode *root)
2005-09-04 23:30:18 -07:00
{
MooMarkupNode *elm;
2005-09-04 23:30:18 -07:00
GSList *list, *l;
FilterStore *store;
Filter *filter;
store = mgr_get_store (mgr, user_id, FALSE);
g_return_if_fail (store != NULL);
if (!store->num_user && !store->last_filter)
return;
if (store->last_filter)
{
filter = store->last_filter;
elm = moo_markup_create_text_element (root, ELEMENT_LAST,
2005-09-04 23:30:18 -07:00
filter_get_glob (filter));
moo_markup_set_prop (elm, PROP_USER, filter->user ? "TRUE" : "FALSE");
if (!filter->user)
moo_markup_set_prop (elm, PROP_DESCRIPTION, filter->description);
}
list = filter_store_list_user_filters (store);
if (!list)
return;
for (l = list; l != NULL; l = l->next)
moo_markup_create_text_element (root, ELEMENT_FILTER,
2005-09-04 23:30:18 -07:00
filter_get_glob (l->data));
g_slist_free (list);
}
static gboolean
mgr_do_save (MooFilterMgr *mgr)
{
MooMarkupDoc *xml;
MooMarkupNode *root, *elm;
2005-09-04 23:30:18 -07:00
GSList *user_ids, *l;
mgr->priv->save_idle_id = 0;
xml = moo_prefs_get_markup ();
g_return_val_if_fail (xml != NULL, FALSE);
root = moo_markup_get_element (MOO_MARKUP_NODE (xml), FILTERS_ROOT);
if (root)
moo_markup_delete_node (root);
2005-09-04 23:30:18 -07:00
root = NULL;
user_ids = mgr_list_user_ids (mgr);
user_ids = g_slist_prepend (user_ids, NULL);
for (l = user_ids; l != NULL; l = l->next)
{
FilterStore *store = mgr_get_store (mgr, l->data, FALSE);
g_return_val_if_fail (!l->data || store != NULL, FALSE);
if (!store)
continue;
if (store->num_user || store->last_filter != mgr_get_null_filter (mgr))
{
if (!root)
{
root = moo_markup_create_element (MOO_MARKUP_NODE (xml), FILTERS_ROOT);
g_return_val_if_fail (root != NULL, FALSE);
}
if (l->data)
{
elm = moo_markup_create_element (root, ELEMENT_SET);
2005-09-04 23:30:18 -07:00
moo_markup_set_prop (elm, PROP_USER_ID, l->data);
}
else
{
elm = moo_markup_create_element (root, ELEMENT_DEFAULT);
2005-09-04 23:30:18 -07:00
}
mgr_save_set (mgr, l->data, elm);
}
}
g_slist_foreach (user_ids, (GFunc) g_free, NULL);
g_slist_free (user_ids);
return FALSE;
}
static void mgr_save (MooFilterMgr *mgr)
{
if (!mgr->priv->save_idle_id)
mgr->priv->save_idle_id = g_idle_add ((GSourceFunc) mgr_do_save, mgr);
}