aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--shell/e-storage-set-store.c1361
-rw-r--r--shell/e-storage-set-store.h91
2 files changed, 1452 insertions, 0 deletions
diff --git a/shell/e-storage-set-store.c b/shell/e-storage-set-store.c
new file mode 100644
index 0000000000..e2816d87d2
--- /dev/null
+++ b/shell/e-storage-set-store.c
@@ -0,0 +1,1361 @@
+/* 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;
+}
+
diff --git a/shell/e-storage-set-store.h b/shell/e-storage-set-store.h
new file mode 100644
index 0000000000..251b61e519
--- /dev/null
+++ b/shell/e-storage-set-store.h
@@ -0,0 +1,91 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-storage-set-store.h
+ *
+ * Copyright (C) 2002 Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Mike Kestner
+ */
+
+#ifndef __E_STORAGE_SET_STORE_H__
+#define __E_STORAGE_SET_STORE_H__
+
+#include <gtk/gtktreemodel.h>
+#include "e-storage-set.h"
+#include "e-storage-set-store.h"
+
+G_BEGIN_DECLS
+
+#define E_STORAGE_SET_STORE_TYPE (e_storage_set_store_get_type ())
+#define E_STORAGE_SET_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_STORAGE_SET_STORE_TYPE, EStorageSetStore))
+#define E_STORAGE_SET_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_STORAGE_SET_STORE_TYPE, EStorageSetStoreClass))
+#define E_IS_STORAGE_SET_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_STORAGE_SET_STORE_TYPE))
+#define E_IS_STORAGE_SET_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_STORAGE_SET_STORE_TYPE))
+#define E_STORAGE_SET_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_STORAGE_SET_STORE_TYPE, EStorageSetStoreClass))
+
+typedef gboolean (* EStorageSetStoreHasCheckBoxFunc) (EStorageSet *storage_set,
+ const char *path,
+ void *data);
+
+typedef enum {
+ E_STORAGE_SET_STORE_COLUMN_NAME,
+ E_STORAGE_SET_STORE_COLUMN_HIGHLIGHT,
+ E_STORAGE_SET_STORE_COLUMN_CHECKED,
+ E_STORAGE_SET_STORE_COLUMN_CHECKABLE,
+ E_STORAGE_SET_STORE_COLUMN_ICON,
+ E_STORAGE_SET_STORE_COLUMN_COUNT
+} E_STORAGE_SET_STORE_COLUMN_TYPE;
+
+typedef struct _EStorageSetStore EStorageSetStore;
+typedef struct _EStorageSetStorePrivate EStorageSetStorePrivate;
+typedef struct _EStorageSetStoreClass EStorageSetStoreClass;
+
+struct _EStorageSetStore {
+ GObject parent;
+
+ EStorageSetStorePrivate *priv;
+};
+
+struct _EStorageSetStoreClass {
+ GObjectClass parent_class;
+};
+
+
+GType e_storage_set_store_get_type (void);
+
+EStorageSetStore *e_storage_set_store_new (EStorageSet *storage_set, gboolean show_folders);
+
+EStorageSet *e_storage_set_store_get_storage_set (EStorageSetStore *storage_set_store);
+
+void e_storage_set_store_set_checkboxes_list (EStorageSetStore *storage_set_store,
+ GSList *checkboxes);
+GSList *e_storage_set_store_get_checkboxes_list (EStorageSetStore *storage_set_store);
+
+void e_storage_set_store_set_allow_dnd (EStorageSetStore *storage_set_store,
+ gboolean allow_dnd);
+gboolean e_storage_set_store_get_allow_dnd (EStorageSetStore *storage_set_store);
+
+GtkTreePath *e_storage_set_store_get_tree_path (EStorageSetStore *store, const gchar *folder_path);
+
+const gchar *e_storage_set_store_get_folder_path (EStorageSetStore *store, GtkTreePath *tree_path);
+
+void e_storage_set_store_set_has_checkbox_func (EStorageSetStore *storage_set_store,
+ EStorageSetStoreHasCheckBoxFunc func,
+ gpointer data);
+
+G_END_DECLS
+
+#endif /* __E_STORAGE_SET_STORE_H__ */