aboutsummaryrefslogtreecommitdiffstats
path: root/mail
diff options
context:
space:
mode:
authorPeter Williams <peterw@ximian.com>2001-08-07 03:02:00 +0800
committerPeter Williams <peterw@src.gnome.org>2001-08-07 03:02:00 +0800
commitd7562e99ae9fa1c7a2dc894087b580a9e503fa71 (patch)
tree4bfdab5bbe5dc2e23c3e6b96059ad4905f29ebf6 /mail
parentf789abbd422604206c386199c80fb5eac8e34733 (diff)
downloadgsoc2013-evolution-d7562e99ae9fa1c7a2dc894087b580a9e503fa71.tar
gsoc2013-evolution-d7562e99ae9fa1c7a2dc894087b580a9e503fa71.tar.gz
gsoc2013-evolution-d7562e99ae9fa1c7a2dc894087b580a9e503fa71.tar.bz2
gsoc2013-evolution-d7562e99ae9fa1c7a2dc894087b580a9e503fa71.tar.lz
gsoc2013-evolution-d7562e99ae9fa1c7a2dc894087b580a9e503fa71.tar.xz
gsoc2013-evolution-d7562e99ae9fa1c7a2dc894087b580a9e503fa71.tar.zst
gsoc2013-evolution-d7562e99ae9fa1c7a2dc894087b580a9e503fa71.zip
Reimplement to be asynchronous and pretty, with progressive folder loading
2001-08-06 Peter Williams <peterw@ximian.com> * subscribe-dialog.[ch]: Reimplement to be asynchronous and pretty, with progressive folder loading and all sorts of wonderful improvements. * mail-callbacks.c (manage_subscriptions): Change to reflect API update. * component-factory.c (mail_load_storages): Don't add the storage if it has been disabled. * Makefile.am (etspec_DATA): Add subscribe-dialog.etspec. (glade_DATA): And the glade file. * subscribe-dialog.etspec: New file, break out the specification from inside the subscribe-dialog.c * subscribe-dialog.glade: Update this, actually use it now. svn path=/trunk/; revision=11706
Diffstat (limited to 'mail')
-rw-r--r--mail/ChangeLog20
-rw-r--r--mail/Makefile.am4
-rw-r--r--mail/mail-callbacks.c7
-rw-r--r--mail/subscribe-dialog.c1860
-rw-r--r--mail/subscribe-dialog.etspec9
-rw-r--r--mail/subscribe-dialog.glade366
-rw-r--r--mail/subscribe-dialog.h34
7 files changed, 1395 insertions, 905 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog
index 96af73c18a..96fc9d4e71 100644
--- a/mail/ChangeLog
+++ b/mail/ChangeLog
@@ -1,3 +1,23 @@
+2001-08-06 Peter Williams <peterw@ximian.com>
+
+ * subscribe-dialog.[ch]: Reimplement to be asynchronous and pretty,
+ with progressive folder loading and all sorts of wonderful
+ improvements.
+
+ * mail-callbacks.c (manage_subscriptions): Change to reflect API
+ update.
+
+ * component-factory.c (mail_load_storages): Don't add the storage
+ if it has been disabled.
+
+ * Makefile.am (etspec_DATA): Add subscribe-dialog.etspec.
+ (glade_DATA): And the glade file.
+
+ * subscribe-dialog.etspec: New file, break out the specification
+ from inside the subscribe-dialog.c
+
+ * subscribe-dialog.glade: Update this, actually use it now.
+
2001-08-06 Jeffrey Stedfast <fejj@ximian.com>
* mail-callbacks.c (empty_trash): Yuck. Special case whether or
diff --git a/mail/Makefile.am b/mail/Makefile.am
index 156ceb55b8..ae84f4837f 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -134,10 +134,10 @@ oaf_DATA = $(oaf_in_files:.oaf.in=.oaf)
@XML_I18N_MERGE_OAF_RULE@
gladedir = $(datadir)/evolution/glade
-glade_DATA = mail-config.glade local-config.glade
+glade_DATA = mail-config.glade local-config.glade subscribe-dialog.glade
etspecdir = $(datadir)/evolution/etspec/
-etspec_DATA = message-list.etspec
+etspec_DATA = message-list.etspec subscribe-dialog.etspec
iconsdir = $(datadir)/images/evolution
buttonsdir = $(datadir)/images/evolution/buttons
diff --git a/mail/mail-callbacks.c b/mail/mail-callbacks.c
index e1bb896ba5..b225c9bd98 100644
--- a/mail/mail-callbacks.c
+++ b/mail/mail-callbacks.c
@@ -1908,7 +1908,7 @@ print_preview_msg (GtkWidget *button, gpointer user_data)
/******************** Begin Subscription Dialog ***************************/
-static GtkWidget *subscribe_dialog = NULL;
+static GtkObject *subscribe_dialog = NULL;
static void
subscribe_dialog_destroy (GtkWidget *widget, gpointer user_data)
@@ -1920,11 +1920,12 @@ void
manage_subscriptions (BonoboUIComponent *uih, void *user_data, const char *path)
{
if (!subscribe_dialog) {
- subscribe_dialog = subscribe_dialog_new ((FOLDER_BROWSER (user_data))->shell);
+ subscribe_dialog = subscribe_dialog_new ();
gtk_signal_connect (GTK_OBJECT (subscribe_dialog), "destroy",
subscribe_dialog_destroy, NULL);
- gtk_widget_show (subscribe_dialog);
+ subscribe_dialog_run_and_close (SUBSCRIBE_DIALOG (subscribe_dialog));
+ gtk_object_unref (subscribe_dialog);
} else {
/* FIXME: raise the subscription dialog window... */
}
diff --git a/mail/subscribe-dialog.c b/mail/subscribe-dialog.c
index b0b49805b9..24ef62f502 100644
--- a/mail/subscribe-dialog.c
+++ b/mail/subscribe-dialog.c
@@ -2,6 +2,7 @@
/* subscribe-dialog.c: Subscribe dialog */
/*
* Authors: Chris Toshok <toshok@ximian.com>
+ * Peter Williams <peterw@ximian.com>
*
* Copyright 2000 Ximian, Inc. (www.ximian.com)
*
@@ -25,15 +26,6 @@
#include <config.h>
#endif
-#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 <gtkhtml/gtkhtml.h>
#include <gal/util/e-util.h>
#include <gal/widgets/e-unicode.h>
@@ -41,21 +33,16 @@
#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-table-simple.h>
-#include <gal/e-table/e-table.h>
-
#include <gal/e-table/e-tree-scrolled.h>
#include <gal/e-table/e-tree-memory-callbacks.h>
#include <gal/e-table/e-tree.h>
-#include <gal/e-paned/e-hpaned.h>
-
-#include "e-util/e-html-utils.h"
#include "evolution-shell-component-utils.h"
#include "mail.h"
#include "mail-tools.h"
+#include "mail-ops.h"
#include "mail-mt.h"
+#include "mail-folder-cache.h"
#include "camel/camel-exception.h"
#include "camel/camel-store.h"
#include "camel/camel-session.h"
@@ -64,275 +51,278 @@
#include "art/empty.xpm"
#include "art/mark.xpm"
+/* Things to test.
+ * - Feature
+ * + How to check that it works.
+ *
+ * - Proper stores displayed
+ * + Skip stores that don't support subscriptions
+ * + Skip disabled stores
+ * - Changing subscription status
+ * + Select single folder, double-click row -> toggled
+ * + Select multiple folders, press subscribe -> all selected folders end up subscribed
+ * - (un)Subscribing from/to already (un)subscribed folder
+ * + Check that no IMAP command is sent
+ * - Switching views between stores
+ * + Proper tree shown
+ * - No crashes when buttons are pressed with "No store" screen
+ * + obvious
+ * - Restoring filter settings when view switched
+ * + Enter search, change view, change back -> filter checked and search entry set
+ * + Clear search, change view, change back -> "all" checked
+ * - Cancelling in middle of get_store
+ * + Enter invalid hostname, open dialog, click Close
+ * - Cancelling in middle if listing
+ * + Open large directory, click Close
+ * - Cancelling in middle of subscription op
+ * + How to test?
+ * - Test with both IMAP and NNTP
+ * + obvious
+ * - Verify that refresh view works
+ * + obvious
+ * - No unnecessary tree rebuilds
+ * + Show All folders, change filter with empty search -> no tree rebuild
+ * + Converse
+ * - No out of date tree
+ * + Show All Folders, change to filter with a search -> tree rebuild
+ * - Tree construction logic (mostly IMAP-specific terminology)
+ * + Tree is created progressively
+ * + No wasted LIST responses
+ * + No extraneous LIST commands
+ * + Specifying "folder names begin with" works
+ * + Always show folders below IMAP namespace (no escaping the namespace)
+ * + Don't allow subscription to NoSelect folders
+ * + IMAP accounts always show INBOX
+ * - Shell interactions
+ * + Folders are properly created / delete from folder tree when subscribed / unsubscribed
+ * + Mail Folder Cache doesn't complain
+ * - No ETable wackiness
+ * + Verify columns cannot be DnD'd
+ * + No sorting, eg (?)
+ * - UI cleanliness
+ * + Keybindings work
+ * + Some widget has focus by default
+ * + Escape / enter work
+ * + Close button works
+ */
-#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_ETREE_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
-};
+/*#define NEED_TOGGLE_SELECTION*/
-enum {
- STORE_COL_NAME,
- STORE_COL_LAST
-};
+/* util */
-static GtkObjectClass *subscribe_dialog_parent_class;
+static void
+recursive_add_folder (EvolutionStorage *storage, const char *path, const char *name, const char *url)
+{
+ char *parent, *pname, *p;
-static void build_tree (SubscribeDialog *sc, CamelStore *store);
+ 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);
+ }
-static EPixmap pixmaps [] = {
- E_PIXMAP ("/Toolbar/SubscribeFolder", "buttons/fetch-mail.png"), /* XXX */
- E_PIXMAP ("/Toolbar/UnsubscribeFolder", "buttons/compose-message.png"), /* XXX */
- E_PIXMAP ("/Toolbar/RefreshList", "buttons/forward.png"), /* XXX */
- E_PIXMAP_END
-};
+ evolution_storage_new_folder (storage, path, name, "mail", url, name, FALSE);
+ mail_folder_cache_set_update_estorage (url, storage);
+ mail_folder_cache_note_name (url, name);
+}
-static GtkWidget*
-make_folder_search_widget (GtkSignalFunc start_search_func,
- gpointer user_data_for_search)
+static char *
+storage_tree_path (CamelFolderInfo *info)
{
- SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data_for_search);
- GtkWidget *search_hbox = gtk_hbox_new (FALSE, 0);
+ int len;
+ CamelFolderInfo *i;
+ char *path, *p;
- sc->search_entry = gtk_entry_new ();
+ for (len = 0, i = info; i; i = i->parent)
+ len += strlen (i->name) + 1;
- if (start_search_func) {
- gtk_signal_connect (GTK_OBJECT (sc->search_entry), "activate",
- start_search_func,
- user_data_for_search);
+ /* 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 = '/';
}
-
- /* 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;
+ return path;
}
-
-/* Our async operations */
+/* ** Get one level of folderinfo ****************************************** */
-typedef void (*SubscribeGetStoreCallback)(SubscribeDialog *sc, CamelStore *store, gpointer cb_data);
-typedef void (*SubscribeFolderCallback)(SubscribeDialog *sc, gboolean success, gpointer cb_data);
+typedef void (*SubscribeShortFolderinfoFunc) (CamelStore *store, gchar *prefix, CamelFolderInfo *info, gpointer data);
-/* ** GET STORE ******************************************************* */
+int subscribe_get_short_folderinfo (CamelStore *store, gchar *prefix, SubscribeShortFolderinfoFunc func, gpointer user_data);
-struct _get_store_msg {
- struct _mail_msg msg;
+struct _get_short_folderinfo_msg {
+ struct _mail_msg msg;
- SubscribeDialog *sc;
- char *url;
- SubscribeGetStoreCallback cb;
- gpointer cb_data;
- CamelStore *store;
+ gchar *prefix;
+
+ CamelStore *store;
+ CamelFolderInfo *info;
+
+ SubscribeShortFolderinfoFunc func;
+ gpointer user_data;
};
-static char *get_store_desc(struct _mail_msg *mm, int done)
+static char *
+get_short_folderinfo_desc (struct _mail_msg *mm, int done)
{
- struct _get_store_msg *m = (struct _get_store_msg *)mm;
+ struct _get_short_folderinfo_msg *m = (struct _get_short_folderinfo_msg *) mm;
+ char *ret, *name;
- return g_strdup_printf(_("Getting store for \"%s\""), m->url);
+ name = camel_service_get_name (CAMEL_SERVICE (m->store), TRUE);
+
+ if (m->prefix)
+ ret = g_strdup_printf (_("Scanning folders under %s on \"%s\""), m->prefix, name);
+ else
+ ret = g_strdup_printf (_("Scanning root-level folders on \"%s\""), name);
+
+ g_free (name);
+ return ret;
}
-static void get_store_get(struct _mail_msg *mm)
+static void
+get_short_folderinfo_get (struct _mail_msg *mm)
{
- struct _get_store_msg *m = (struct _get_store_msg *)mm;
+ struct _get_short_folderinfo_msg *m = (struct _get_short_folderinfo_msg *) mm;
- m->store = camel_session_get_store (session, m->url, &mm->ex);
+ camel_operation_register (mm->cancel);
+ m->info = camel_store_get_folder_info (m->store, m->prefix, CAMEL_STORE_FOLDER_INFO_FAST, &mm->ex);
+ camel_operation_unregister (mm->cancel);
}
-static void get_store_got(struct _mail_msg *mm)
+static void
+get_short_folderinfo_got (struct _mail_msg *mm)
{
- struct _get_store_msg *m = (struct _get_store_msg *)mm;
+ struct _get_short_folderinfo_msg *m = (struct _get_short_folderinfo_msg *) mm;
+
+ if (camel_exception_is_set (&(mm->ex)))
+ g_warning ("Error getting folder info from store at %s: %s",
+ camel_service_get_url (CAMEL_SERVICE (m->store)),
+ camel_exception_get_description (&(mm->ex)));
- m->cb(m->sc, m->store, m->cb_data);
+ /* 'done' is probably guaranteed to fail, but... */
+
+ if (m->func)
+ m->func (m->store, m->prefix, m->info, m->user_data);
}
-static void get_store_free(struct _mail_msg *mm)
+static void
+get_short_folderinfo_free (struct _mail_msg *mm)
{
- struct _get_store_msg *m = (struct _get_store_msg *)mm;
+ struct _get_short_folderinfo_msg *m = (struct _get_short_folderinfo_msg *) mm;
- if (m->store)
- camel_object_unref((CamelObject *)m->store);
- g_free(m->url);
+ camel_store_free_folder_info (m->store, m->info);
+ camel_object_unref (CAMEL_OBJECT (m->store));
+
+ g_free (m->prefix); /* may be NULL but that's ok */
}
-static struct _mail_msg_op get_store_op = {
- get_store_desc,
- get_store_get,
- get_store_got,
- get_store_free,
+static struct _mail_msg_op get_short_folderinfo_op = {
+ get_short_folderinfo_desc,
+ get_short_folderinfo_get,
+ get_short_folderinfo_got,
+ get_short_folderinfo_free,
};
-static void
-subscribe_do_get_store (SubscribeDialog *sc, const char *url, SubscribeGetStoreCallback cb, gpointer cb_data)
+int
+subscribe_get_short_folderinfo (CamelStore *store,
+ gchar *prefix,
+ SubscribeShortFolderinfoFunc func,
+ gpointer user_data)
{
- struct _get_store_msg *m;
+ struct _get_short_folderinfo_msg *m;
int id;
- g_return_if_fail (url != NULL);
+ m = mail_msg_new (&get_short_folderinfo_op, NULL, sizeof(*m));
- m = mail_msg_new(&get_store_op, NULL, sizeof(*m));
- m->sc = sc;
- m->url = g_strdup(url);
- m->cb = cb;
- m->cb_data = cb_data;
-
- id = m->msg.seq;
- e_thread_put(mail_thread_queued, (EMsg *)m);
- mail_msg_wait(id);
-}
+ m->store = store;
+ camel_object_ref (CAMEL_OBJECT (store));
-/* ** 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;
+ if (prefix)
+ m->prefix = g_strdup (prefix);
+ else
+ m->prefix = NULL;
- for (len = 0, i = info; i; i = i->parent)
- len += strlen (i->name) + 1;
+ m->func = func;
+ m->user_data = user_data;
- /* 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;
+ id = m->msg.seq;
+ e_thread_put (mail_thread_new, (EMsg *)m);
+ return id;
}
-/* ********************************************************************** */
-/* Subscribe folder */
+/* ** Subscribe folder operation **************************************** */
+
+typedef void (*SubscribeFolderCallback) (const char *, const char *, gboolean, gboolean, gpointer);
struct _subscribe_msg {
- struct _mail_msg msg;
+ struct _mail_msg msg;
- SubscribeDialog *sc;
- CamelStore *store;
- gboolean subscribe;
- SubscribeFolderCallback cb;
- gpointer cb_data;
-
- char *path;
- char *name;
- char *full_name;
- char *url;
+ CamelStore *store;
+ gboolean subscribe;
+ gchar *full_name;
+ gchar *name;
+
+ SubscribeFolderCallback cb;
+ gpointer cb_data;
};
-static char *subscribe_folder_desc(struct _mail_msg *mm, int done)
+static char *
+subscribe_folder_desc (struct _mail_msg *mm, int done)
{
- struct _subscribe_msg *m = (struct _subscribe_msg *)mm;
+ struct _subscribe_msg *m = (struct _subscribe_msg *) mm;
if (m->subscribe)
- return g_strdup_printf(_("Subscribing to folder \"%s\""), m->name);
+ return g_strdup_printf (_("Subscribing to folder \"%s\""), m->name);
else
- return g_strdup_printf(_("Unsubscribing to folder \"%s\""), m->name);
+ return g_strdup_printf (_("Unsubscribing to folder \"%s\""), m->name);
}
-static void subscribe_folder_subscribe(struct _mail_msg *mm)
+static void
+subscribe_folder_subscribe (struct _mail_msg *mm)
{
- struct _subscribe_msg *m = (struct _subscribe_msg *)mm;
+ struct _subscribe_msg *m = (struct _subscribe_msg *) mm;
if (m->subscribe)
- camel_store_subscribe_folder(m->store, m->full_name, &mm->ex);
+ camel_store_subscribe_folder (m->store, m->full_name, &mm->ex);
else
- camel_store_unsubscribe_folder(m->store, m->full_name, &mm->ex);
+ camel_store_unsubscribe_folder (m->store, m->full_name, &mm->ex);
}
-static void
-recursive_add_folder (EvolutionStorage *storage, const char *path, const char *name, const char *url)
+static void
+subscribe_folder_subscribed (struct _mail_msg *mm)
{
- 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, name, FALSE);
-}
-
-static void subscribe_folder_subscribed(struct _mail_msg *mm)
-{
- struct _subscribe_msg *m = (struct _subscribe_msg *)mm;
-
- if (!camel_exception_is_set (&mm->ex)) {
- if (m->subscribe)
- recursive_add_folder(m->sc->storage, m->path, m->name, m->url);
- else
- evolution_storage_removed_folder(m->sc->storage, m->path);
- }
+ struct _subscribe_msg *m = (struct _subscribe_msg *) mm;
if (m->cb)
- m->cb(m->sc, !camel_exception_is_set(&mm->ex), m->cb_data);
+ (m->cb) (m->full_name, m->name,
+ m->subscribe,
+ !camel_exception_is_set(&mm->ex), m->cb_data);
}
-static void subscribe_folder_free(struct _mail_msg *mm)
+static void
+subscribe_folder_free (struct _mail_msg *mm)
{
- struct _subscribe_msg *m = (struct _subscribe_msg *)mm;
+ struct _subscribe_msg *m = (struct _subscribe_msg *) mm;
- g_free(m->path);
- g_free(m->name);
- g_free(m->full_name);
- g_free(m->url);
+ g_free (m->name);
+ g_free (m->full_name);
- camel_object_unref((CamelObject *)m->store);
- /* in wrong thread to do this?
- gtk_object_unref (GTK_OBJECT (input->sc));*/
+ camel_object_unref (CAMEL_OBJECT (m->store));
}
static struct _mail_msg_op subscribe_folder_op = {
@@ -342,721 +332,1132 @@ static struct _mail_msg_op subscribe_folder_op = {
subscribe_folder_free,
};
-static void
-subscribe_do_subscribe_folder (SubscribeDialog *sc, CamelStore *store, CamelFolderInfo *info,
+static int
+subscribe_do_subscribe_folder (CamelStore *store, const char *full_name, const char *name,
gboolean subscribe, SubscribeFolderCallback cb, gpointer cb_data)
{
struct _subscribe_msg *m;
-
- g_return_if_fail (CAMEL_IS_STORE (store));
- g_return_if_fail (info);
+ int id;
- m = mail_msg_new(&subscribe_folder_op, NULL, sizeof(*m));
- m->sc = sc;
- m->store = store;
- camel_object_ref((CamelObject *)store);
- m->subscribe = subscribe;
- m->cb = cb;
- m->cb_data = cb_data;
+ g_return_val_if_fail (CAMEL_IS_STORE (store), 0);
+ g_return_val_if_fail (full_name, 0);
- m->path = storage_tree_path (info);
- m->name = g_strdup (info->name);
- m->full_name = g_strdup (info->full_name);
- m->url = g_strdup (info->url);
+ m = mail_msg_new (&subscribe_folder_op, NULL, sizeof(*m));
+ m->store = store;
+ m->subscribe = subscribe;
+ m->name = g_strdup (name);
+ m->full_name = g_strdup (full_name);
+ m->cb = cb;
+ m->cb_data = cb_data;
- /*
- gtk_object_ref (GTK_OBJECT (sc));*/
+ camel_object_ref (CAMEL_OBJECT (store));
- e_thread_put(mail_thread_new, (EMsg *)m);
+ id = m->msg.seq;
+ e_thread_put (mail_thread_new, (EMsg *)m);
+ return id;
}
-
+/* ** FolderETree Extras *************************************************** */
-static gboolean
-folder_info_subscribed (SubscribeDialog *sc, CamelFolderInfo *info)
-{
- return camel_store_folder_subscribed (sc->store, info->full_name);
-}
+typedef struct _FolderETreeExtras FolderETreeExtras;
+typedef struct _FolderETreeExtrasClass FolderETreeExtrasClass;
-static void
-node_changed_cb (SubscribeDialog *sc, gboolean changed, gpointer data)
-{
- ETreePath node = data;
+enum {
+ FOLDER_COL_SUBSCRIBED,
+ FOLDER_COL_NAME,
+ FOLDER_COL_LAST
+};
- if (changed)
- e_tree_model_node_data_changed (sc->folder_model, node);
-}
+struct _FolderETreeExtras {
+ ETableExtras parent;
+ GdkPixbuf *toggles[2];
+};
-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);
-}
+struct _FolderETreeExtrasClass {
+ ETableExtrasClass parent;
+};
-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 GtkObjectClass *ftree_extras_parent_class = NULL;
static void
-subscribe_close (BonoboUIComponent *uic,
- void *user_data, const char *path)
+fete_destroy (GtkObject *object)
{
- SubscribeDialog *sc = (SubscribeDialog*)user_data;
+ FolderETreeExtras *extras = (FolderETreeExtras *) object;
- gtk_widget_destroy (sc->app);
+ gdk_pixbuf_unref (extras->toggles[0]);
+ gdk_pixbuf_unref (extras->toggles[1]);
+
+ ftree_extras_parent_class->destroy (object);
}
static void
-subscribe_select_all (BonoboUIComponent *uic,
- void *user_data, const char *path)
+fete_class_init (GtkObjectClass *object_class)
{
- SubscribeDialog *sc = (SubscribeDialog*)user_data;
- ETreeScrolled *scrolled = E_TREE_SCROLLED (sc->folder_etree);
- ETree *tree = e_tree_scrolled_get_tree (scrolled);
- ESelectionModel *esm = e_tree_get_selection_model (E_TREE (tree));
+ object_class->destroy = fete_destroy;
- e_selection_model_select_all (E_SELECTION_MODEL (esm));
+ ftree_extras_parent_class = gtk_type_class (E_TABLE_EXTRAS_TYPE);
}
static void
-subscribe_invert_selection (BonoboUIComponent *uic,
- void *user_data, const char *path)
+fete_init (GtkObject *object)
{
- SubscribeDialog *sc = (SubscribeDialog*)user_data;
- ETreeScrolled *scrolled = E_TREE_SCROLLED (sc->folder_etree);
- ETree *tree = e_tree_scrolled_get_tree (scrolled);
- ESelectionModel *esm = e_tree_get_selection_model (E_TREE (tree));
-
- e_selection_model_invert_selection (E_SELECTION_MODEL (esm));
-}
+ FolderETreeExtras *extras = (FolderETreeExtras *) object;
+ ECell *cell;
+ ECell *text_cell;
-static void
-subscribe_folder_foreach (int model_row, gpointer closure)
-{
- SubscribeDialog *sc = SUBSCRIBE_DIALOG (closure);
- ETreePath node = e_tree_node_at_row (e_tree_scrolled_get_tree(E_TREE_SCROLLED(sc->folder_etree)), model_row);
- CamelFolderInfo *info = e_tree_memory_node_get_data (E_TREE_MEMORY(sc->folder_model), node);
+ /* text column */
- if (!folder_info_subscribed (sc, info))
- subscribe_folder_info (sc, info, node);
-}
+ cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT);
+ text_cell = cell;
+ gtk_object_set (GTK_OBJECT (cell),
+ "bold_column", FOLDER_COL_SUBSCRIBED,
+ NULL);
+ e_table_extras_add_cell (E_TABLE_EXTRAS (extras), "cell_text", cell);
-static void
-subscribe_folders (BonoboUIComponent *componet, gpointer user_data, const char *cname)
-{
- SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+ /* toggle column */
- e_tree_selected_row_foreach (e_tree_scrolled_get_tree(E_TREE_SCROLLED(sc->folder_etree)),
- subscribe_folder_foreach, sc);
-}
+ extras->toggles[0] = gdk_pixbuf_new_from_xpm_data ((const char **)empty_xpm);
+ extras->toggles[1] = gdk_pixbuf_new_from_xpm_data ((const char **)mark_xpm);
+ cell = e_cell_toggle_new (0, 2, extras->toggles);
+ e_table_extras_add_cell (E_TABLE_EXTRAS (extras), "cell_toggle", cell);
-static void
-unsubscribe_folder_foreach (int model_row, gpointer closure)
-{
- SubscribeDialog *sc = SUBSCRIBE_DIALOG (closure);
- ETreePath node = e_tree_node_at_row (e_tree_scrolled_get_tree(E_TREE_SCROLLED(sc->folder_etree)), model_row);
- CamelFolderInfo *info = e_tree_memory_node_get_data (E_TREE_MEMORY(sc->folder_model), node);
+ /* tree cell */
+
+ cell = e_cell_tree_new (NULL, NULL, TRUE, text_cell);
+ e_table_extras_add_cell (E_TABLE_EXTRAS (extras), "cell_tree", cell);
- if (folder_info_subscribed(sc, info))
- unsubscribe_folder_info (sc, info, node);
+ /* misc */
+
+ e_table_extras_add_pixbuf (E_TABLE_EXTRAS (extras), "subscribed-image", extras->toggles[1]);
}
+/* naughty! */
+static
+E_MAKE_TYPE (fete, "FolderETreeExtras", FolderETreeExtras, fete_class_init, fete_init, E_TABLE_EXTRAS_TYPE);
-static void
-unsubscribe_folders (BonoboUIComponent *component, gpointer user_data, const char *cname)
-{
- SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+/* ** Global Extras ******************************************************** */
- e_tree_selected_row_foreach (e_tree_scrolled_get_tree(E_TREE_SCROLLED(sc->folder_etree)),
- unsubscribe_folder_foreach, sc);
-}
+static FolderETreeExtras *global_extras = NULL;
static void
-subscribe_refresh_list (BonoboUIComponent *component, gpointer user_data, const char *cname)
+global_extras_destroyed (GtkObject *obj, gpointer user_data)
{
- SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+ global_extras = NULL;
+}
- e_utf8_gtk_entry_set_text (GTK_ENTRY (sc->search_entry), "");
- if (sc->search_top) {
- g_free (sc->search_top);
- sc->search_top = NULL;
+static ETableExtras *
+subscribe_get_global_extras (void)
+{
+ if (global_extras == NULL) {
+ global_extras = gtk_type_new (fete_get_type());
+ gtk_object_ref (GTK_OBJECT (global_extras));
+ gtk_object_sink (GTK_OBJECT (global_extras));
+ gtk_signal_connect (GTK_OBJECT (global_extras), "destroy",
+ global_extras_destroyed, NULL);
}
- if (sc->store)
- build_tree (sc, sc->store);
+
+ gtk_object_ref (GTK_OBJECT (global_extras));
+ return E_TABLE_EXTRAS (global_extras);
}
-static void
-subscribe_search (GtkWidget *widget, gpointer user_data)
+/* ** Folder Tree Node ***************************************************** */
+
+typedef struct _ftree_node ftree_node;
+
+struct _ftree_node {
+ guint8 flags;
+ int path_offset;
+ int uri_offset;
+ int full_name_offset;
+
+ /* format: {name}{\0}{path}{\0}{uri}{\0}{full_name}{\0}
+ * (No braces). */
+ char data[1];
+};
+
+#define FTREE_NODE_GOT_CHILDREN (1 << 0)
+#define FTREE_NODE_SUBSCRIBABLE (1 << 1)
+#define FTREE_NODE_SUBSCRIBED (1 << 2)
+#define FTREE_NODE_ROOT (1 << 3)
+
+static ftree_node *
+ftree_node_new_root (const char *prefix)
{
- SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
- char* search_pattern = e_utf8_gtk_entry_get_text(GTK_ENTRY(widget));
+ ftree_node *node;
+ size_t size;
- if (sc->search_top) {
- g_free (sc->search_top);
- sc->search_top = NULL;
- }
+ if (prefix == NULL)
+ prefix = "";
+
+ size = sizeof (ftree_node) + strlen (prefix) + 1;
- if (search_pattern && *search_pattern)
- sc->search_top = search_pattern;
+ node = g_malloc (size);
+ node->flags = FTREE_NODE_ROOT;
+ node->path_offset = 0;
+ node->uri_offset = 0;
+ node->full_name_offset = 1;
+ node->data[0] = '\0';
+ strcpy (node->data + 1, prefix);
- if (sc->store)
- build_tree (sc, sc->store);
+ return node;
}
-
-#if 0
-/* HTML Helpers */
-static void
-html_size_req (GtkWidget *widget, GtkRequisition *requisition)
+static ftree_node *
+ftree_node_new (CamelStore *store, CamelFolderInfo *fi)
{
- if (GTK_LAYOUT (widget)->height > 90)
- requisition->height = 90;
+ ftree_node *node;
+ int path_offset, uri_offset, full_name_offset;
+ size_t size;
+ char *path;
+ CamelURL *url;
+
+ path = storage_tree_path (fi);
+
+ path_offset = strlen (fi->name) + 1;
+ uri_offset = path_offset + strlen (path) + 1;
+ full_name_offset = uri_offset + strlen (fi->url) + 1;
+ size = full_name_offset + strlen (fi->full_name);
+
+ /* - 1 for sizeof(node.data) but +1 for terminating \0 */
+ node = g_malloc (sizeof (*node) + size);
+
+ /* Noselect? */
+
+ url = camel_url_new (fi->url, NULL);
+ if (camel_url_get_param (url, "noselect"))
+ node->flags = 0;
else
- requisition->height = GTK_LAYOUT (widget)->height;
-}
+ node->flags = FTREE_NODE_SUBSCRIBABLE;
+ camel_url_free (url);
-/* 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;
-}
+ /* subscribed? */
-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);
+ if (camel_store_folder_subscribed (store, fi->full_name))
+ node->flags |= FTREE_NODE_SUBSCRIBED;
+
+ /* Copy strings */
+
+ node->path_offset = path_offset;
+ node->uri_offset = uri_offset;
+ node->full_name_offset = full_name_offset;
+
+ strcpy (node->data, fi->name);
+ strcpy (node->data + path_offset, path);
+ strcpy (node->data + uri_offset, fi->url);
+ strcpy (node->data + full_name_offset, fi->full_name);
+
+ /* Done */
+
+ g_free (path);
+ return node;
}
-#endif
-
-/* etree stuff for the subscribe ui */
+#define ftree_node_subscribable(node) ( ((ftree_node *) (node))->flags & FTREE_NODE_SUBSCRIBABLE )
+#define ftree_node_subscribed(node) ( ((ftree_node *) (node))->flags & FTREE_NODE_SUBSCRIBED )
+#define ftree_node_get_name(node) ( ((ftree_node *) (node))->data )
+#define ftree_node_get_full_name(node) ( ((ftree_node *) (node))->data + ((ftree_node *) (node))->full_name_offset )
+#define ftree_node_get_path(node) ( ((ftree_node *) (node))->data + ((ftree_node *) (node))->path_offset )
+#define ftree_node_get_uri(node) ( ((ftree_node *) (node))->data + ((ftree_node *) (node))->uri_offset )
+
+/* ** Folder Tree Model **************************************************** */
+
+typedef struct _FolderETree FolderETree;
+typedef struct _FolderETreeClass FolderETreeClass;
+
+struct _FolderETree {
+ ETreeMemory parent;
+ ETreePath root;
+
+ GHashTable *scan_ops;
+ GHashTable *subscribe_ops;
+
+ CamelStore *store;
+ EvolutionStorage *e_storage;
+ gchar *search;
+};
+
+struct _FolderETreeClass {
+ ETreeMemoryClass parent;
+};
+
+static GtkObjectClass *folder_etree_parent_class = NULL;
+
+/* A subscribe or scan operation */
+
+typedef struct _ftree_op_data ftree_op_data;
+
+struct _ftree_op_data {
+ FolderETree *ftree;
+ ETreePath path;
+ ftree_node *data;
+ int handle;
+};
+
+
+/* ETreeModel functions */
static int
-folder_etree_column_count (ETreeModel *etm, void *data)
+fe_column_count (ETreeModel *etm)
{
return FOLDER_COL_LAST;
}
-static void*
-folder_etree_duplicate_value (ETreeModel *etm, int col, const void *val, void *data)
+static void *
+fe_duplicate_value (ETreeModel *etm, int col, const void *val)
{
return g_strdup (val);
}
static void
-folder_etree_free_value (ETreeModel *etm, int col, void *val, void *data)
+fe_free_value (ETreeModel *etm, int col, void *val)
{
g_free (val);
}
static void*
-folder_etree_init_value (ETreeModel *etm, int col, void *data)
+fe_init_value (ETreeModel *etm, int col)
{
return g_strdup ("");
}
static gboolean
-folder_etree_value_is_empty (ETreeModel *etm, int col, const void *val, void *data)
+fe_value_is_empty (ETreeModel *etm, int col, const void *val)
{
return !(val && *(char *)val);
}
-static char*
-folder_etree_value_to_string (ETreeModel *etm, int col, const void *val, void *data)
+static char *
+fe_value_to_string (ETreeModel *etm, int col, const void *val)
{
- return g_strdup(val);
+ return g_strdup (val);
}
-static GdkPixbuf*
-folder_etree_icon_at (ETreeModel *etree, ETreePath path, void *model_data)
+static GdkPixbuf *
+fe_icon_at (ETreeModel *etree, ETreePath path)
{
return NULL; /* XXX no icons for now */
}
-static void*
-folder_etree_value_at (ETreeModel *etree, ETreePath path, int col, void *model_data)
+static gpointer
+fe_root_value_at (FolderETree *ftree, int col)
{
- SubscribeDialog *dialog = SUBSCRIBE_DIALOG (model_data);
- CamelFolderInfo *info = e_tree_memory_node_get_data (E_TREE_MEMORY(etree), path);
-
- if (col == FOLDER_COL_NAME) {
- return info->name;
+ switch (col) {
+ case FOLDER_COL_NAME:
+ return camel_service_get_name (CAMEL_SERVICE (ftree->store), TRUE);
+ case FOLDER_COL_SUBSCRIBED:
+ return GINT_TO_POINTER (0);
+ default:
+ printf ("Oh no, unimplemented column %d in subscribe dialog\n", col);
}
- 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 */
+
+ return NULL;
+}
+
+static gpointer
+fe_real_value_at (FolderETree *ftree, int col, gpointer data)
+{
+ switch (col) {
+ case FOLDER_COL_NAME:
+ return g_strdup (ftree_node_get_name (data));
+ case FOLDER_COL_SUBSCRIBED:
+ if (ftree_node_subscribed (data))
+ return GINT_TO_POINTER (1);
+ return GINT_TO_POINTER (0);
+ default:
+ printf ("Oh no, unimplemented column %d in subscribe dialog\n", col);
}
+
+ return NULL;
+}
+
+static void *
+fe_value_at (ETreeModel *etree, ETreePath path, int col)
+{
+ FolderETree *ftree = (FolderETree *) etree;
+ gpointer node_data;
+
+ if (path == ftree->root)
+ return fe_root_value_at (ftree, col);
+
+ node_data = e_tree_memory_node_get_data (E_TREE_MEMORY (etree), path);
+ return fe_real_value_at (ftree, col, node_data);
}
static void
-folder_etree_set_value_at (ETreeModel *etree, ETreePath path, int col, const void *val, void *model_data)
+fe_set_value_at (ETreeModel *etree, ETreePath path, int col, const void *val)
{
/* nothing */
}
static gboolean
-folder_etree_is_editable (ETreeModel *etree, ETreePath path, int col, void *model_data)
+fe_return_false (void)
{
return FALSE;
}
-
+/* scanning */
-static int
-store_etable_col_count (ETableModel *etm, void *data)
+static void
+fe_got_children (CamelStore *store, gchar *prefix, CamelFolderInfo *info, gpointer data)
+{
+ ftree_op_data *closure = (ftree_op_data *) data;
+
+ if (!info) /* cancelled */
+ return;
+
+ if (!prefix)
+ prefix = "";
+ printf ("CHILDREN OF \"%s\":\n", prefix);
+
+ for (; info; info = info->sibling) {
+ ETreePath child_path;
+ ftree_node *node;
+
+ if (strcmp (info->full_name, prefix) == 0)
+ continue;
+
+ node = ftree_node_new (store, info);
+ child_path = e_tree_memory_node_insert (E_TREE_MEMORY (closure->ftree),
+ closure->path,
+ 0,
+ node);
+
+ printf (" \"%s\"\n", info->full_name);
+ }
+
+ if (closure->data)
+ closure->data->flags |= FTREE_NODE_GOT_CHILDREN;
+
+ g_hash_table_remove (closure->ftree->scan_ops, closure->path);
+ g_free (closure);
+}
+
+static void
+fe_check_for_children (FolderETree *ftree, ETreePath path)
{
- return STORE_COL_LAST;
+ ftree_op_data *closure;
+ ftree_node *node;
+ gchar *prefix;
+
+ node = e_tree_memory_node_get_data (E_TREE_MEMORY (ftree), path);
+
+ /* have we already gotten these children? */
+ if (node->flags & FTREE_NODE_GOT_CHILDREN) {
+ printf ("CHECK FOR CHILDREN: cancel: below %s, (got children)\n", ftree_node_get_full_name (node));
+ fflush (stdout);
+ return;
+ }
+
+ /* or we're loading them right now? */
+ if (g_hash_table_lookup (ftree->scan_ops, path)) {
+ printf ("CHECK FOR CHILDREN: cancel: below %s, in progress\n", ftree_node_get_full_name (node));
+ fflush (stdout);
+ return;
+ }
+
+ printf ("CHECK FOR CHILDREN: keepon: below %s\n", ftree_node_get_full_name (node));
+ fflush (stdout);
+
+ /* figure out our search prefix */
+ if (path == ftree->root)
+ prefix = ftree->search;
+ else
+ prefix = ftree_node_get_full_name (node);
+
+ closure = g_new (ftree_op_data, 1);
+ closure->ftree = ftree;
+ closure->path = path;
+ closure->data = node;
+ closure->handle = -1;
+
+ g_hash_table_insert (ftree->scan_ops, path, closure);
+
+ /* FIXME. Tiny race possiblity I guess. */
+
+ closure->handle = subscribe_get_short_folderinfo (ftree->store, prefix, fe_got_children, closure);
}
-static int
-store_etable_row_count (ETableModel *etm, void *data)
+static void
+fe_create_root_node (FolderETree *ftree)
{
- SubscribeDialog *sc = SUBSCRIBE_DIALOG (data);
+ ftree_node *node;
- return g_list_length (sc->store_list);
+ node = ftree_node_new_root (ftree->search);
+ ftree->root = e_tree_memory_node_insert (E_TREE_MEMORY(ftree), NULL, 0, node);
}
-static void*
-store_etable_value_at (ETableModel *etm, int col, int row, void *data)
+static ETreePath
+fe_get_first_child (ETreeModel *model, ETreePath path)
{
- SubscribeDialog *sc = SUBSCRIBE_DIALOG (data);
- CamelStore *store = (CamelStore*)g_list_nth_data (sc->store_list, row);
+ ETreePath child_path;
- return camel_service_get_name (CAMEL_SERVICE (store), TRUE);
+ child_path = E_TREE_MODEL_CLASS (folder_etree_parent_class)->get_first_child (model, path);
+ if (child_path)
+ fe_check_for_children ((FolderETree *) model, child_path);
+ else
+ fe_check_for_children ((FolderETree *) model, path);
+ return child_path;
}
+/* subscribing */
+
static void
-store_etable_set_value_at (ETableModel *etm, int col, int row, const void *val, void *data)
+fe_done_subscribing (const char *full_name, const char *name, gboolean subscribe, gboolean success, gpointer user_data)
{
- /* nada */
+ ftree_op_data *closure = (ftree_op_data *) user_data;
+
+ if (success) {
+ if (subscribe) {
+ closure->data->flags |= FTREE_NODE_SUBSCRIBED;
+ recursive_add_folder (closure->ftree->e_storage,
+ ftree_node_get_path (closure->data),
+ name,
+ ftree_node_get_uri (closure->data));
+ } else {
+ closure->data->flags &= ~FTREE_NODE_SUBSCRIBED;
+ evolution_storage_removed_folder (closure->ftree->e_storage, ftree_node_get_path (closure->data));
+ }
+
+ e_tree_model_node_data_changed (E_TREE_MODEL (closure->ftree), closure->path);
+ }
+
+ g_hash_table_remove (closure->ftree->subscribe_ops, closure->path);
+ g_free (closure);
}
+/* cleanup */
+
static gboolean
-store_etable_is_editable (ETableModel *etm, int col, int row, void *data)
+fe_cancel_op_foreach (gpointer key, gpointer value, gpointer user_data)
{
- return FALSE;
+ /*FolderETree *ftree = (FolderETree *) user_data;*/
+ ftree_op_data *closure = (ftree_op_data *) value;
+
+ if (closure->handle != -1)
+ mail_msg_cancel (closure->handle);
+ else
+ printf ("aaagh, annoying race condition in fe_cancel_op_foreach.\n");
+
+ g_free (value);
+ return TRUE;
}
-static void*
-store_etable_duplicate_value (ETableModel *etm, int col, const void *val, void *data)
+static void
+fe_kill_current_tree (FolderETree *ftree)
{
- return g_strdup (val);
+ g_hash_table_foreach_remove (ftree->scan_ops, fe_cancel_op_foreach, ftree);
+ g_assert (g_hash_table_size (ftree->scan_ops) == 0);
}
static void
-store_etable_free_value (ETableModel *etm, int col, void *val, void *data)
+fe_destroy (GtkObject *obj)
{
- g_free (val);
+ FolderETree *ftree = (FolderETree *) (obj);
+
+ fe_kill_current_tree (ftree);
+
+ g_hash_table_foreach_remove (ftree->subscribe_ops, fe_cancel_op_foreach, ftree);
+
+ g_hash_table_destroy (ftree->scan_ops);
+ g_hash_table_destroy (ftree->subscribe_ops);
+
+ camel_object_unref (CAMEL_OBJECT (ftree->store));
+
+ g_free (ftree->search);
}
-static void*
-store_etable_initialize_value (ETableModel *etm, int col, void *data)
+typedef gboolean (*bool_func_1) (ETreeModel *, ETreePath, int);
+typedef gboolean (*bool_func_2) (ETreeModel *);
+
+static void
+folder_etree_class_init (GtkObjectClass *klass)
{
- return g_strdup ("");
+ ETreeModelClass *etree_model_class = E_TREE_MODEL_CLASS (klass);
+
+ folder_etree_parent_class = gtk_type_class (E_TREE_MEMORY_TYPE);
+
+ klass->destroy = fe_destroy;
+
+ etree_model_class->value_at = fe_value_at;
+ etree_model_class->set_value_at = fe_set_value_at;
+ etree_model_class->column_count = fe_column_count;
+ etree_model_class->duplicate_value = fe_duplicate_value;
+ etree_model_class->free_value = fe_free_value;
+ etree_model_class->initialize_value = fe_init_value;
+ etree_model_class->value_is_empty = fe_value_is_empty;
+ etree_model_class->value_to_string = fe_value_to_string;
+ etree_model_class->icon_at = fe_icon_at;
+ etree_model_class->is_editable = (bool_func_1) fe_return_false;
+ etree_model_class->has_save_id = (bool_func_2) fe_return_false;
+ etree_model_class->has_get_node_by_id = (bool_func_2) fe_return_false;
+ etree_model_class->get_first_child = fe_get_first_child;
}
-static gboolean
-store_etable_value_is_empty (ETableModel *etm, int col, const void *val, void *data)
+static void
+folder_etree_init (GtkObject *object)
{
- return !(val && *(char *)val);
+ FolderETree *ftree = (FolderETree *) object;
+
+ e_tree_memory_set_node_destroy_func (E_TREE_MEMORY (ftree), (GFunc) g_free, ftree);
+
+ ftree->scan_ops = g_hash_table_new (g_direct_hash, g_direct_equal);
+ ftree->subscribe_ops = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ ftree->search = g_strdup ("");
}
-static char*
-store_etable_value_to_string (ETableModel *etm, int col, const void *val, void *data)
+static FolderETree *
+folder_etree_construct (FolderETree *ftree,
+ CamelStore *store)
{
- return g_strdup(val);
+ e_tree_memory_construct (E_TREE_MEMORY (ftree));
+
+ fe_create_root_node (ftree);
+
+ ftree->store = store;
+ camel_object_ref (CAMEL_OBJECT (store));
+ ftree->e_storage = mail_lookup_storage (store);
+
+ return ftree;
}
-
+static
+E_MAKE_TYPE (folder_etree, "FolderETree", FolderETree, folder_etree_class_init, folder_etree_init, E_TREE_MEMORY_TYPE);
+
+/* public */
+
+static FolderETree *
+folder_etree_new (CamelStore *store)
+{
+ FolderETree *ftree;
+
+ ftree = gtk_type_new (folder_etree_get_type());
+ ftree = folder_etree_construct (ftree, store);
+ return ftree;
+}
static void
-build_etree_from_folder_info (SubscribeDialog *sc, ETreePath parent, CamelFolderInfo *info)
+folder_etree_clear_tree (FolderETree *ftree)
{
- CamelFolderInfo *i;
+ e_tree_memory_freeze (E_TREE_MEMORY (ftree));
+ e_tree_memory_node_remove (E_TREE_MEMORY (ftree), ftree->root);
+ fe_create_root_node (ftree);
+ e_tree_memory_thaw (E_TREE_MEMORY (ftree));
+}
- if (info == NULL)
+static void
+folder_etree_set_search (FolderETree *ftree, const char *search)
+{
+ if (!strcmp (search, ftree->search))
return;
- for (i = info; i; i = i->sibling) {
- ETreePath node = e_tree_memory_node_insert (E_TREE_MEMORY(sc->folder_model), parent, -1, i);
- build_etree_from_folder_info (sc, node, i->child);
- }
+ g_free (ftree->search);
+ ftree->search = g_strdup (search);
+
+ folder_etree_clear_tree (ftree);
}
-static void
-build_tree (SubscribeDialog *sc, CamelStore *store)
+
+static int
+folder_etree_path_set_subscription (FolderETree *ftree, ETreePath path, gboolean subscribe)
{
- CamelException *ex = camel_exception_new();
+ ftree_op_data *closure;
+ ftree_node *node;
- /* 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));
+ /* already in progress? */
- sc->store = store;
- sc->storage = mail_lookup_storage (sc->store);
- sc->folder_info = camel_store_get_folder_info (sc->store, sc->search_top, CAMEL_STORE_FOLDER_INFO_RECURSIVE | CAMEL_STORE_FOLDER_INFO_FAST, ex);
+ if (g_hash_table_lookup (ftree->subscribe_ops, path))
+ return 0;
- if (camel_exception_is_set (ex)) {
- printf ("camel_store_get_folder_info failed\n");
- camel_exception_free (ex);
- return;
- }
+ /* noselect? */
+
+ node = e_tree_memory_node_get_data (E_TREE_MEMORY (ftree), path);
+
+ if (!ftree_node_subscribable (node))
+ return -1;
- e_tree_memory_freeze(E_TREE_MEMORY(sc->folder_model));
- e_tree_memory_node_remove (E_TREE_MEMORY(sc->folder_model), sc->folder_root);
- sc->folder_root = e_tree_memory_node_insert (E_TREE_MEMORY(sc->folder_model), NULL,
- 0, NULL);
+ /* noop? */
- build_etree_from_folder_info (sc, sc->folder_root, sc->folder_info);
- e_tree_memory_thaw(E_TREE_MEMORY(sc->folder_model));
+ /* uh, this should be a not XOR or something */
+ if ((ftree_node_subscribed (node) && subscribe) ||
+ (!ftree_node_subscribed (node) && !subscribe))
+ return 0;
- camel_exception_free (ex);
+ closure = g_new (ftree_op_data, 1);
+ closure->ftree = ftree;
+ closure->path = path;
+ closure->data = node;
+ closure->handle = -1;
+
+ g_hash_table_insert (ftree->subscribe_ops, path, closure);
+
+ closure->handle = subscribe_do_subscribe_folder (ftree->store,
+ ftree_node_get_full_name (node),
+ ftree_node_get_name (node),
+ subscribe,
+ fe_done_subscribing,
+ closure);
+ return 0;
}
-static void
-storage_selected_cb (ETree *table, int row, gpointer data)
+static int
+folder_etree_path_toggle_subscription (FolderETree *ftree, ETreePath path)
{
- SubscribeDialog *sc = SUBSCRIBE_DIALOG (data);
- CamelStore *store = (CamelStore*)g_list_nth_data (sc->store_list, row);
+ ftree_node *node = e_tree_memory_node_get_data (E_TREE_MEMORY (ftree), path);
- build_tree (sc, store);
+ if (ftree_node_subscribed (node))
+ return folder_etree_path_set_subscription (ftree, path, FALSE);
+ else
+ return folder_etree_path_set_subscription (ftree, path, TRUE);
}
-
+/* ** StoreData ************************************************************ */
+
+typedef struct _StoreData StoreData;
+
+typedef void (*StoreDataStoreFunc) (StoreData *, CamelStore *, gpointer);
+
+struct _StoreData {
+ gchar *uri;
+
+ FolderETree *ftree;
+ CamelStore *store;
+
+ int request_id;
+
+ GtkWidget *widget;
+ StoreDataStoreFunc store_func;
+ gpointer store_data;
+};
+
+static StoreData *
+store_data_new (const gchar *uri)
+{
+ StoreData *sd;
+
+ sd = g_new0 (StoreData, 1);
+ sd->uri = g_strdup (uri);
+ return sd;
+}
static void
-folder_toggle_cb (ETree *tree, int row, ETreePath path, int col, GdkEvent *event, gpointer data)
+sd_got_store (char *uri, CamelStore *store, gpointer user_data)
{
- SubscribeDialog *sc = SUBSCRIBE_DIALOG (data);
- CamelFolderInfo *info = e_tree_memory_node_get_data (E_TREE_MEMORY(sc->folder_model), path);
+ StoreData *sd = (StoreData *) user_data;
- if (folder_info_subscribed(sc, info))
- unsubscribe_folder_info (sc, info, path);
- else
- subscribe_folder_info (sc, info, path);
+ sd->store = store;
- e_tree_model_node_data_changed (sc->folder_model, path);
-}
+ if (store) /* we can have exceptions getting the store... server is down, eg */
+ camel_object_ref (CAMEL_OBJECT (sd->store));
-
+ /* uh, so we might have a problem if this operation is cancelled. Unsure. */
+ sd->request_id = 0;
-#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"
+ if (sd->store_func)
+ (sd->store_func) (sd, sd->store, sd->store_data);
+}
-static BonoboUIVerb verbs [] = {
- /* File Menu */
- BONOBO_UI_VERB ("FileCloseWin", subscribe_close),
+static void
+store_data_async_get_store (StoreData *sd, StoreDataStoreFunc func, gpointer user_data)
+{
+ if (sd->request_id) {
+ printf ("Already loading store, nooping\n");
+ return;
+ }
- /* 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),
+ if (sd->store) {
+ func (sd, sd->store, user_data);
+ return;
+ }
- /* Toolbar Specific */
- BONOBO_UI_VERB ("RefreshList", subscribe_refresh_list),
+ sd->store_func = func;
+ sd->store_data = user_data;
+ sd->request_id = mail_get_store (sd->uri, sd_got_store, sd);
+}
- BONOBO_UI_VERB_END
-};
+static void
+store_data_cancel_get_store (StoreData *sd)
+{
+ g_return_if_fail (sd->request_id);
+
+ mail_msg_cancel (sd->request_id);
+ sd->request_id = 0;
+}
static void
-store_cb (SubscribeDialog *sc, CamelStore *store, gpointer data)
+sd_toggle_cb (ETree *tree, int row, ETreePath path, int col, GdkEvent *event, gpointer user_data)
{
- if (!store)
- return;
+ StoreData *sd = (StoreData *) user_data;
+
+ folder_etree_path_toggle_subscription (sd->ftree, path);
+}
- if (camel_store_supports_subscriptions (store)) {
- camel_object_ref((CamelObject *)store);
- sc->store_list = g_list_prepend (sc->store_list, store);
- e_table_model_row_inserted (sc->store_model, 0);
+static GtkWidget *
+store_data_get_widget (StoreData *sd)
+{
+ GtkWidget *tree;
+
+ if (!sd->store) {
+ printf ("store data can't get widget before getting store.\n");
+ return NULL;
}
+
+ if (sd->widget)
+ return sd->widget;
+
+ sd->ftree = folder_etree_new (sd->store);
+
+ /* You annoy me, etree! */
+ tree = gtk_widget_new (E_TREE_SCROLLED_TYPE,
+ "hadjustment", NULL,
+ "vadjustment", NULL,
+ NULL);
+
+ tree = (GtkWidget *) e_tree_scrolled_construct_from_spec_file (E_TREE_SCROLLED (tree),
+ E_TREE_MODEL (sd->ftree),
+ subscribe_get_global_extras (),
+ EVOLUTION_ETSPECDIR "/subscribe-dialog.etspec",
+ NULL);
+ e_tree_root_node_set_visible (e_tree_scrolled_get_tree(E_TREE_SCROLLED(tree)), TRUE);
+ gtk_signal_connect (GTK_OBJECT (e_tree_scrolled_get_tree(E_TREE_SCROLLED (tree))),
+ "double_click", GTK_SIGNAL_FUNC (sd_toggle_cb), sd);
+
+ gtk_object_unref (GTK_OBJECT (global_extras));
+
+ sd->widget = tree;
+ gtk_object_ref (GTK_OBJECT (sd->widget));
+
+ return sd->widget;
}
+typedef struct _selection_closure {
+ StoreData *sd;
+ enum { SET, CLEAR, TOGGLE } mode;
+} selection_closure;
+
static void
-populate_store_foreach (MailConfigService *service, SubscribeDialog *sc)
+sd_subscribe_folder_foreach (int model_row, gpointer closure)
{
- g_return_if_fail (service->url != NULL);
-
- subscribe_do_get_store (sc, service->url, store_cb, NULL);
+ selection_closure *sc = (selection_closure *) closure;
+ StoreData *sd = sc->sd;
+ ETree *tree = e_tree_scrolled_get_tree(E_TREE_SCROLLED(sd->widget));
+ ETreePath path = e_tree_node_at_row (tree, model_row);
+
+ /* ignore results */
+ switch (sc->mode) {
+ case SET:
+ folder_etree_path_set_subscription (sd->ftree, path, TRUE);
+ break;
+ case CLEAR:
+ folder_etree_path_set_subscription (sd->ftree, path, FALSE);
+ break;
+ case TOGGLE:
+ folder_etree_path_toggle_subscription (sd->ftree, path);
+ break;
+ }
}
static void
-populate_store_list (SubscribeDialog *sc)
+store_data_selection_set_subscription (StoreData *sd, gboolean subscribe)
{
- const GSList *news;
- GSList *sources;
-
- sources = mail_config_get_sources ();
- g_slist_foreach (sources, (GFunc)populate_store_foreach, sc);
- g_slist_free (sources);
+ selection_closure sc;
+ ETree *tree;
- news = mail_config_get_news ();
- g_slist_foreach ((GSList *)news, (GFunc)populate_store_foreach, sc);
-
- e_table_model_changed (sc->store_model);
+ sc.sd = sd;
+ if (subscribe)
+ sc.mode = SET;
+ else
+ sc.mode = CLEAR;
+
+ tree = e_tree_scrolled_get_tree (E_TREE_SCROLLED (sd->widget));
+ e_tree_selected_row_foreach (tree, sd_subscribe_folder_foreach, &sc);
}
+#ifdef NEED_TOGGLE_SELECTION
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)));
+store_data_selection_toggle_subscription (StoreData *sd)
+{
+ selection_closure sc;
+ ETree *tree;
- bonobo_ui_component_add_verb_list_with_data (
- component, verbs, sc);
+ sc.sd = sd;
+ sc.mode = TOGGLE;
+
+ tree = e_tree_scrolled_get_tree (E_TREE_SCROLLED (sd->widget));
+ e_tree_selected_row_foreach (tree, sd_subscribe_folder_foreach, &sc);
+}
+#endif
- bonobo_ui_component_freeze (component, NULL);
+static gboolean
+store_data_mid_request (StoreData *sd)
+{
+ return (gboolean) sd->request_id;
+}
- bonobo_ui_util_set_ui (component, EVOLUTION_DATADIR,
- "evolution-subscribe.xml",
- "evolution-subscribe");
+static void
+store_data_free (StoreData *sd)
+{
+ if (sd->request_id)
+ mail_msg_cancel (sd->request_id);
- e_pixmaps_update (component, pixmaps);
+ if (sd->widget)
+ gtk_object_unref (GTK_OBJECT (sd->widget));
- bonobo_ui_component_thaw (component, NULL);
+ if (sd->ftree)
+ gtk_object_unref (GTK_OBJECT (sd->ftree));
- sc->table = gtk_table_new (1, 2, FALSE);
+ if (sd->store)
+ camel_object_unref ((CamelObject *) sd->store);
- sc->hpaned = e_hpaned_new ();
+ g_free (sd->uri);
+ g_free (sd);
+}
- 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);
+/* ** yaay, SubscribeDialog ******************************************************* */
- bonobo_ui_component_object_set (component, "/Searchbar/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);
+#define PARENT_TYPE (gtk_object_get_type ())
- gtk_table_attach (GTK_TABLE (sc->table), sc->description->parent->parent,
- 0, 1, 0, 1,
- GTK_FILL | GTK_EXPAND,
- 0,
- 0, 0);
+#ifdef JUST_FOR_TRANSLATORS
+static char *str = N_("Folder");
#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);
+#define STORE_DATA_KEY "store-data"
- extras = e_table_extras_new ();
+struct _SubscribeDialogPrivate {
+ GladeXML *xml;
+ GList *store_list;
- sc->store_etable = e_table_scrolled_new (E_TABLE_MODEL(sc->store_model),
- extras, STORE_ETABLE_SPEC, NULL);
+ StoreData *current_store;
+ GtkWidget *current_widget;
- gtk_object_sink (GTK_OBJECT (extras));
+ GtkWidget *default_widget;
+ GtkWidget *none_item;
+ GtkWidget *search_entry;
+ GtkWidget *hbox;
+};
- 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);
+static GtkObjectClass *subscribe_dialog_parent_class;
- /* set up the folder etable */
- sc->folder_model = e_tree_memory_callbacks_new (folder_etree_icon_at,
+static void
+sc_refresh_pressed (GtkWidget *widget, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
- folder_etree_column_count,
+ e_utf8_gtk_entry_set_text (GTK_ENTRY (sc->priv->search_entry), "");
- NULL,
- NULL,
+ if (sc->priv->current_store)
+ folder_etree_clear_tree (sc->priv->current_store->ftree);
+}
- NULL,
- NULL,
+static void
+sc_search_activated (GtkWidget *widget, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+ StoreData *store = sc->priv->current_store;
+ char *search;
+ GtkWidget *filter_radio;
- folder_etree_value_at,
- folder_etree_set_value_at,
- folder_etree_is_editable,
+ filter_radio = glade_xml_get_widget (sc->priv->xml, "filter_radio");
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (filter_radio), TRUE);
- folder_etree_duplicate_value,
- folder_etree_free_value,
- folder_etree_init_value,
- folder_etree_value_is_empty,
- folder_etree_value_to_string,
+ if (!store)
+ return;
- sc);
+ search = e_utf8_gtk_entry_get_text (GTK_ENTRY (widget));
+ folder_etree_set_search (store->ftree, search);
+}
- e_tree_memory_set_expanded_default (E_TREE_MEMORY(sc->folder_model), TRUE);
+static void
+sc_subscribe_pressed (GtkWidget *widget, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+ StoreData *store = sc->priv->current_store;
- sc->folder_root = e_tree_memory_node_insert (E_TREE_MEMORY(sc->folder_model), NULL,
- 0, NULL);
+ if (!store)
+ return;
- toggles[0] = gdk_pixbuf_new_from_xpm_data ((const char **)empty_xpm);
- toggles[1] = gdk_pixbuf_new_from_xpm_data ((const char **)mark_xpm);
+ store_data_selection_set_subscription (store, TRUE);
+}
- extras = e_table_extras_new ();
+static void
+sc_unsubscribe_pressed (GtkWidget *widget, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+ StoreData *store = sc->priv->current_store;
- cell = e_cell_text_new(NULL, GTK_JUSTIFY_LEFT);
+ if (!store)
+ return;
- 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));
+ store_data_selection_set_subscription (store, FALSE);
+}
- gtk_object_set (GTK_OBJECT (cell),
- "bold_column", FOLDER_COL_SUBSCRIBED,
- NULL);
+static void
+sc_all_toggled (GtkWidget *widget, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+ StoreData *store = sc->priv->current_store;
+
+ if (!store)
+ return;
+
+ if (GTK_TOGGLE_BUTTON (widget)->active)
+ folder_etree_set_search (store->ftree, "");
+}
+
+static void
+sc_filter_toggled (GtkWidget *widget, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+ StoreData *store = sc->priv->current_store;
+
+ if (!store)
+ return;
+
+ if (GTK_TOGGLE_BUTTON (widget)->active)
+ sc_search_activated (sc->priv->search_entry, sc);
+}
+
+static void
+populate_store_foreach (MailConfigService *service, SubscribeDialog *sc)
+{
+ StoreData *sd;
- e_table_extras_add_pixbuf (extras, "subscribed-image", toggles[1]);
+ if (service->url == NULL || service->enabled == FALSE)
+ return;
- sc->folder_etree = e_tree_scrolled_new (E_TREE_MODEL(sc->folder_model),
- extras, FOLDER_ETREE_SPEC, NULL);
+ sd = store_data_new (service->url);
+ sc->priv->store_list = g_list_prepend (sc->priv->store_list, sd);
+}
- e_tree_root_node_set_visible (e_tree_scrolled_get_tree(E_TREE_SCROLLED(sc->folder_etree)), FALSE);
+static void
+menu_item_selected (GtkMenuItem *item, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+ StoreData *sd = gtk_object_get_data (GTK_OBJECT (item), STORE_DATA_KEY);
+ GtkWidget *toggle;
- gtk_object_sink (GTK_OBJECT (extras));
- gdk_pixbuf_unref(toggles[0]);
- gdk_pixbuf_unref(toggles[1]);
+ g_return_if_fail (sd);
- gtk_signal_connect (GTK_OBJECT (e_tree_scrolled_get_tree(E_TREE_SCROLLED (sc->folder_etree))),
- "double_click", GTK_SIGNAL_FUNC (folder_toggle_cb),
- sc);
- gtk_table_attach (
- GTK_TABLE (sc->table), sc->folder_etree,
- 0, 1, 1, 3,
- GTK_FILL | GTK_EXPAND,
- GTK_FILL | GTK_EXPAND,
- 0, 0);
+ if (sd->widget == NULL) {
+ GtkWidget *widget;
- 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);
+ widget = store_data_get_widget (sd);
+ gtk_box_pack_start (GTK_BOX (sc->priv->hbox), widget, TRUE, TRUE, 0);
+ }
- bonobo_window_set_contents (BONOBO_WINDOW (sc->app), sc->hpaned);
+ gtk_widget_hide (sc->priv->current_widget);
+ gtk_widget_hide (sc->priv->none_item); /* will happen redundantly... so what? */
+ gtk_widget_show (sd->widget);
+ sc->priv->current_widget = sd->widget;
+ sc->priv->current_store = sd;
+
+ if (sd->ftree->search) {
+ e_utf8_gtk_entry_set_text (GTK_ENTRY (sc->priv->search_entry), sd->ftree->search);
+ toggle = glade_xml_get_widget (sc->priv->xml, "filter_radio");
+ } else {
+ e_utf8_gtk_entry_set_text (GTK_ENTRY (sc->priv->search_entry), "");
+ toggle = glade_xml_get_widget (sc->priv->xml, "all_radio");
+ }
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), TRUE);
+}
-#if 0
- gtk_widget_show (sc->description);
-#endif
+static void
+dummy_item_selected (GtkMenuItem *item, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+ GtkWidget *all_toggle;
- gtk_widget_show (sc->folder_etree);
- gtk_widget_show (sc->table);
- gtk_widget_show (sc->store_etable);
- gtk_widget_show (sc->hpaned);
+ gtk_widget_hide (sc->priv->current_widget);
+ gtk_widget_show (sc->priv->default_widget);
+ sc->priv->current_widget = sc->priv->default_widget;
+ sc->priv->current_store = NULL;
- /* FIXME: Session management and stuff? */
- gtk_window_set_default_size (GTK_WINDOW (sc->app),
- DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ e_utf8_gtk_entry_set_text (GTK_ENTRY (sc->priv->search_entry), "");
- populate_store_list (sc);
+ all_toggle = glade_xml_get_widget (sc->priv->xml, "all_radio");
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (all_toggle), TRUE);
+}
+
+/* wonderful */
+
+static void
+got_sd_store (StoreData *sd, CamelStore *store, gpointer data)
+{
+ if (store && camel_store_supports_subscriptions (store))
+ gtk_widget_show (GTK_WIDGET (data));
+}
+
+/* FIXME: if there aren't any stores that are subscribable, the option
+ * menu will only have the "No server selected" item and the user will
+ * be confused. */
+
+static void
+populate_store_list (SubscribeDialog *sc)
+{
+ const GSList *news;
+ GSList *sources;
+ GList *iter;
+ GtkWidget *menu;
+ GtkWidget *omenu;
+
+ 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);
+
+ menu = gtk_menu_new ();
+
+ for (iter = sc->priv->store_list; iter; iter = iter->next) {
+ GtkWidget *item;
+ CamelURL *url;
+ gchar *string;
+
+ url = camel_url_new (((StoreData *) iter->data)->uri, NULL);
+ string = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
+ camel_url_free (url);
+ item = gtk_menu_item_new_with_label (string);
+ store_data_async_get_store (iter->data, got_sd_store, item);
+ gtk_object_set_data (GTK_OBJECT (item), STORE_DATA_KEY, iter->data);
+ gtk_signal_connect (GTK_OBJECT (item), "activate", menu_item_selected, sc);
+ g_free (string);
+
+ gtk_menu_prepend (GTK_MENU (menu), item);
+ /*gtk_object_unref (GTK_OBJECT (item));*/
+ }
+
+ sc->priv->none_item = gtk_menu_item_new_with_label (_("No server has been selected"));
+ gtk_signal_connect (GTK_OBJECT (sc->priv->none_item), "activate", dummy_item_selected, sc);
+ gtk_widget_show (sc->priv->none_item);
+ gtk_menu_prepend (GTK_MENU (menu), sc->priv->none_item);
+
+ gtk_widget_show (menu);
+
+ omenu = glade_xml_get_widget (sc->priv->xml, "store_menu");
+ gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu);
+ /*gtk_object_unref (GTK_OBJECT (menu));*/
}
static void
subscribe_dialog_destroy (GtkObject *object)
{
SubscribeDialog *sc;
+ GList *iter;
sc = SUBSCRIBE_DIALOG (object);
- /* free our folder information */
- e_tree_memory_node_remove (E_TREE_MEMORY(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);
+ for (iter = sc->priv->store_list; iter; iter = iter->next) {
+ if (store_data_mid_request (iter->data))
+ store_data_cancel_get_store (iter->data);
+ store_data_free (iter->data);
+ }
- /* free our store information */
- gtk_object_unref (GTK_OBJECT (sc->store_model));
- g_list_foreach (sc->store_list, (GFunc)gtk_object_unref, NULL);
+ g_list_free (sc->priv->store_list);
- /* free our storage */
- if (sc->storage)
- gtk_object_unref (GTK_OBJECT (sc->storage));
+ gtk_object_unref (GTK_OBJECT (sc->priv->xml));
- /* free our search */
- if (sc->search_top)
- g_free (sc->search_top);
+ g_free (sc->priv);
subscribe_dialog_parent_class->destroy (object);
}
@@ -1072,37 +1473,86 @@ subscribe_dialog_class_init (GtkObjectClass *object_class)
static void
subscribe_dialog_init (GtkObject *object)
{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (object);
+
+ sc->priv = g_new0 (SubscribeDialogPrivate, 1);
+}
+
+static GtkWidget *
+sc_create_default_widget (void)
+{
+ GtkWidget *label;
+ GtkWidget *viewport;
+
+ label = gtk_label_new (_("Please select a server."));
+ gtk_widget_show (label);
+
+ viewport = gtk_viewport_new (NULL, NULL);
+ gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (viewport), label);
+
+ return viewport;
}
static void
-subscribe_dialog_construct (GtkObject *object, GNOME_Evolution_Shell shell)
+subscribe_dialog_construct (GtkObject *object)
{
SubscribeDialog *sc = SUBSCRIBE_DIALOG (object);
+ GtkWidget *widget;
+
+ /* Load the XML */
+
+ sc->priv->xml = glade_xml_new (EVOLUTION_GLADEDIR "/subscribe-dialog.glade", NULL);
+ sc->app = glade_xml_get_widget (sc->priv->xml, "Manage Subscriptions");
+ sc->priv->hbox = glade_xml_get_widget (sc->priv->xml, "tree_box");
+ sc->priv->search_entry = glade_xml_get_widget (sc->priv->xml, "search_entry");
+
+ /* create default view */
+
+ sc->priv->default_widget = sc_create_default_widget();
+ sc->priv->current_widget = sc->priv->default_widget;
+ gtk_box_pack_start (GTK_BOX (sc->priv->hbox), sc->priv->default_widget, TRUE, TRUE, 0);
+ gtk_widget_show (sc->priv->default_widget);
+
+ /* hook up some signals */
+
+ gtk_signal_connect (GTK_OBJECT (sc->priv->search_entry), "activate", sc_search_activated, sc);
+
+ widget = glade_xml_get_widget (sc->priv->xml, "subscribe_button");
+ gtk_signal_connect (GTK_OBJECT (widget), "clicked", sc_subscribe_pressed, sc);
+
+ widget = glade_xml_get_widget (sc->priv->xml, "unsubscribe_button");
+ gtk_signal_connect (GTK_OBJECT (widget), "clicked", sc_unsubscribe_pressed, sc);
- /*
- * Our instance data
- */
- sc->shell = shell;
- sc->store = NULL;
- sc->storage = NULL;
- sc->folder_info = NULL;
- sc->store_list = NULL;
- sc->search_top = NULL;
+ widget = glade_xml_get_widget (sc->priv->xml, "refresh_button");
+ gtk_signal_connect (GTK_OBJECT (widget), "clicked", sc_refresh_pressed, sc);
- subscribe_dialog_gui_init (sc);
+ widget = glade_xml_get_widget (sc->priv->xml, "all_radio");
+ gtk_signal_connect (GTK_OBJECT (widget), "toggled", sc_all_toggled, sc);
+
+ widget = glade_xml_get_widget (sc->priv->xml, "filter_radio");
+ gtk_signal_connect (GTK_OBJECT (widget), "toggled", sc_filter_toggled, sc);
+
+ /* Get the list of stores */
+
+ populate_store_list (sc);
}
-GtkWidget *
-subscribe_dialog_new (GNOME_Evolution_Shell shell)
+GtkObject *
+subscribe_dialog_new (void)
{
SubscribeDialog *subscribe_dialog;
- subscribe_dialog = gtk_type_new (subscribe_dialog_get_type ());
+ subscribe_dialog = gtk_type_new (SUBSCRIBE_DIALOG_TYPE);
+ subscribe_dialog_construct (GTK_OBJECT (subscribe_dialog));
- subscribe_dialog_construct (GTK_OBJECT (subscribe_dialog), shell);
-
- return GTK_WIDGET (subscribe_dialog->app);
+ return GTK_OBJECT (subscribe_dialog);
}
E_MAKE_TYPE (subscribe_dialog, "SubscribeDialog", SubscribeDialog, subscribe_dialog_class_init, subscribe_dialog_init, PARENT_TYPE);
+void
+subscribe_dialog_run_and_close (SubscribeDialog *dialog)
+{
+ gnome_dialog_run_and_close (GNOME_DIALOG (dialog->app));
+}
diff --git a/mail/subscribe-dialog.etspec b/mail/subscribe-dialog.etspec
new file mode 100644
index 0000000000..1f5decbb36
--- /dev/null
+++ b/mail/subscribe-dialog.etspec
@@ -0,0 +1,9 @@
+<ETableSpecification cursor-mode="line" no-headers="true">
+ <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>
diff --git a/mail/subscribe-dialog.glade b/mail/subscribe-dialog.glade
index 5169f450c3..472491b3e8 100644
--- a/mail/subscribe-dialog.glade
+++ b/mail/subscribe-dialog.glade
@@ -15,12 +15,13 @@
<widget>
<class>GnomeDialog</class>
- <name>subscriptions</name>
- <visible>False</visible>
- <title></title>
+ <name>Manage Subscriptions</name>
+ <title>Manage Subscriptions</title>
<type>GTK_WINDOW_TOPLEVEL</type>
<position>GTK_WIN_POS_NONE</position>
- <modal>True</modal>
+ <modal>False</modal>
+ <default_width>484</default_width>
+ <default_height>423</default_height>
<allow_shrink>False</allow_shrink>
<allow_grow>True</allow_grow>
<auto_shrink>False</auto_shrink>
@@ -30,7 +31,7 @@
<widget>
<class>GtkVBox</class>
<child_name>GnomeDialog:vbox</child_name>
- <name>dialog-vbox1</name>
+ <name>dialog-vbox2</name>
<homogeneous>False</homogeneous>
<spacing>8</spacing>
<child>
@@ -42,7 +43,7 @@
<widget>
<class>GtkHButtonBox</class>
<child_name>GnomeDialog:action_area</child_name>
- <name>dialog-action_area1</name>
+ <name>dialog-action_area2</name>
<layout_style>GTK_BUTTONBOX_END</layout_style>
<spacing>8</spacing>
<child_min_width>85</child_min_width>
@@ -58,36 +59,19 @@
<widget>
<class>GtkButton</class>
- <name>button1</name>
+ <name>button9</name>
<can_default>True</can_default>
<can_focus>True</can_focus>
- <stock_button>GNOME_STOCK_BUTTON_OK</stock_button>
- </widget>
-
- <widget>
- <class>GtkButton</class>
- <name>button2</name>
- <can_default>True</can_default>
- <can_focus>True</can_focus>
- <stock_button>GNOME_STOCK_BUTTON_APPLY</stock_button>
- </widget>
-
- <widget>
- <class>GtkButton</class>
- <name>button3</name>
- <can_default>True</can_default>
- <has_default>True</has_default>
- <can_focus>True</can_focus>
- <has_focus>True</has_focus>
- <stock_button>GNOME_STOCK_BUTTON_CANCEL</stock_button>
+ <stock_button>GNOME_STOCK_BUTTON_CLOSE</stock_button>
</widget>
</widget>
<widget>
<class>GtkVBox</class>
- <name>vbox1</name>
+ <name>vbox2</name>
+ <border_width>3</border_width>
<homogeneous>False</homogeneous>
- <spacing>0</spacing>
+ <spacing>3</spacing>
<child>
<padding>0</padding>
<expand>True</expand>
@@ -95,199 +79,243 @@
</child>
<widget>
- <class>GtkTable</class>
- <name>table</name>
- <rows>3</rows>
- <columns>2</columns>
+ <class>GtkHBox</class>
+ <name>hbox1</name>
<homogeneous>False</homogeneous>
- <row_spacing>0</row_spacing>
- <column_spacing>3</column_spacing>
+ <spacing>0</spacing>
<child>
<padding>0</padding>
- <expand>True</expand>
+ <expand>False</expand>
<fill>True</fill>
</child>
<widget>
<class>GtkLabel</class>
- <name>lblDisplay</name>
- <label>Display folders whose name contain:</label>
- <justify>GTK_JUSTIFY_LEFT</justify>
+ <name>label1</name>
+ <label>Show _folders from server: </label>
+ <justify>GTK_JUSTIFY_CENTER</justify>
<wrap>False</wrap>
- <xalign>0</xalign>
+ <xalign>0.5</xalign>
<yalign>0.5</yalign>
<xpad>0</xpad>
<ypad>0</ypad>
+ <default_focus_target>store_menu</default_focus_target>
<child>
- <left_attach>0</left_attach>
- <right_attach>1</right_attach>
- <top_attach>0</top_attach>
- <bottom_attach>1</bottom_attach>
- <xpad>0</xpad>
- <ypad>0</ypad>
- <xexpand>False</xexpand>
- <yexpand>False</yexpand>
- <xshrink>False</xshrink>
- <yshrink>False</yshrink>
- <xfill>False</xfill>
- <yfill>False</yfill>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
</child>
</widget>
<widget>
- <class>GtkEntry</class>
- <name>txtSearch``</name>
+ <class>GtkOptionMenu</class>
+ <name>store_menu</name>
<can_focus>True</can_focus>
- <editable>True</editable>
- <text_visible>True</text_visible>
- <text_max_length>0</text_max_length>
- <text></text>
+ <items></items>
+ <initial_choice>0</initial_choice>
<child>
- <left_attach>0</left_attach>
- <right_attach>1</right_attach>
- <top_attach>1</top_attach>
- <bottom_attach>2</bottom_attach>
- <xpad>0</xpad>
- <ypad>0</ypad>
- <xexpand>True</xexpand>
- <yexpand>False</yexpand>
- <xshrink>False</xshrink>
- <yshrink>False</yshrink>
- <xfill>True</xfill>
- <yfill>False</yfill>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
</child>
</widget>
+ </widget>
+
+ <widget>
+ <class>GtkHBox</class>
+ <name>tree_box</name>
+ <homogeneous>False</homogeneous>
+ <spacing>0</spacing>
+ <child>
+ <padding>0</padding>
+ <expand>True</expand>
+ <fill>True</fill>
+ </child>
+
+ <widget>
+ <class>Placeholder</class>
+ </widget>
<widget>
- <class>GtkNotebook</class>
- <name>notebook</name>
- <can_focus>True</can_focus>
- <show_tabs>True</show_tabs>
- <show_border>True</show_border>
- <tab_pos>GTK_POS_BOTTOM</tab_pos>
- <scrollable>False</scrollable>
- <tab_hborder>2</tab_hborder>
- <tab_vborder>2</tab_vborder>
- <popup_enable>False</popup_enable>
+ <class>GtkVBox</class>
+ <name>vbox3</name>
+ <border_width>3</border_width>
+ <homogeneous>False</homogeneous>
+ <spacing>3</spacing>
<child>
- <left_attach>0</left_attach>
- <right_attach>1</right_attach>
- <top_attach>2</top_attach>
- <bottom_attach>3</bottom_attach>
- <xpad>0</xpad>
- <ypad>0</ypad>
- <xexpand>False</xexpand>
- <yexpand>True</yexpand>
- <xshrink>False</xshrink>
- <yshrink>False</yshrink>
- <xfill>True</xfill>
- <yfill>True</yfill>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
+ <pack>GTK_PACK_END</pack>
</child>
<widget>
- <class>Custom</class>
- <name>etableAll</name>
- <creation_function>create_folderlist</creation_function>
- <int1>0</int1>
- <int2>0</int2>
- <last_modification_time>Thu, 09 Nov 2000 23:31:36 GMT</last_modification_time>
- </widget>
-
- <widget>
<class>GtkLabel</class>
- <child_name>Notebook:tab</child_name>
- <name>lblAll</name>
- <label>All Folders</label>
+ <name>label2</name>
+ <label>
+</label>
<justify>GTK_JUSTIFY_CENTER</justify>
<wrap>False</wrap>
<xalign>0.5</xalign>
<yalign>0.5</yalign>
<xpad>0</xpad>
<ypad>0</ypad>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
+ </child>
</widget>
<widget>
- <class>Custom</class>
- <name>etableSubscribed</name>
- <creation_function>create_folderlist</creation_function>
- <int1>1</int1>
- <int2>0</int2>
- <last_modification_time>Thu, 09 Nov 2000 23:30:19 GMT</last_modification_time>
+ <class>GtkVButtonBox</class>
+ <name>vbuttonbox2</name>
+ <layout_style>GTK_BUTTONBOX_SPREAD</layout_style>
+ <spacing>0</spacing>
+ <child_min_width>85</child_min_width>
+ <child_min_height>27</child_min_height>
+ <child_ipad_x>7</child_ipad_x>
+ <child_ipad_y>0</child_ipad_y>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
+ </child>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>subscribe_button</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <label>_Subscribe</label>
+ <relief>GTK_RELIEF_NORMAL</relief>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>unsubscribe_button</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <label>_Unsubscribe</label>
+ <relief>GTK_RELIEF_NORMAL</relief>
+ </widget>
</widget>
<widget>
- <class>GtkLabel</class>
- <child_name>Notebook:tab</child_name>
- <name>lblSubscribed</name>
- <label>Subscribed</label>
- <justify>GTK_JUSTIFY_CENTER</justify>
- <wrap>False</wrap>
- <xalign>0.5</xalign>
- <yalign>0.5</yalign>
- <xpad>0</xpad>
- <ypad>0</ypad>
+ <class>GtkHSeparator</class>
+ <name>hseparator1</name>
+ <child>
+ <padding>14</padding>
+ <expand>False</expand>
+ <fill>False</fill>
+ </child>
</widget>
- </widget>
- <widget>
- <class>GtkButton</class>
- <name>cmdQuery</name>
- <can_focus>True</can_focus>
- <label>Query</label>
- <child>
- <left_attach>1</left_attach>
- <right_attach>2</right_attach>
- <top_attach>1</top_attach>
- <bottom_attach>2</bottom_attach>
- <xpad>5</xpad>
- <ypad>0</ypad>
- <xexpand>False</xexpand>
- <yexpand>False</yexpand>
- <xshrink>False</xshrink>
- <yshrink>False</yshrink>
- <xfill>True</xfill>
- <yfill>False</yfill>
- </child>
+ <widget>
+ <class>GtkVButtonBox</class>
+ <name>vbuttonbox3</name>
+ <layout_style>GTK_BUTTONBOX_START</layout_style>
+ <spacing>10</spacing>
+ <child_min_width>85</child_min_width>
+ <child_min_height>27</child_min_height>
+ <child_ipad_x>7</child_ipad_x>
+ <child_ipad_y>0</child_ipad_y>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
+ </child>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>refresh_button</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <label> _Refresh List </label>
+ <relief>GTK_RELIEF_NORMAL</relief>
+ </widget>
+ </widget>
</widget>
+ </widget>
+
+ <widget>
+ <class>GtkFrame</class>
+ <name>frame1</name>
+ <label>Display options</label>
+ <label_xalign>0</label_xalign>
+ <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>True</fill>
+ </child>
<widget>
- <class>GtkVButtonBox</class>
- <name>vbuttonbox1</name>
- <layout_style>GTK_BUTTONBOX_DEFAULT_STYLE</layout_style>
- <spacing>0</spacing>
- <child_min_width>85</child_min_width>
- <child_min_height>27</child_min_height>
- <child_ipad_x>7</child_ipad_x>
- <child_ipad_y>0</child_ipad_y>
- <child>
- <left_attach>1</left_attach>
- <right_attach>2</right_attach>
- <top_attach>2</top_attach>
- <bottom_attach>3</bottom_attach>
- <xpad>0</xpad>
- <ypad>0</ypad>
- <xexpand>False</xexpand>
- <yexpand>False</yexpand>
- <xshrink>False</xshrink>
- <yshrink>False</yshrink>
- <xfill>True</xfill>
- <yfill>True</yfill>
- </child>
+ <class>GtkHBox</class>
+ <name>hbox3</name>
+ <border_width>3</border_width>
+ <homogeneous>False</homogeneous>
+ <spacing>3</spacing>
+
+ <widget>
+ <class>GtkRadioButton</class>
+ <name>all_radio</name>
+ <can_focus>True</can_focus>
+ <label>All folders</label>
+ <active>False</active>
+ <draw_indicator>True</draw_indicator>
+ <group>view_type</group>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
+ </child>
+ </widget>
<widget>
- <class>GtkButton</class>
- <name>cmdSubscribe</name>
- <can_default>True</can_default>
+ <class>GtkRadioButton</class>
+ <name>filter_radio</name>
<can_focus>True</can_focus>
- <label>Subscribe</label>
+ <label>Folders whose names begin with:</label>
+ <active>False</active>
+ <draw_indicator>True</draw_indicator>
+ <group>view_type</group>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
+ </child>
</widget>
<widget>
- <class>GtkButton</class>
- <name>cmdUnsubscribe</name>
- <can_default>True</can_default>
+ <class>GtkEntry</class>
+ <name>search_entry</name>
<can_focus>True</can_focus>
- <label>Unsubscribe</label>
+ <editable>True</editable>
+ <text_visible>True</text_visible>
+ <text_max_length>0</text_max_length>
+ <text></text>
+ <child>
+ <padding>0</padding>
+ <expand>True</expand>
+ <fill>True</fill>
+ </child>
+ </widget>
+
+ <widget>
+ <class>GtkHButtonBox</class>
+ <name>hbuttonbox1</name>
+ <layout_style>GTK_BUTTONBOX_DEFAULT_STYLE</layout_style>
+ <spacing>30</spacing>
+ <child_min_width>85</child_min_width>
+ <child_min_height>27</child_min_height>
+ <child_ipad_x>7</child_ipad_x>
+ <child_ipad_y>0</child_ipad_y>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
+ </child>
</widget>
</widget>
</widget>
diff --git a/mail/subscribe-dialog.h b/mail/subscribe-dialog.h
index 2696acf2e2..10fa5d9f44 100644
--- a/mail/subscribe-dialog.h
+++ b/mail/subscribe-dialog.h
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Authors: Chris Toshok <toshok@ximian.com>
+ * Peter Williams <peterw@ximian.com>
*
* Copyright 2000 Ximian, Inc. (www.ximian.com)
*
@@ -39,32 +40,12 @@
#define IS_SUBSCRIBE_DIALOG(o) (GTK_CHECK_TYPE ((o), SUBSCRIBE_DIALOG_TYPE))
#define IS_SUBSCRIBE_DIALOG_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), SUBSCRIBE_DIALOG_TYPE))
+typedef struct _SubscribeDialogPrivate SubscribeDialogPrivate;
struct _SubscribeDialog {
- GtkObject parent;
+ GtkObject parent;
- GNOME_Evolution_Shell shell;
-
- GtkWidget *app;
-
- GtkWidget *hpaned;
- GtkWidget *table;
- GtkWidget *description;
-
- GtkWidget *store_etable;
- ETableModel *store_model;
-
- GtkWidget *folder_etree;
- ETreeModel *folder_model;
- ETreePath folder_root;
-
- CamelStore *store;
- EvolutionStorage *storage;
- CamelFolderInfo *folder_info;
-
- GList *store_list;
-
- GtkWidget *search_entry;
- char *search_top;
+ GtkWidget *app;
+ SubscribeDialogPrivate *priv;
};
@@ -72,7 +53,8 @@ typedef struct {
GtkObjectClass parent_class;
} SubscribeDialogClass;
-GtkType subscribe_dialog_get_type (void);
-GtkWidget *subscribe_dialog_new (GNOME_Evolution_Shell shell);
+GtkType subscribe_dialog_get_type (void);
+GtkObject *subscribe_dialog_new (void);
+void subscribe_dialog_run_and_close (SubscribeDialog *dialog);
#endif /* _SUBSCRIBE_DIALOG_H_ */