Files
evolution/mail/subscribe-dialog.c
Jeffrey Stedfast 93c8da913b Check for a NULL service->url as we obviously can't subscribe to folders
2001-01-26  Jeffrey Stedfast  <fejj@ximian.com>

	* subscribe-dialog.c (populate_store_foreach): Check for a NULL
	service->url as we obviously can't subscribe to folders on a
	non-existant mail source :-)
	(subscribe_do_get_store): Check for a NULL url here too, not that
	we should need it anymore (due to the above fix) but it doesn't
	hurt. Also, should we wait on the thread? Probably doesn't matter.

svn path=/trunk/; revision=7844
2001-01-27 03:13:30 +00:00

1140 lines
30 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* subscribe-dialog.c: Subscribe dialog */
/*
* Authors: Chris Toshok <toshok@helixcode.com>
*
* Copyright 2000 Helix Code, Inc. (www.helixcode.com)
*
* 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.
*
* 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 Street #330, Boston, MA 02111-1307, USA.
*
*/
#include <config.h>
#include <gnome.h>
#include "subscribe-dialog.h"
#include "e-util/e-html-utils.h"
#include <gtkhtml/gtkhtml.h>
#include <gal/util/e-util.h>
#include <gal/widgets/e-unicode.h>
#include <gal/e-table/e-cell-toggle.h>
#include <gal/e-table/e-cell-text.h>
#include <gal/e-table/e-cell-tree.h>
#include <gal/e-table/e-table-scrolled.h>
#include <gal/e-table/e-tree-simple.h>
#include <gal/e-paned/e-hpaned.h>
#include <bonobo/bonobo-main.h>
#include <bonobo/bonobo-object.h>
#include <bonobo/bonobo-generic-factory.h>
#include <bonobo/bonobo-control.h>
#include <bonobo/bonobo-ui-component.h>
#include <bonobo/bonobo-ui-util.h>
#include <bonobo/bonobo-widget.h>
#include "mail.h"
#include "mail-tools.h"
#include "mail-threads.h"
#include "camel/camel.h"
#include "art/empty.xpm"
#include "art/mark.xpm"
#define DEFAULT_STORE_TABLE_WIDTH 200
#define DEFAULT_WIDTH 500
#define DEFAULT_HEIGHT 300
#define PARENT_TYPE (gtk_object_get_type ())
#ifdef JUST_FOR_TRANSLATORS
static char *list [] = {
N_("Folder"),
N_("Store"),
};
#endif
#define FOLDER_ETABLE_SPEC "<ETableSpecification cursor-mode=\"line\"> \
<ETableColumn model_col=\"0\" pixbuf=\"subscribed-image\" expansion=\"0.0\" minimum_width=\"16\" resizable=\"false\" cell=\"cell_toggle\" compare=\"integer\"/> \
<ETableColumn model_col=\"1\" _title=\"Folder\" expansion=\"1.0\" minimum_width=\"20\" resizable=\"true\" cell=\"cell_tree\" compare=\"string\"/> \
<ETableState> \
<column source=\"0\"/> \
<column source=\"1\"/> \
<grouping></grouping> \
</ETableState> \
</ETableSpecification>"
#define STORE_ETABLE_SPEC "<ETableSpecification cursor-mode=\"line\"> \
<ETableColumn model_col=\"0\" _title=\"Store\" expansion=\"1.0\" minimum_width=\"20\" resizable=\"true\" cell=\"string\" compare=\"string\"/> \
<ETableState> \
<column source=\"0\"/> \
<grouping></grouping> \
</ETableState> \
</ETableSpecification>"
enum {
FOLDER_COL_SUBSCRIBED,
FOLDER_COL_NAME,
FOLDER_COL_LAST
};
enum {
STORE_COL_NAME,
STORE_COL_LAST
};
static GtkObjectClass *subscribe_dialog_parent_class;
static void build_tree (SubscribeDialog *sc, CamelStore *store);
static void
set_pixmap (BonoboUIComponent *component,
const char *xml_path,
const char *icon)
{
char *path;
GdkPixbuf *pixbuf;
path = g_concat_dir_and_file (EVOLUTION_DATADIR "/images/evolution/buttons", icon);
pixbuf = gdk_pixbuf_new_from_file (path);
g_return_if_fail (pixbuf != NULL);
bonobo_ui_util_set_pixbuf (component, xml_path, pixbuf);
gdk_pixbuf_unref (pixbuf);
g_free (path);
}
static void
update_pixmaps (BonoboUIComponent *component)
{
set_pixmap (component, "/Toolbar/SubscribeFolder", "fetch-mail.png"); /* XXX */
set_pixmap (component, "/Toolbar/UnsubscribeFolder", "compose-message.png"); /* XXX */
set_pixmap (component, "/Toolbar/RefreshList", "forward.png"); /* XXX */
}
static GtkWidget*
make_folder_search_widget (GtkSignalFunc start_search_func,
gpointer user_data_for_search)
{
SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data_for_search);
GtkWidget *search_hbox = gtk_hbox_new (FALSE, 0);
sc->search_entry = gtk_entry_new ();
if (start_search_func) {
gtk_signal_connect (GTK_OBJECT (sc->search_entry), "activate",
start_search_func,
user_data_for_search);
}
/* add the search entry to the our search_vbox */
gtk_box_pack_start (GTK_BOX (search_hbox),
gtk_label_new(_("Display folders starting with:")),
FALSE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (search_hbox), sc->search_entry,
FALSE, TRUE, 3);
return search_hbox;
}
/* Our async operations */
typedef void (*SubscribeGetStoreCallback)(SubscribeDialog *sc, CamelStore *store, gpointer cb_data);
typedef void (*SubscribeFolderCallback)(SubscribeDialog *sc, gboolean success, gpointer cb_data);
/* ** GET STORE ******************************************************* */
typedef struct get_store_input_s {
SubscribeDialog *sc;
gchar *url;
SubscribeGetStoreCallback cb;
gpointer cb_data;
} get_store_input_t;
typedef struct get_store_data_s {
CamelStore *store;
} get_store_data_t;
static gchar *
describe_get_store (gpointer in_data, gboolean gerund)
{
get_store_input_t *input = (get_store_input_t *) in_data;
if (gerund) {
return g_strdup_printf (_("Getting store for \"%s\""), input->url);
}
else {
return g_strdup_printf (_("Get store for \"%s\""), input->url);
}
}
static void
setup_get_store (gpointer in_data, gpointer op_data, CamelException *ex)
{
}
static void
do_get_store (gpointer in_data, gpointer op_data, CamelException *ex)
{
get_store_input_t *input = (get_store_input_t *)in_data;
get_store_data_t *data = (get_store_data_t*)op_data;
mail_tool_camel_lock_up ();
data->store = camel_session_get_store (session, input->url, ex);
mail_tool_camel_lock_down ();
if (camel_exception_is_set (ex))
data->store = NULL;
}
static void
cleanup_get_store (gpointer in_data, gpointer op_data, CamelException *ex)
{
get_store_input_t *input = (get_store_input_t *)in_data;
get_store_data_t *data = (get_store_data_t*)op_data;
input->cb (input->sc, data->store, input->cb_data);
g_free (input->url);
}
static const mail_operation_spec op_get_store = {
describe_get_store,
sizeof (get_store_data_t),
setup_get_store,
do_get_store,
cleanup_get_store
};
static void
subscribe_do_get_store (SubscribeDialog *sc, const char *url, SubscribeGetStoreCallback cb, gpointer cb_data)
{
get_store_input_t *input;
g_return_if_fail (url != NULL);
input = g_new (get_store_input_t, 1);
input->sc = sc;
input->url = g_strdup (url);
input->cb = cb;
input->cb_data = cb_data;
mail_operation_queue (&op_get_store, input, TRUE);
mail_operation_wait_for_finish ();
}
/* ** SUBSCRIBE FOLDER ******************************************************* */
/* Given a CamelFolderInfo, construct the corresponding
* EvolutionStorage path to it.
*/
static char *
storage_tree_path (CamelFolderInfo *info)
{
int len;
CamelFolderInfo *i;
char *path, *p;
for (len = 0, i = info; i; i = i->parent)
len += strlen (i->name) + 1;
/* We do this backwards because that's the way the pointers point. */
path = g_malloc (len + 1);
p = path + len;
*p = '\0';
for (i = info; i; i = i->parent) {
len = strlen (i->name);
p -= len;
memcpy (p, i->name, len);
*--p = '/';
}
return path;
}
typedef struct subscribe_folder_input_s {
SubscribeDialog *sc;
CamelStore *store;
CamelFolderInfo *info;
gboolean subscribe;
SubscribeFolderCallback cb;
gpointer cb_data;
} subscribe_folder_input_t;
typedef struct subscribe_folder_data_s {
char *path;
char *name;
char *full_name;
char *url;
} subscribe_folder_data_t;
static gchar *
describe_subscribe_folder (gpointer in_data, gboolean gerund)
{
subscribe_folder_input_t *input = (subscribe_folder_input_t *) in_data;
if (gerund) {
if (input->subscribe)
return g_strdup_printf
(_("Subscribing to folder \"%s\""),
input->info->name);
else
return g_strdup_printf
(_("Unsubscribing from folder \"%s\""),
input->info->name);
} else {
if (input->subscribe)
return g_strdup_printf (_("Subscribe to folder \"%s\""),
input->info->name);
else
return g_strdup_printf (_("Unsubscribe from folder \"%s\""),
input->info->name);
}
}
static void
setup_subscribe_folder (gpointer in_data, gpointer op_data, CamelException *ex)
{
subscribe_folder_input_t *input = (subscribe_folder_input_t *) in_data;
subscribe_folder_data_t *data = (subscribe_folder_data_t *) op_data;
data->path = storage_tree_path (input->info);
data->name = g_strdup (input->info->name);
data->full_name = g_strdup (input->info->full_name);
data->url = g_strdup (input->info->url);
camel_object_ref (CAMEL_OBJECT (input->store));
gtk_object_ref (GTK_OBJECT (input->sc));
}
static void
do_subscribe_folder (gpointer in_data, gpointer op_data, CamelException *ex)
{
subscribe_folder_input_t *input = (subscribe_folder_input_t *) in_data;
subscribe_folder_data_t *data = (subscribe_folder_data_t *) op_data;
mail_tool_camel_lock_up ();
if (input->subscribe)
camel_store_subscribe_folder (input->store, data->full_name, ex);
else
camel_store_unsubscribe_folder (input->store, data->full_name, ex);
mail_tool_camel_lock_down ();
}
static void
recursive_add_folder (EvolutionStorage *storage, const char *path,
const char *name, const char *url)
{
char *parent, *pname, *p;
p = strrchr (path, '/');
if (p && p != path) {
parent = g_strndup (path, p - path);
if (!evolution_storage_folder_exists (storage, parent)) {
p = strrchr (parent, '/');
if (p)
pname = g_strdup (p + 1);
else
pname = g_strdup ("");
recursive_add_folder (storage, parent, pname, "");
g_free (pname);
}
g_free (parent);
}
evolution_storage_new_folder (storage, path, name, "mail", url,
_("(No description)"), FALSE);
}
static void
cleanup_subscribe_folder (gpointer in_data, gpointer op_data,
CamelException *ex)
{
subscribe_folder_input_t *input = (subscribe_folder_input_t *) in_data;
subscribe_folder_data_t *data = (subscribe_folder_data_t *) op_data;
if (!camel_exception_is_set (ex)) {
if (input->subscribe)
recursive_add_folder (input->sc->storage,
data->path, data->name,
data->url);
else
evolution_storage_removed_folder (input->sc->storage, data->path);
}
if (input->cb)
input->cb (input->sc, !camel_exception_is_set (ex), input->cb_data);
g_free (data->path);
g_free (data->name);
g_free (data->full_name);
g_free (data->url);
camel_object_unref (CAMEL_OBJECT (input->store));
gtk_object_unref (GTK_OBJECT (input->sc));
}
static const mail_operation_spec op_subscribe_folder = {
describe_subscribe_folder,
sizeof (subscribe_folder_data_t),
setup_subscribe_folder,
do_subscribe_folder,
cleanup_subscribe_folder
};
static void
subscribe_do_subscribe_folder (SubscribeDialog *sc, CamelStore *store, CamelFolderInfo *info,
gboolean subscribe, SubscribeFolderCallback cb, gpointer cb_data)
{
subscribe_folder_input_t *input;
g_return_if_fail (CAMEL_IS_STORE (store));
g_return_if_fail (info);
input = g_new (subscribe_folder_input_t, 1);
input->sc = sc;
input->store = store;
input->info = info;
input->subscribe = subscribe;
input->cb = cb;
input->cb_data = cb_data;
mail_operation_queue (&op_subscribe_folder, input, TRUE);
}
static gboolean
folder_info_subscribed (SubscribeDialog *sc, CamelFolderInfo *info)
{
return camel_store_folder_subscribed (sc->store, info->full_name);
}
static void
node_changed_cb (SubscribeDialog *sc, gboolean changed, gpointer data)
{
ETreePath *node = data;
if (changed)
e_tree_model_node_changed (sc->folder_model, node);
}
static void
subscribe_folder_info (SubscribeDialog *sc, CamelFolderInfo *info, ETreePath *node)
{
/* folders without urls cannot be subscribed to */
if (info->url == NULL)
return;
subscribe_do_subscribe_folder (sc, sc->store, info, TRUE, node_changed_cb, node);
}
static void
unsubscribe_folder_info (SubscribeDialog *sc, CamelFolderInfo *info, ETreePath *node)
{
/* folders without urls cannot be subscribed to */
if (info->url == NULL)
return;
subscribe_do_subscribe_folder (sc, sc->store, info, FALSE, node_changed_cb, node);
}
static void
subscribe_close (BonoboUIComponent *uic,
void *user_data, const char *path)
{
SubscribeDialog *sc = (SubscribeDialog*)user_data;
gtk_widget_destroy (sc->app);
}
static void
subscribe_select_all (BonoboUIComponent *uic,
void *user_data, const char *path)
{
SubscribeDialog *sc = (SubscribeDialog*)user_data;
ETableScrolled *scrolled = E_TABLE_SCROLLED (sc->folder_etable);
e_table_select_all (scrolled->table);
}
static void
subscribe_invert_selection (BonoboUIComponent *uic,
void *user_data, const char *path)
{
SubscribeDialog *sc = (SubscribeDialog*)user_data;
ETableScrolled *scrolled = E_TABLE_SCROLLED (sc->folder_etable);
e_table_invert_selection (scrolled->table);
}
static void
subscribe_folder_foreach (int model_row, gpointer closure)
{
SubscribeDialog *sc = SUBSCRIBE_DIALOG (closure);
ETreePath *node = e_tree_model_node_at_row (sc->folder_model, model_row);
CamelFolderInfo *info = e_tree_model_node_get_data (sc->folder_model, node);
if (!folder_info_subscribed (sc, info))
subscribe_folder_info (sc, info, node);
}
static void
subscribe_folders (BonoboUIComponent *componet, gpointer user_data, const char *cname)
{
SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
e_table_selected_row_foreach (E_TABLE_SCROLLED(sc->folder_etable)->table,
subscribe_folder_foreach, sc);
}
static void
unsubscribe_folder_foreach (int model_row, gpointer closure)
{
SubscribeDialog *sc = SUBSCRIBE_DIALOG (closure);
ETreePath *node = e_tree_model_node_at_row (sc->folder_model, model_row);
CamelFolderInfo *info = e_tree_model_node_get_data (sc->folder_model, node);
if (folder_info_subscribed(sc, info))
unsubscribe_folder_info (sc, info, node);
}
static void
unsubscribe_folders (BonoboUIComponent *component, gpointer user_data, const char *cname)
{
SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
e_table_selected_row_foreach (E_TABLE_SCROLLED(sc->folder_etable)->table,
unsubscribe_folder_foreach, sc);
}
static void
subscribe_refresh_list (BonoboUIComponent *component, gpointer user_data, const char *cname)
{
SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
e_utf8_gtk_entry_set_text (GTK_ENTRY (sc->search_entry), "");
if (sc->search_top) {
g_free (sc->search_top);
sc->search_top = NULL;
}
if (sc->store)
build_tree (sc, sc->store);
}
static void
subscribe_search (GtkWidget *widget, gpointer user_data)
{
SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
char* search_pattern = e_utf8_gtk_entry_get_text(GTK_ENTRY(widget));
if (sc->search_top) {
g_free (sc->search_top);
sc->search_top = NULL;
}
if (search_pattern && *search_pattern)
sc->search_top = search_pattern;
if (sc->store)
build_tree (sc, sc->store);
}
#if 0
/* HTML Helpers */
static void
html_size_req (GtkWidget *widget, GtkRequisition *requisition)
{
if (GTK_LAYOUT (widget)->height > 90)
requisition->height = 90;
else
requisition->height = GTK_LAYOUT (widget)->height;
}
/* Returns a GtkHTML which is already inside a GtkScrolledWindow. If
* @white is TRUE, the GtkScrolledWindow will be inside a GtkFrame.
*/
static GtkWidget *
html_new (gboolean white)
{
GtkWidget *html, *scrolled, *frame;
GtkStyle *style;
html = gtk_html_new ();
GTK_LAYOUT (html)->height = 0;
gtk_signal_connect (GTK_OBJECT (html), "size_request",
GTK_SIGNAL_FUNC (html_size_req), NULL);
gtk_html_set_editable (GTK_HTML (html), FALSE);
style = gtk_rc_get_style (html);
if (style) {
gtk_html_set_default_background_color (GTK_HTML (html),
white ? &style->white :
&style->bg[0]);
}
gtk_widget_set_sensitive (html, FALSE);
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_NEVER,
GTK_POLICY_NEVER);
gtk_container_add (GTK_CONTAINER (scrolled), html);
if (white) {
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame),
GTK_SHADOW_ETCHED_IN);
gtk_container_add (GTK_CONTAINER (frame), scrolled);
gtk_widget_show_all (frame);
} else
gtk_widget_show_all (scrolled);
return html;
}
static void
put_html (GtkHTML *html, char *text)
{
GtkHTMLStream *handle;
text = e_text_to_html (text, (E_TEXT_TO_HTML_CONVERT_NL |
E_TEXT_TO_HTML_CONVERT_SPACES |
E_TEXT_TO_HTML_CONVERT_URLS));
handle = gtk_html_begin (html);
gtk_html_write (html, handle, "<HTML><BODY>", 12);
gtk_html_write (html, handle, text, strlen (text));
gtk_html_write (html, handle, "</BODY></HTML>", 14);
g_free (text);
gtk_html_end (html, handle, GTK_HTML_STREAM_OK);
}
#endif
/* etable stuff for the subscribe ui */
static int
folder_etable_col_count (ETableModel *etm, void *data)
{
return FOLDER_COL_LAST;
}
static void*
folder_etable_duplicate_value (ETableModel *etm, int col, const void *val, void *data)
{
return g_strdup (val);
}
static void
folder_etable_free_value (ETableModel *etm, int col, void *val, void *data)
{
g_free (val);
}
static void*
folder_etable_init_value (ETableModel *etm, int col, void *data)
{
return g_strdup ("");
}
static gboolean
folder_etable_value_is_empty (ETableModel *etm, int col, const void *val, void *data)
{
return !(val && *(char *)val);
}
static char*
folder_etable_value_to_string (ETableModel *etm, int col, const void *val, void *data)
{
return g_strdup(val);
}
static GdkPixbuf*
folder_etree_icon_at (ETreeModel *etree, ETreePath *path, void *model_data)
{
return NULL; /* XXX no icons for now */
}
static void*
folder_etree_value_at (ETreeModel *etree, ETreePath *path, int col, void *model_data)
{
SubscribeDialog *dialog = SUBSCRIBE_DIALOG (model_data);
CamelFolderInfo *info = e_tree_model_node_get_data (etree, path);
if (col == FOLDER_COL_NAME) {
return info->name;
}
else /* FOLDER_COL_SUBSCRIBED */ {
/* folders without urls cannot be subscribed to */
if (info->url == NULL)
return GINT_TO_POINTER(0); /* empty */
else if (!folder_info_subscribed(dialog, info))
return GINT_TO_POINTER(0); /* XXX unchecked */
else
return GUINT_TO_POINTER (1); /* checked */
}
}
static void
folder_etree_set_value_at (ETreeModel *etree, ETreePath *path, int col, const void *val, void *model_data)
{
/* nothing */
}
static gboolean
folder_etree_is_editable (ETreeModel *etree, ETreePath *path, int col, void *model_data)
{
return FALSE;
}
static int
store_etable_col_count (ETableModel *etm, void *data)
{
return STORE_COL_LAST;
}
static int
store_etable_row_count (ETableModel *etm, void *data)
{
SubscribeDialog *sc = SUBSCRIBE_DIALOG (data);
return g_list_length (sc->store_list);
}
static void*
store_etable_value_at (ETableModel *etm, int col, int row, void *data)
{
SubscribeDialog *sc = SUBSCRIBE_DIALOG (data);
CamelStore *store = (CamelStore*)g_list_nth_data (sc->store_list, row);
return camel_service_get_name (CAMEL_SERVICE (store), TRUE);
}
static void
store_etable_set_value_at (ETableModel *etm, int col, int row, const void *val, void *data)
{
/* nada */
}
static gboolean
store_etable_is_editable (ETableModel *etm, int col, int row, void *data)
{
return FALSE;
}
static void*
store_etable_duplicate_value (ETableModel *etm, int col, const void *val, void *data)
{
return g_strdup (val);
}
static void
store_etable_free_value (ETableModel *etm, int col, void *val, void *data)
{
g_free (val);
}
static void*
store_etable_initialize_value (ETableModel *etm, int col, void *data)
{
return g_strdup ("");
}
static gboolean
store_etable_value_is_empty (ETableModel *etm, int col, const void *val, void *data)
{
return !(val && *(char *)val);
}
static char*
store_etable_value_to_string (ETableModel *etm, int col, const void *val, void *data)
{
return g_strdup(val);
}
static void
build_etree_from_folder_info (SubscribeDialog *sc, ETreePath *parent, CamelFolderInfo *info)
{
CamelFolderInfo *i;
if (info == NULL)
return;
for (i = info; i; i = i->sibling) {
ETreePath *node = e_tree_model_node_insert (sc->folder_model, parent, -1, i);
build_etree_from_folder_info (sc, node, i->child);
}
}
static void
build_tree (SubscribeDialog *sc, CamelStore *store)
{
CamelException *ex = camel_exception_new();
/* free up the existing CamelFolderInfo* if there is any */
if (sc->folder_info)
camel_store_free_folder_info (sc->store, sc->folder_info);
if (sc->storage)
gtk_object_unref (GTK_OBJECT (sc->storage));
sc->store = store;
sc->storage = mail_lookup_storage (sc->store);
sc->folder_info = camel_store_get_folder_info (sc->store, sc->search_top, TRUE, TRUE, FALSE, ex);
if (camel_exception_is_set (ex)) {
printf ("camel_store_get_folder_info failed\n");
camel_exception_free (ex);
return;
}
e_tree_model_node_remove (sc->folder_model, sc->folder_root);
sc->folder_root = e_tree_model_node_insert (sc->folder_model, NULL,
0, NULL);
build_etree_from_folder_info (sc, sc->folder_root, sc->folder_info);
camel_exception_free (ex);
}
static void
storage_selected_cb (ETable *table, int row, gpointer data)
{
SubscribeDialog *sc = SUBSCRIBE_DIALOG (data);
CamelStore *store = (CamelStore*)g_list_nth_data (sc->store_list, row);
build_tree (sc, store);
}
static void
folder_toggle_cb (ETable *table, int row, int col, GdkEvent *event, gpointer data)
{
SubscribeDialog *sc = SUBSCRIBE_DIALOG (data);
ETreePath *node = e_tree_model_node_at_row (sc->folder_model, row);
CamelFolderInfo *info = e_tree_model_node_get_data (sc->folder_model, node);
if (folder_info_subscribed(sc, info))
unsubscribe_folder_info (sc, info, node);
else
subscribe_folder_info (sc, info, node);
e_tree_model_node_changed (sc->folder_model, node);
}
#define EXAMPLE_DESCR "And the beast shall come forth surrounded by a roiling cloud of vengeance.\n" \
" The house of the unbelievers shall be razed and they shall be scorched to the\n" \
" earth. Their tags shall blink until the end of days. \n" \
" from The Book of Mozilla, 12:10"
static BonoboUIVerb verbs [] = {
/* File Menu */
BONOBO_UI_VERB ("FileCloseWin", subscribe_close),
/* Edit Menu */
BONOBO_UI_VERB ("EditSelectAll", subscribe_select_all),
BONOBO_UI_VERB ("EditInvertSelection", subscribe_invert_selection),
/* Folder Menu / Toolbar */
BONOBO_UI_VERB ("SubscribeFolder", subscribe_folders),
BONOBO_UI_VERB ("UnsubscribeFolder", unsubscribe_folders),
/* Toolbar Specific */
BONOBO_UI_VERB ("RefreshList", subscribe_refresh_list),
BONOBO_UI_VERB_END
};
static void
store_cb (SubscribeDialog *sc, CamelStore *store, gpointer data)
{
if (!store)
return;
if (camel_store_supports_subscriptions (store)) {
sc->store_list = g_list_prepend (sc->store_list, store);
e_table_model_row_inserted (sc->store_model, 0);
} else {
camel_object_unref (CAMEL_OBJECT (store));
}
}
static void
populate_store_foreach (MailConfigService *service, SubscribeDialog *sc)
{
g_return_if_fail (service->url != NULL);
subscribe_do_get_store (sc, service->url, store_cb, NULL);
}
static void
populate_store_list (SubscribeDialog *sc)
{
const GSList *news;
GSList *sources;
sources = mail_config_get_sources ();
g_slist_foreach (sources, (GFunc)populate_store_foreach, sc);
g_slist_free (sources);
news = mail_config_get_news ();
g_slist_foreach ((GSList *)news, (GFunc)populate_store_foreach, sc);
e_table_model_changed (sc->store_model);
}
static void
subscribe_dialog_gui_init (SubscribeDialog *sc)
{
ETableExtras *extras;
ECell *cell;
GdkPixbuf *toggles[2];
BonoboUIComponent *component;
BonoboUIContainer *container;
GtkWidget *folder_search_widget;
BonoboControl *search_control;
CORBA_Environment ev;
CORBA_exception_init (&ev);
/* Construct the app */
sc->app = bonobo_window_new ("subscribe-dialog", "Manage Subscriptions");
/* Build the menu and toolbar */
container = bonobo_ui_container_new ();
bonobo_ui_container_set_win (container, BONOBO_WINDOW (sc->app));
/* set up the bonobo stuff */
component = bonobo_ui_component_new_default ();
bonobo_ui_component_set_container (
component, bonobo_object_corba_objref (BONOBO_OBJECT (container)));
bonobo_ui_component_add_verb_list_with_data (
component, verbs, sc);
bonobo_ui_component_freeze (component, NULL);
bonobo_ui_util_set_ui (component, EVOLUTION_DATADIR,
"evolution-subscribe.xml",
"evolution-subscribe");
update_pixmaps (component);
bonobo_ui_component_thaw (component, NULL);
sc->table = gtk_table_new (1, 2, FALSE);
sc->hpaned = e_hpaned_new ();
folder_search_widget = make_folder_search_widget (subscribe_search, sc);
gtk_widget_show_all (folder_search_widget);
search_control = bonobo_control_new (folder_search_widget);
bonobo_ui_component_object_set (component, "/Toolbar/FolderSearch",
bonobo_object_corba_objref (BONOBO_OBJECT (search_control)),
NULL);
/* set our our contents */
#if 0
sc->description = html_new (TRUE);
put_html (GTK_HTML (sc->description), EXAMPLE_DESCR);
gtk_table_attach (GTK_TABLE (sc->table), sc->description->parent->parent,
0, 1, 0, 1,
GTK_FILL | GTK_EXPAND,
0,
0, 0);
#endif
/* set up the store etable */
sc->store_model = e_table_simple_new (store_etable_col_count,
store_etable_row_count,
store_etable_value_at,
store_etable_set_value_at,
store_etable_is_editable,
store_etable_duplicate_value,
store_etable_free_value,
store_etable_initialize_value,
store_etable_value_is_empty,
store_etable_value_to_string,
sc);
extras = e_table_extras_new ();
sc->store_etable = e_table_scrolled_new (E_TABLE_MODEL(sc->store_model),
extras, STORE_ETABLE_SPEC, NULL);
gtk_object_sink (GTK_OBJECT (extras));
gtk_signal_connect (GTK_OBJECT (e_table_scrolled_get_table(E_TABLE_SCROLLED (sc->store_etable))),
"cursor_change", GTK_SIGNAL_FUNC (storage_selected_cb),
sc);
/* set up the folder etable */
sc->folder_model = e_tree_simple_new (folder_etable_col_count,
folder_etable_duplicate_value,
folder_etable_free_value,
folder_etable_init_value,
folder_etable_value_is_empty,
folder_etable_value_to_string,
folder_etree_icon_at,
folder_etree_value_at,
folder_etree_set_value_at,
folder_etree_is_editable,
sc);
sc->folder_root = e_tree_model_node_insert (sc->folder_model, NULL,
0, NULL);
e_tree_model_root_node_set_visible (sc->folder_model, FALSE);
e_tree_model_set_expanded_default (sc->folder_model, TRUE);
toggles[0] = gdk_pixbuf_new_from_xpm_data ((const char **)empty_xpm);
toggles[1] = gdk_pixbuf_new_from_xpm_data ((const char **)mark_xpm);
extras = e_table_extras_new ();
cell = e_cell_text_new(NULL, GTK_JUSTIFY_LEFT);
e_table_extras_add_cell (extras, "cell_text", cell);
e_table_extras_add_cell (extras, "cell_toggle", e_cell_toggle_new (0, 2, toggles));
e_table_extras_add_cell (extras, "cell_tree", e_cell_tree_new(NULL, NULL, TRUE, cell));
gtk_object_set (GTK_OBJECT (cell),
"bold_column", FOLDER_COL_SUBSCRIBED,
NULL);
e_table_extras_add_pixbuf (extras, "subscribed-image", toggles[1]);
sc->folder_etable = e_table_scrolled_new (E_TABLE_MODEL(sc->folder_model),
extras, FOLDER_ETABLE_SPEC, NULL);
gtk_object_sink (GTK_OBJECT (extras));
gdk_pixbuf_unref(toggles[0]);
gdk_pixbuf_unref(toggles[1]);
gtk_signal_connect (GTK_OBJECT (e_table_scrolled_get_table(E_TABLE_SCROLLED (sc->folder_etable))),
"double_click", GTK_SIGNAL_FUNC (folder_toggle_cb),
sc);
gtk_table_attach (
GTK_TABLE (sc->table), sc->folder_etable,
0, 1, 1, 3,
GTK_FILL | GTK_EXPAND,
GTK_FILL | GTK_EXPAND,
0, 0);
e_paned_add1 (E_PANED (sc->hpaned), sc->store_etable);
e_paned_add2 (E_PANED (sc->hpaned), sc->table);
e_paned_set_position (E_PANED (sc->hpaned), DEFAULT_STORE_TABLE_WIDTH);
bonobo_window_set_contents (BONOBO_WINDOW (sc->app), sc->hpaned);
#if 0
gtk_widget_show (sc->description);
#endif
gtk_widget_show (sc->folder_etable);
gtk_widget_show (sc->table);
gtk_widget_show (sc->store_etable);
gtk_widget_show (sc->hpaned);
/* FIXME: Session management and stuff? */
gtk_window_set_default_size (GTK_WINDOW (sc->app),
DEFAULT_WIDTH, DEFAULT_HEIGHT);
populate_store_list (sc);
}
static void
subscribe_dialog_destroy (GtkObject *object)
{
SubscribeDialog *sc;
sc = SUBSCRIBE_DIALOG (object);
/* free our folder information */
e_tree_model_node_remove (sc->folder_model, sc->folder_root);
gtk_object_unref (GTK_OBJECT (sc->folder_model));
if (sc->folder_info)
camel_store_free_folder_info (sc->store, sc->folder_info);
/* free our store information */
gtk_object_unref (GTK_OBJECT (sc->store_model));
g_list_foreach (sc->store_list, (GFunc)gtk_object_unref, NULL);
/* free our storage */
if (sc->storage)
gtk_object_unref (GTK_OBJECT (sc->storage));
/* free our search */
if (sc->search_top)
g_free (sc->search_top);
subscribe_dialog_parent_class->destroy (object);
}
static void
subscribe_dialog_class_init (GtkObjectClass *object_class)
{
object_class->destroy = subscribe_dialog_destroy;
subscribe_dialog_parent_class = gtk_type_class (PARENT_TYPE);
}
static void
subscribe_dialog_init (GtkObject *object)
{
}
static void
subscribe_dialog_construct (GtkObject *object, GNOME_Evolution_Shell shell)
{
SubscribeDialog *sc = SUBSCRIBE_DIALOG (object);
/*
* Our instance data
*/
sc->shell = shell;
sc->store = NULL;
sc->storage = NULL;
sc->folder_info = NULL;
sc->store_list = NULL;
sc->search_top = NULL;
subscribe_dialog_gui_init (sc);
}
GtkWidget *
subscribe_dialog_new (GNOME_Evolution_Shell shell)
{
SubscribeDialog *subscribe_dialog;
subscribe_dialog = gtk_type_new (subscribe_dialog_get_type ());
subscribe_dialog_construct (GTK_OBJECT (subscribe_dialog), shell);
return GTK_WIDGET (subscribe_dialog->app);
}
E_MAKE_TYPE (subscribe_dialog, "SubscribeDialog", SubscribeDialog, subscribe_dialog_class_init, subscribe_dialog_init, PARENT_TYPE);