diff options
Diffstat (limited to 'shell/e-storage-set-store.c')
-rw-r--r-- | shell/e-storage-set-store.c | 1361 |
1 files changed, 0 insertions, 1361 deletions
diff --git a/shell/e-storage-set-store.c b/shell/e-storage-set-store.c deleted file mode 100644 index e2816d87d2..0000000000 --- a/shell/e-storage-set-store.c +++ /dev/null @@ -1,1361 +0,0 @@ -/* e-storage-set-store.c - * Copyright (C) 2002 Ximian, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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 <string.h> - -#include <gtk/gtktreemodel.h> -#include <gtk/gtktreednd.h> - -#include "e-icon-factory.h" -#include "e-storage-set-store.h" -#include "e-shell-constants.h" - -struct _EStorageSetStorePrivate { - EStorageSet *storage_set; - GHashTable *checkboxes; - GHashTable *path_to_node; - GHashTable *type_name_to_pixbuf; - GNode *root; - gint stamp; - EStorageSetStoreHasCheckBoxFunc has_checkbox_func; - gpointer has_checkbox_func_data; -}; - -#define G_NODE(node) ((GNode *)(node)) -#define VALID_ITER(iter, store) ((iter) != NULL && (iter)->user_data != NULL && (store)->priv->stamp == (iter)->stamp) -#define VALID_COL(col) ((col) >= 0 && (col) < E_STORAGE_SET_STORE_COLUMN_COUNT) - -static GObjectClass *parent_class = NULL; - -static gboolean -has_checkbox (EStorageSetStore *store, const gchar *folder_path) -{ - EStorageSetStorePrivate *priv = store->priv; - - g_return_val_if_fail (folder_path != NULL, FALSE); - - if (strchr (folder_path + 1, '/') == NULL) { - /* If it's a toplevel, never allow checking it. */ - return FALSE; - } - -#if 0 - if (priv->has_checkbox_func) - return (* priv->has_checkbox_func) (priv->storage_set, - folder_path, - priv->has_checkbox_func_data); -#endif - - return TRUE; -} - - -/* GtkTreeModel interface implementation */ - -static guint -esss_get_flags(GtkTreeModel *tree_model) -{ - g_return_val_if_fail(E_IS_STORAGE_SET_STORE(tree_model), 0); - - return GTK_TREE_MODEL_ITERS_PERSIST; -} - -static gint -esss_get_n_columns(GtkTreeModel *tree_model) -{ - g_return_val_if_fail(E_IS_STORAGE_SET_STORE(tree_model), 0); - - return E_STORAGE_SET_STORE_COLUMN_COUNT; -} - -static GType -esss_get_column_type(GtkTreeModel *tree_model, gint index) -{ - EStorageSetStore *store = (EStorageSetStore *) tree_model; - GType retval; - - g_return_val_if_fail(E_IS_STORAGE_SET_STORE(tree_model), G_TYPE_INVALID); - g_return_val_if_fail(VALID_COL(index), G_TYPE_INVALID); - - switch (index) { - case E_STORAGE_SET_STORE_COLUMN_NAME: - retval = G_TYPE_STRING; - break; - case E_STORAGE_SET_STORE_COLUMN_HIGHLIGHT: - retval = G_TYPE_INT; - break; - case E_STORAGE_SET_STORE_COLUMN_CHECKED: - case E_STORAGE_SET_STORE_COLUMN_CHECKABLE: - retval = G_TYPE_BOOLEAN; - break; - case E_STORAGE_SET_STORE_COLUMN_ICON: - retval = GDK_TYPE_PIXBUF; - break; - default: - g_assert_not_reached (); - } - - return retval; -} - -static gboolean -esss_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path) -{ - EStorageSetStore *store = (EStorageSetStore *) tree_model; - GtkTreeIter parent; - gint *indices; - gint depth, i; - - g_return_val_if_fail(E_IS_STORAGE_SET_STORE(tree_model), FALSE); - g_return_val_if_fail(iter != NULL, FALSE); - - indices = gtk_tree_path_get_indices(path); - depth = gtk_tree_path_get_depth(path); - - g_return_val_if_fail(depth > 0, FALSE); - - parent.stamp = store->priv->stamp; - parent.user_data = store->priv->root; - - for (i = 0; i < depth; i++) { - if (!gtk_tree_model_iter_nth_child (tree_model, iter, &parent, indices[i])) - return FALSE; - parent = *iter; - } - - return TRUE; -} - -static GtkTreePath * -tree_path_from_node (EStorageSetStore *store, GNode *node) -{ - GtkTreePath *retval; - GNode *tmp_node, *curr_node; - gint i = 0; - - if (node == store->priv->root) - return NULL; - - retval = gtk_tree_path_new(); - - for (curr_node = node; curr_node != store->priv->root; curr_node = curr_node->parent) { - - if (curr_node->parent == NULL) { - gtk_tree_path_free(retval); - return NULL; - } - - for (i = 0, tmp_node = curr_node->parent->children; - tmp_node && tmp_node != curr_node; - i++, tmp_node = tmp_node->next); - - if (tmp_node == NULL) { - gtk_tree_path_free(retval); - return NULL; - } - - gtk_tree_path_prepend_index(retval, i); - } - - return retval; -} - -static GtkTreePath * -esss_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter) -{ - EStorageSetStore *store = (EStorageSetStore *) tree_model; - - g_return_val_if_fail(E_IS_STORAGE_SET_STORE(tree_model), NULL); - g_return_val_if_fail(VALID_ITER(iter, store), NULL); - - if (iter->user_data == store->priv->root) - return NULL; - - return tree_path_from_node (store, G_NODE (iter->user_data)); -} - -static GdkPixbuf * -get_pixbuf_for_folder (EStorageSetStore *store, EFolder *folder) -{ - const char *type_name; - EStorageSetStorePrivate *priv; - EFolderTypeRegistry *folder_type_registry; - EStorageSet *storage_set; - GdkPixbuf *icon_pixbuf; - GdkPixbuf *scaled_pixbuf; - const char *custom_icon_name; - int icon_pixbuf_width, icon_pixbuf_height; - - priv = store->priv; - - custom_icon_name = e_folder_get_custom_icon_name (folder); - if (custom_icon_name != NULL) - return e_icon_factory_get_icon (custom_icon_name, TRUE); - - type_name = e_folder_get_type_string (folder); - - scaled_pixbuf = g_hash_table_lookup (priv->type_name_to_pixbuf, type_name); - if (scaled_pixbuf != NULL) - return scaled_pixbuf; - - storage_set = priv->storage_set; - folder_type_registry = e_storage_set_get_folder_type_registry (storage_set); - - icon_pixbuf = e_folder_type_registry_get_icon_for_type (folder_type_registry, - type_name, TRUE); - - if (icon_pixbuf == NULL) - return NULL; - - icon_pixbuf_width = gdk_pixbuf_get_width (icon_pixbuf); - icon_pixbuf_height = gdk_pixbuf_get_height (icon_pixbuf); - - if (icon_pixbuf_width == E_SHELL_MINI_ICON_SIZE && icon_pixbuf_height == E_SHELL_MINI_ICON_SIZE) { - scaled_pixbuf = g_object_ref (icon_pixbuf); - } else { - scaled_pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (icon_pixbuf), - gdk_pixbuf_get_has_alpha (icon_pixbuf), - gdk_pixbuf_get_bits_per_sample (icon_pixbuf), - E_SHELL_MINI_ICON_SIZE, E_SHELL_MINI_ICON_SIZE); - - gdk_pixbuf_scale (icon_pixbuf, scaled_pixbuf, - 0, 0, E_SHELL_MINI_ICON_SIZE, E_SHELL_MINI_ICON_SIZE, - 0.0, 0.0, - (double) E_SHELL_MINI_ICON_SIZE / gdk_pixbuf_get_width (icon_pixbuf), - (double) E_SHELL_MINI_ICON_SIZE / gdk_pixbuf_get_height (icon_pixbuf), - GDK_INTERP_HYPER); - } - - g_hash_table_insert (priv->type_name_to_pixbuf, g_strdup (type_name), scaled_pixbuf); - - return scaled_pixbuf; -} - -static void -esss_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value) -{ - gchar *folder_path; - const gchar *folder_name; - int unread_count; - EStorageSetStore *store = (EStorageSetStore *) tree_model; - EFolder *folder; - GNode *node; - gboolean is_storage; - - g_return_if_fail(E_IS_STORAGE_SET_STORE(tree_model)); - g_return_if_fail(VALID_ITER(iter, store)); - g_return_if_fail(VALID_COL(column)); - - node = G_NODE (iter->user_data); - g_value_init(value, esss_get_column_type(tree_model, column)); - - is_storage = (node->parent == store->priv->root); - - if (is_storage) - folder_path = g_strconcat ("/", node->data, NULL); - else - folder_path = g_strdup (node->data); - - folder = e_storage_set_get_folder(store->priv->storage_set, folder_path); - g_free (folder_path); - - switch (column) { - case E_STORAGE_SET_STORE_COLUMN_NAME: - if (!folder) { - g_value_set_string(value, "?"); - return; - } - folder_name = e_folder_get_name(folder); - unread_count = e_folder_get_unread_count(folder); - if (unread_count > 0) { - gchar *with_unread = g_strdup_printf("%s (%d)", folder_name, unread_count); - g_object_set_data_full(G_OBJECT(folder), "name_with_unread", - with_unread, g_free); - g_value_set_string(value, with_unread); - } else - g_value_set_string(value, folder_name); - break; - - case E_STORAGE_SET_STORE_COLUMN_HIGHLIGHT: - if (!folder) { - g_value_set_boolean(value, FALSE); - return; - } - g_value_set_int(value, is_storage || e_folder_get_highlighted(folder) ? PANGO_WEIGHT_BOLD : 0); - break; - - case E_STORAGE_SET_STORE_COLUMN_CHECKED: - if (is_storage || !store->priv->checkboxes) { - g_value_set_boolean(value, FALSE); - return; - } - g_value_set_boolean(value, - g_hash_table_lookup(store->priv->checkboxes, folder_path) ? TRUE : FALSE); - break; - - case E_STORAGE_SET_STORE_COLUMN_CHECKABLE: - g_value_set_boolean(value, !is_storage && has_checkbox(store, (gchar *)node->data)); - break; - - case E_STORAGE_SET_STORE_COLUMN_ICON: - if (!is_storage) - g_value_set_object (value, get_pixbuf_for_folder (store, folder)); - break; - - default: - g_assert_not_reached (); - break; - } -} - -static gboolean -esss_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter) -{ - g_return_val_if_fail(E_IS_STORAGE_SET_STORE(tree_model), FALSE); - g_return_val_if_fail(VALID_ITER(iter, E_STORAGE_SET_STORE(tree_model)), FALSE); - - if (G_NODE(iter->user_data)->next) { - iter->user_data = G_NODE(iter->user_data)->next; - return TRUE; - } else - return FALSE; -} - -static gboolean -esss_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) -{ - GNode *children; - EStorageSetStore *store = (EStorageSetStore *) tree_model; - - g_return_val_if_fail(E_IS_STORAGE_SET_STORE(tree_model), FALSE); - g_return_val_if_fail(iter != NULL, FALSE); - g_return_val_if_fail(parent == NULL || parent->user_data != NULL, FALSE); - g_return_val_if_fail(parent == NULL || parent->stamp == store->priv->stamp, FALSE); - - if (parent) - children = G_NODE(parent->user_data)->children; - else - children = - G_NODE(store->priv->root)->children; - - if (children) { - iter->stamp = store->priv->stamp; - iter->user_data = children; - return TRUE; - } else - return FALSE; -} - -static gboolean -esss_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter) -{ - EStorageSetStore *store = (EStorageSetStore *) tree_model; - - g_return_val_if_fail(E_IS_STORAGE_SET_STORE(tree_model), FALSE); - g_return_val_if_fail(VALID_ITER(iter, store), FALSE); - - return G_NODE(iter->user_data)->children != NULL; -} - -static gint -esss_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter) -{ - GNode *node; - gint i = 0; - EStorageSetStore *store = (EStorageSetStore *) tree_model; - - g_return_val_if_fail(E_IS_STORAGE_SET_STORE(tree_model), 0); - g_return_val_if_fail(iter == NULL || iter->user_data != NULL, FALSE); - - if (iter == NULL) - node = G_NODE(store->priv->root)->children; - else - node = G_NODE(iter->user_data)->children; - - while (node) { - i++; - node = node->next; - } - - return i; -} - -static gboolean -esss_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n) -{ - GNode *parent_node; - GNode *child; - EStorageSetStore *store = (EStorageSetStore *) tree_model; - - g_return_val_if_fail(E_IS_STORAGE_SET_STORE(tree_model), FALSE); - g_return_val_if_fail(iter != NULL, FALSE); - g_return_val_if_fail(parent == NULL || parent->user_data != NULL, FALSE); - - if (parent == NULL) - parent_node = store->priv->root; - else - parent_node = parent->user_data; - - child = g_node_nth_child(parent_node, n); - - if (child) { - iter->user_data = child; - iter->stamp = store->priv->stamp; - return TRUE; - } else - return FALSE; -} - -static gboolean -esss_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) -{ - GNode *parent; - EStorageSetStore *store = (EStorageSetStore *) tree_model; - - g_return_val_if_fail(E_IS_STORAGE_SET_STORE(tree_model), FALSE); - g_return_val_if_fail(iter != NULL, FALSE); - g_return_val_if_fail(VALID_ITER(child, store), FALSE); - - parent = G_NODE(child->user_data)->parent; - - g_assert(parent != NULL); - - if (parent != store->priv->root) { - iter->user_data = parent; - iter->stamp = store->priv->stamp; - return TRUE; - } else - return FALSE; -} - -static void -esss_tree_model_init(GtkTreeModelIface *iface) -{ - iface->get_flags = esss_get_flags; - iface->get_n_columns = esss_get_n_columns; - iface->get_column_type = esss_get_column_type; - iface->get_iter = esss_get_iter; - iface->get_path = esss_get_path; - iface->get_value = esss_get_value; - iface->iter_next = esss_iter_next; - iface->iter_children = esss_iter_children; - iface->iter_has_child = esss_iter_has_child; - iface->iter_n_children = esss_iter_n_children; - iface->iter_nth_child = esss_iter_nth_child; - iface->iter_parent = esss_iter_parent; -} - -/* GtkTreeDragSource interface implementation */ - -static gboolean -esss_drag_data_delete(GtkTreeDragSource *source, GtkTreePath *path) -{ - GtkTreeIter iter; - - g_return_val_if_fail(E_IS_STORAGE_SET_STORE(source), FALSE); - - if (gtk_tree_model_get_iter(GTK_TREE_MODEL(source), &iter, path)) { -#if 0 - e_storage_set_store_remove(E_STORAGE_SET_STORE(source), &iter); -#endif - return TRUE; - } else { - return FALSE; - } -} - -static gboolean -esss_drag_data_get(GtkTreeDragSource *source, GtkTreePath *path, GtkSelectionData *selection_data) -{ - g_return_val_if_fail(E_IS_STORAGE_SET_STORE(source), FALSE); - - /* Note that we don't need to handle the GTK_TREE_MODEL_ROW - * target, because the default handler does it for us, but - * we do anyway for the convenience of someone maybe overriding the - * default handler. - */ - - if (gtk_tree_set_row_drag_data(selection_data, GTK_TREE_MODEL(source), path)) { - return TRUE; - } else { - /* FIXME handle text targets at least. */ - } - - return FALSE; -} - -static void -esss_drag_source_init(GtkTreeDragSourceIface * iface) -{ - iface->drag_data_delete = esss_drag_data_delete; - iface->drag_data_get = esss_drag_data_get; -} - -/* GtkTreeDragDest interface implementation */ - -static void -copy_node_data(EStorageSetStore *store, GtkTreeIter *src_iter, GtkTreeIter *dest_iter) -{ -} - -static void -recursive_node_copy(EStorageSetStore * store, - GtkTreeIter * src_iter, GtkTreeIter * dest_iter) -{ -} - -static gboolean -esss_drag_data_received(GtkTreeDragDest * drag_dest, - GtkTreePath * dest, - GtkSelectionData * selection_data) -{ -#if 0 - GtkTreeModel *tree_model; - EStorageSetStore *store; - GtkTreeModel *src_model = NULL; - GtkTreePath *src_path = NULL; - gboolean retval = FALSE; - - g_return_val_if_fail(E_IS_STORAGE_SET_STORE(drag_dest), FALSE); - - tree_model = GTK_TREE_MODEL(drag_dest); - store = E_STORAGE_SET_STORE(drag_dest); - - validate_tree(store); - - if (gtk_tree_get_row_drag_data(selection_data, - &src_model, - &src_path) && - src_model == tree_model) { - /* Copy the given row to a new position */ - GtkTreeIter src_iter; - GtkTreeIter dest_iter; - GtkTreePath *prev; - - if (!gtk_tree_model_get_iter(src_model, - &src_iter, src_path)) { - goto out; - } - - /* Get the path to insert _after_ (dest is the path to insert _before_) */ - prev = gtk_tree_path_copy(dest); - - if (!gtk_tree_path_prev(prev)) { - GtkTreeIter dest_parent; - GtkTreePath *parent; - GtkTreeIter *dest_parent_p; - - /* dest was the first spot at the current depth; which means - * we are supposed to prepend. - */ - - /* Get the parent, NULL if parent is the root */ - dest_parent_p = NULL; - parent = gtk_tree_path_copy(dest); - if (gtk_tree_path_up(parent) && - gtk_tree_path_get_depth(parent) > 0) { - gtk_tree_model_get_iter(tree_model, - &dest_parent, - parent); - dest_parent_p = &dest_parent; - } - gtk_tree_path_free(parent); - parent = NULL; - - e_storage_set_store_prepend(E_STORAGE_SET_STORE(tree_model), - &dest_iter, dest_parent_p); - - retval = TRUE; - } else { - if (gtk_tree_model_get_iter - (GTK_TREE_MODEL(tree_model), &dest_iter, - prev)) { - GtkTreeIter tmp_iter = dest_iter; - - if (GPOINTER_TO_INT - (g_object_get_data - (G_OBJECT(tree_model), - "gtk-tree-model-drop-append"))) { - GtkTreeIter parent; - - if (gtk_tree_model_iter_parent - (GTK_TREE_MODEL(tree_model), - &parent, &tmp_iter)) - e_storage_set_store_append - (E_STORAGE_SET_STORE - (tree_model), - &dest_iter, &parent); - else - e_storage_set_store_append - (E_STORAGE_SET_STORE - (tree_model), - &dest_iter, NULL); - } else - e_storage_set_store_insert_after - (E_STORAGE_SET_STORE(tree_model), - &dest_iter, NULL, &tmp_iter); - retval = TRUE; - - } - } - - g_object_set_data(G_OBJECT(tree_model), - "gtk-tree-model-drop-append", NULL); - - gtk_tree_path_free(prev); - - /* If we succeeded in creating dest_iter, walk src_iter tree branch, - * duplicating it below dest_iter. - */ - - if (retval) { - recursive_node_copy(store, - &src_iter, &dest_iter); - } - } else { - /* FIXME maybe add some data targets eventually, or handle text - * targets in the simple case. - */ - - } - - out: - - if (src_path) - gtk_tree_path_free(src_path); - - return retval; -#else - return FALSE; -#endif -} - -static gboolean -esss_row_drop_possible(GtkTreeDragDest * drag_dest, - GtkTreePath * dest_path, - GtkSelectionData * selection_data) -{ -#if 0 - GtkTreeModel *src_model = NULL; - GtkTreePath *src_path = NULL; - GtkTreePath *tmp = NULL; - gboolean retval = FALSE; - - if (!gtk_tree_get_row_drag_data(selection_data, - &src_model, &src_path)) - goto out; - - /* can only drag to ourselves */ - if (src_model != GTK_TREE_MODEL(drag_dest)) - goto out; - - /* Can't drop into ourself. */ - if (gtk_tree_path_is_ancestor(src_path, dest_path)) - goto out; - - /* Can't drop if dest_path's parent doesn't exist */ - { - GtkTreeIter iter; - - if (gtk_tree_path_get_depth(dest_path) > 1) { - tmp = gtk_tree_path_copy(dest_path); - gtk_tree_path_up(tmp); - - if (!gtk_tree_model_get_iter - (GTK_TREE_MODEL(drag_dest), &iter, tmp)) - goto out; - } - } - - /* Can otherwise drop anywhere. */ - retval = TRUE; - - out: - - if (src_path) - gtk_tree_path_free(src_path); - if (tmp) - gtk_tree_path_free(tmp); - - return retval; -#else - return FALSE; -#endif -} - -static void -esss_drag_dest_init(GtkTreeDragDestIface * iface) -{ - iface->drag_data_received = esss_drag_data_received; - iface->row_drop_possible = esss_row_drop_possible; -} - -typedef struct { - gint offset; - GNode *node; -} SortTuple; - -static gint -folder_sort_callback (gconstpointer a, gconstpointer b, gpointer user_data) -{ - EStorageSetStore *store = (EStorageSetStore *) user_data; - EStorageSetStorePrivate *priv = store->priv; - EFolder *folder_1, *folder_2; - char *folder_path_1, *folder_path_2; - int priority_1, priority_2; - - - folder_path_1 = (gchar *)((SortTuple *)a)->node->data; - folder_path_2 = (gchar *)((SortTuple *)b)->node->data; - - folder_1 = e_storage_set_get_folder (priv->storage_set, folder_path_1); - folder_2 = e_storage_set_get_folder (priv->storage_set, folder_path_2); - - priority_1 = e_folder_get_sorting_priority (folder_1); - priority_2 = e_folder_get_sorting_priority (folder_2); - - if (priority_1 == priority_2) - return g_utf8_collate (e_folder_get_name (folder_1), e_folder_get_name (folder_2)); - else if (priority_1 < priority_2) - return -1; - else /* priority_1 > priority_2 */ - return +1; -} - -static gint -storage_sort_callback (gconstpointer a, gconstpointer b, gpointer user_data) -{ - char *folder_path_1; - char *folder_path_2; - gboolean path_1_local; - gboolean path_2_local; - - folder_path_1 = (gchar *)((SortTuple *)a)->node->data; - folder_path_2 = (gchar *)((SortTuple *)b)->node->data; - - /* FIXME bad hack to put the "my evolution" and "local" storages on - * top. */ - - if (strcmp (folder_path_1, E_SUMMARY_STORAGE_NAME) == 0) - return -1; - if (strcmp (folder_path_2, E_SUMMARY_STORAGE_NAME) == 0) - return +1; - - path_1_local = ! strcmp (folder_path_1, E_LOCAL_STORAGE_NAME); - path_2_local = ! strcmp (folder_path_2, E_LOCAL_STORAGE_NAME); - - if (path_1_local && path_2_local) - return 0; - if (path_1_local) - return -1; - if (path_2_local) - return 1; - - return g_utf8_collate (folder_path_1, folder_path_2); -} - -static void -esss_sort (EStorageSetStore *store, GNode *parent, GCompareDataFunc callback) -{ - GtkTreeIter iter; - GArray *sort_array; - GNode *node; - GNode *tmp_node; - gint list_length; - gint i; - gint *new_order; - GtkTreePath *path; - - node = parent->children; - if (node == NULL || node->next == NULL) - return; - - list_length = 0; - for (tmp_node = node; tmp_node; tmp_node = tmp_node->next) - list_length++; - - sort_array = g_array_sized_new(FALSE, FALSE, sizeof(SortTuple), list_length); - - i = 0; - for (tmp_node = node; tmp_node; tmp_node = tmp_node->next) { - SortTuple tuple; - - tuple.offset = i; - tuple.node = tmp_node; - g_array_append_val(sort_array, tuple); - i++; - } - - /* Sort the array */ - g_array_sort_with_data(sort_array, callback, store); - - for (i = 0; i < list_length - 1; i++) { - g_array_index(sort_array, SortTuple, i).node->next = - g_array_index(sort_array, SortTuple, i + 1).node; - g_array_index(sort_array, SortTuple, i + 1).node->prev = - g_array_index(sort_array, SortTuple, i).node; - } - g_array_index(sort_array, SortTuple, list_length - 1).node->next = NULL; - g_array_index(sort_array, SortTuple, 0).node->prev = NULL; - parent->children = g_array_index(sort_array, SortTuple, 0).node; - - /* Let the world know about our new order */ - new_order = g_new(gint, list_length); - for (i = 0; i < list_length; i++) - new_order[i] = g_array_index(sort_array, SortTuple, i).offset; - - iter.stamp = store->priv->stamp; - iter.user_data = parent; - path = esss_get_path(GTK_TREE_MODEL(store), &iter); - gtk_tree_model_rows_reordered(GTK_TREE_MODEL(store), path, &iter, new_order); - if (path) - gtk_tree_path_free(path); - g_free(new_order); - g_array_free(sort_array, TRUE); -} - -static void -esss_init(EStorageSetStore *store) -{ - store->priv = g_new0(EStorageSetStorePrivate, 1); - - store->priv->storage_set = NULL; - store->priv->checkboxes = NULL; - store->priv->root = g_node_new(NULL); - do { - store->priv->stamp = g_random_int(); - } while (store->priv->stamp == 0); - - store->priv->path_to_node = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - store->priv->type_name_to_pixbuf = g_hash_table_new (g_str_hash, g_str_equal); -} - -static void -esss_dispose(GObject *object) -{ - EStorageSetStore *store = E_STORAGE_SET_STORE(object); - - if (store->priv->storage_set) - g_object_unref(store->priv->storage_set); - store->priv->storage_set = NULL; - - (*parent_class->dispose) (object); -} - -static void -node_free (GNode *node, gpointer data) -{ - g_free (node->data); -} - -static void -pixbuf_free_func (gpointer key, gpointer value, gpointer user_data) -{ - g_free (key); - g_object_unref (value); -} - -static void -esss_finalize(GObject *object) -{ - EStorageSetStore *store = E_STORAGE_SET_STORE(object); - - g_node_children_foreach(store->priv->root, G_TRAVERSE_ALL, node_free, NULL); - - g_hash_table_foreach (store->priv->type_name_to_pixbuf, pixbuf_free_func, NULL); - g_hash_table_destroy (store->priv->type_name_to_pixbuf); - g_hash_table_destroy (store->priv->path_to_node); - if (store->priv->checkboxes) - g_hash_table_destroy (store->priv->checkboxes); - - g_free (store->priv); - - (*parent_class->finalize) (object); -} - -static void -esss_class_init(EStorageSetStoreClass *class) -{ - GObjectClass *object_class; - - parent_class = g_type_class_peek_parent(class); - object_class = (GObjectClass *) class; - - object_class->dispose = esss_dispose; - object_class->finalize = esss_finalize; -} - -GType -e_storage_set_store_get_type(void) -{ - static GType store_type = 0; - - if (!store_type) { - static const GTypeInfo store_info = { - sizeof(EStorageSetStoreClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) esss_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(EStorageSetStore), - 0, /* n_preallocs */ - (GInstanceInitFunc) esss_init - }; - - static const GInterfaceInfo tree_model_info = { - (GInterfaceInitFunc) - esss_tree_model_init, - NULL, - NULL - }; - - static const GInterfaceInfo drag_source_info = { - (GInterfaceInitFunc) - esss_drag_source_init, - NULL, - NULL - }; - - static const GInterfaceInfo drag_dest_info = { - (GInterfaceInitFunc) esss_drag_dest_init, - NULL, - NULL - }; - - store_type = g_type_register_static(G_TYPE_OBJECT, "EStorageSetStore", &store_info, 0); - - g_type_add_interface_static(store_type, GTK_TYPE_TREE_MODEL, &tree_model_info); - g_type_add_interface_static(store_type, GTK_TYPE_TREE_DRAG_SOURCE, &drag_source_info); - g_type_add_interface_static(store_type, GTK_TYPE_TREE_DRAG_DEST, &drag_dest_info); - } - - return store_type; -} - -/* Handling of the "changed" signal in EFolders displayed in the EStorageSetStore. */ - -typedef struct { - EStorageSetStore *store; - GNode * node; -} FolderChangedCallbackData; - -static void -folder_changed_cb (EFolder *folder, void *data) -{ - FolderChangedCallbackData *callback_data; - GtkTreePath *path; - GtkTreeIter iter; - - callback_data = (FolderChangedCallbackData *) data; - iter.user_data = callback_data->node; - iter.stamp = callback_data->store->priv->stamp; - path = esss_get_path (GTK_TREE_MODEL (callback_data->store), &iter); - - gtk_tree_model_row_changed (GTK_TREE_MODEL (callback_data->store), path, &iter); - if (path) - gtk_tree_path_free (path); -} - -static void -folder_name_changed_cb (EFolder *folder, void *data) -{ - FolderChangedCallbackData *callback_data; - - callback_data = (FolderChangedCallbackData *) data; - - esss_sort (callback_data->store, callback_data->node->parent, folder_sort_callback); -} - -static void -setup_folder_changed_callbacks (EStorageSetStore *store, EFolder *folder, GNode *node) -{ - FolderChangedCallbackData *callback_data = g_new0 (FolderChangedCallbackData, 1); - callback_data->store = store; - callback_data->node = node; - - g_signal_connect (G_OBJECT (folder), "changed", - G_CALLBACK (folder_changed_cb), callback_data); - - g_signal_connect_data (G_OBJECT (folder), "name_changed", - G_CALLBACK (folder_name_changed_cb), - callback_data, (GClosureNotify)g_free, 0); -} - -static void -insert_folders (EStorageSetStore *store, GNode *parent, EStorage *storage, const gchar *path) -{ - EStorageSetStorePrivate *priv; - GList *folder_path_list, *p; - const gchar *storage_name = e_storage_get_name (storage); - - priv = store->priv; - - folder_path_list = e_storage_get_subfolder_paths (storage, path); - if (folder_path_list == NULL) - return; - - for (p = folder_path_list; p != NULL; p = p->next) { - EFolder *folder; - const char *subpath = (const char *) p->data; - char *folder_path = g_strconcat ("/", storage_name, subpath, NULL); - gchar *key = g_strdup (folder_path+1); - GNode *node = g_node_new (folder_path); - - g_node_append (parent, node); - g_hash_table_replace (priv->path_to_node, key, node); - - folder = e_storage_get_folder (storage, subpath); - setup_folder_changed_callbacks (store, folder, node); - - insert_folders (store, node, storage, subpath); - } - - esss_sort (store, parent, folder_sort_callback); - - e_free_string_list (folder_path_list); -} - -/* StorageSet signal handling. */ - -static void -new_storage_cb (EStorageSet *storage_set, EStorage *storage, void *data) -{ - EStorageSetStore *store = E_STORAGE_SET_STORE (data); - EStorageSetStorePrivate *priv = store->priv; - gchar *storage_name = g_strdup (e_storage_get_name (storage)); - GNode *node = g_node_new (g_strdup (e_storage_get_name (storage))); - GtkTreePath *path; - GtkTreeIter iter; - - g_hash_table_replace (priv->path_to_node, storage_name, node); - g_node_append (priv->root, node); - esss_sort (store, priv->root, storage_sort_callback); - - iter.user_data = node; - iter.stamp = store->priv->stamp; - path = esss_get_path (GTK_TREE_MODEL (store), &iter); - gtk_tree_model_row_inserted (GTK_TREE_MODEL (store), path, &iter); - if (path) - gtk_tree_path_free (path); -} - -static void -removed_storage_cb (EStorageSet *storage_set, EStorage *storage, void *data) -{ - EStorageSetStore *store = E_STORAGE_SET_STORE (data); - EStorageSetStorePrivate *priv = store->priv; - const gchar *name = e_storage_get_name (storage); - GNode *node = g_hash_table_lookup (priv->path_to_node, name); - GtkTreePath *path; - - if (node == NULL) { - g_warning ("EStorageSetStore: unknown storage removed -- %s", name); - return; - } - - g_hash_table_remove (priv->path_to_node, name); - /* FIXME: subfolder hashtable entries might be leaked */ - - path = tree_path_from_node (store, node); - gtk_tree_model_row_deleted (GTK_TREE_MODEL (store), path); - if (path) - gtk_tree_path_free (path); - g_node_destroy (node); -} - -static void -new_folder_cb (EStorageSet *storage_set, const char *path, void *data) -{ - EStorageSetStore *store = E_STORAGE_SET_STORE (data); - EStorageSetStorePrivate *priv = store->priv; - GNode *parent_node, *new_node; - const char *last_separator; - char *parent_path; - char *copy_of_path; - GtkTreeIter iter; - GtkTreePath *treepath; - - last_separator = strrchr (path, E_PATH_SEPARATOR); - - parent_path = g_strndup (path + 1, last_separator - path - 1); - parent_node = g_hash_table_lookup (priv->path_to_node, parent_path); - g_free (parent_path); - if (parent_node == NULL) { - g_warning ("EStorageSetStore: EStorageSet reported new subfolder for non-existing folder -- %s", parent_path); - return; - } - - copy_of_path = g_strdup (path); - new_node = g_node_new (copy_of_path); - g_node_append (parent_node, new_node); - iter.user_data = new_node; - iter.stamp = priv->stamp; - treepath = esss_get_path (GTK_TREE_MODEL (store), &iter); - gtk_tree_model_row_inserted (GTK_TREE_MODEL (store), treepath, &iter); - if (treepath) - gtk_tree_path_free (treepath); - - g_hash_table_replace (priv->path_to_node, g_strdup (path + 1), new_node); - - setup_folder_changed_callbacks (store, e_storage_set_get_folder (storage_set, path), new_node); - esss_sort (store, parent_node, folder_sort_callback); -} - -static void -updated_folder_cb (EStorageSet *storage_set, const char *path, void *data) -{ - EStorageSetStore *store = E_STORAGE_SET_STORE (data); - EStorageSetStorePrivate *priv = store->priv; - GNode *node; - GtkTreeIter iter; - GtkTreePath *treepath; - - node = g_hash_table_lookup (priv->path_to_node, path+1); - if (node == NULL) { - g_warning ("EStorageSetStore: unknown folder updated -- %s", path); - return; - } - - iter.user_data = node; - iter.stamp = priv->stamp; - treepath = esss_get_path (GTK_TREE_MODEL (store), &iter); - gtk_tree_model_row_changed (GTK_TREE_MODEL (store), treepath, &iter); - if (treepath) - gtk_tree_path_free (treepath); -} - -static void -removed_folder_cb (EStorageSet *storage_set, const char *path, void *data) -{ - EStorageSetStore *store = E_STORAGE_SET_STORE (data); - EStorageSetStorePrivate *priv = store->priv; - GNode *node; - GtkTreePath *treepath; - - node = g_hash_table_lookup (priv->path_to_node, path+1); - if (node == NULL) { - g_warning ("EStorageSetStore: unknown folder removed -- %s", path); - return; - } - - g_hash_table_remove (priv->path_to_node, path+1); - /* FIXME: subfolder hashtable entries might be leaked */ - - treepath = tree_path_from_node (store, node); - gtk_tree_model_row_deleted (GTK_TREE_MODEL (store), treepath); - if (treepath) - gtk_tree_path_free (treepath); - g_node_destroy (node); -} - -static void -close_folder_cb (EStorageSet *storage_set, - const char *path, - void *data) -{ - g_warning ("FIXME: EStorageSetStore: needs to handle close_folder properly"); -#if 0 - EStorageSetStore *store; - EStorageSetStorePrivate *priv; - ETreeModel *etree; - ETreePath node; - - store = E_STORAGE_SET_STORE (data); - priv = store->priv; - etree = priv->etree_model; - - node = lookup_node_in_hash (store, path); - e_tree_model_node_request_collapse (priv->etree_model, node); -#endif -} - -static void -connect_storage_set (EStorageSetStore *store, EStorageSet *storage_set, gboolean show_folders) -{ - EStorageSetStorePrivate *priv; - GList *storage_list; - GList *p; - - priv = store->priv; - priv->storage_set = storage_set; - g_object_ref (storage_set); - - storage_list = e_storage_set_get_storage_list (storage_set); - - for (p = storage_list; p != NULL; p = p->next) { - EStorage *storage = E_STORAGE (p->data); - const char *name = e_storage_get_name (storage); - GNode *node = g_node_new (g_strdup (name)); - g_node_append (priv->root, node); - g_hash_table_replace (priv->path_to_node, g_strdup (name), node); - - if (show_folders) - insert_folders (store, node, storage, "/"); - } - - esss_sort (store, priv->root, storage_sort_callback); - - e_free_object_list (storage_list); - - g_signal_connect_object (storage_set, "new_storage", G_CALLBACK (new_storage_cb), store, 0); - g_signal_connect_object (storage_set, "removed_storage", G_CALLBACK (removed_storage_cb), store, 0); - if (!show_folders) - return; - - g_signal_connect_object (storage_set, "new_folder", G_CALLBACK (new_folder_cb), store, 0); - g_signal_connect_object (storage_set, "updated_folder", G_CALLBACK (updated_folder_cb), store, 0); - g_signal_connect_object (storage_set, "removed_folder", G_CALLBACK (removed_folder_cb), store, 0); - g_signal_connect_object (storage_set, "close_folder", G_CALLBACK (close_folder_cb), store, 0); -} - -/** - * e_storage_set_store_new: - * @storage_set: the #EStorageSet that the store exposes - * @show_folders: flag indicating if subfolders should be shown - * - * Creates a new tree store from the provided #EStorageSet. - * - * Return value: a new #EStorageSetStore - **/ -EStorageSetStore * -e_storage_set_store_new(EStorageSet *storage_set, gboolean show_folders) -{ - EStorageSetStore *store; - g_return_val_if_fail (E_IS_STORAGE_SET(storage_set), NULL); - - store = E_STORAGE_SET_STORE (g_object_new (E_STORAGE_SET_STORE_TYPE, NULL)); - connect_storage_set (store, storage_set, show_folders); - - return store; -} - -static gboolean -esss_real_set_value(EStorageSetStore *store, GtkTreeIter *iter, gint column, GValue *value) -{ - gchar *path; - - if (column != E_STORAGE_SET_STORE_COLUMN_CHECKED) - return FALSE; - - path = G_NODE (iter->user_data)->data; - - if (g_value_get_boolean (value)) { - g_hash_table_insert (store->priv->checkboxes, path, path); - } else { - g_hash_table_remove (store->priv->checkboxes, path); - } - - return TRUE; -} - -/** - * e_storage_set_store_set_value: - * @store: a #EStorageSetStore - * @iter: A valid #GtkTreeIter for the row being modified - * @column: column number to modify - * @value: new value for the cell - * - * Sets the data in the cell specified by @iter and @column. - * The type of @value must be convertible to the type of the - * column. - * - **/ -void -e_storage_set_store_set_value(EStorageSetStore *store, GtkTreeIter *iter, - gint column, GValue *value) -{ - g_return_if_fail(E_IS_STORAGE_SET_STORE(store)); - g_return_if_fail(VALID_ITER(iter, store)); - g_return_if_fail(VALID_COL(column)); - g_return_if_fail(G_IS_VALUE(value)); - - if (esss_real_set_value (store, iter, column, value)) { - GtkTreePath *path; - - path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), iter); - gtk_tree_model_row_changed(GTK_TREE_MODEL(store), path, iter); - if (path) - gtk_tree_path_free(path); - } -} - -/** - * e_storage_set_store_get_tree_path: - * @store: a #EStorageSetStore - * @folder_path: a string representing the #EStorageSet folder path - * - * Gets a #GtkTreePath corresponding to the folder path specified. - * - * Return value: the tree path of the folder - **/ -GtkTreePath * -e_storage_set_store_get_tree_path (EStorageSetStore *store, const gchar *folder_path) -{ - GNode *node; - - g_return_if_fail(E_IS_STORAGE_SET_STORE(store)); - - node = g_hash_table_lookup (store->priv->path_to_node, folder_path+1); - - return tree_path_from_node (store, node); -} - -/** - * e_storage_set_store_get_folder_path: - * @store: a #EStorageSetStore - * @folder_path: a string representing the #EStorageSet folder path - * - * Gets a #GtkTreePath corresponding to the folder path specified. - * - * Return value: the tree path of the folder - **/ -const gchar * -e_storage_set_store_get_folder_path (EStorageSetStore *store, GtkTreePath *tree_path) -{ - GtkTreeIter iter; - GNode *node; - - g_return_if_fail(E_IS_STORAGE_SET_STORE(store)); - - if (!esss_get_iter (GTK_TREE_MODEL (store), &iter, tree_path)) - return NULL; - - node = G_NODE (iter.user_data); - - return (const gchar *)node->data; -} - -/** - * e_storage_set_store_set_has_checkbox_func: - * @store: a #EStorageSetStore - * @func: a callback to determine if a row is checked - * @data: callback data - * - * Sets a callback function for checkbox visibility determination - **/ -void -e_storage_set_store_set_has_checkbox_func (EStorageSetStore *store, EStorageSetStoreHasCheckBoxFunc func, gpointer data) -{ - g_return_if_fail(E_IS_STORAGE_SET_STORE(store)); - - store->priv->has_checkbox_func = func; - store->priv->has_checkbox_func_data = data; -} - |