diff options
author | Jeffrey Stedfast <fejj@ximian.com> | 2003-11-14 03:02:07 +0800 |
---|---|---|
committer | Jeffrey Stedfast <fejj@src.gnome.org> | 2003-11-14 03:02:07 +0800 |
commit | fd244132adb4225b6982422632bd69bc57b4e589 (patch) | |
tree | e6f706c7bb025b7bd90498aa3a6517924955a6a7 | |
parent | 4e093efda9886a3c51cdefd3fc236807a34e11f9 (diff) | |
download | gsoc2013-evolution-fd244132adb4225b6982422632bd69bc57b4e589.tar.gz gsoc2013-evolution-fd244132adb4225b6982422632bd69bc57b4e589.tar.zst gsoc2013-evolution-fd244132adb4225b6982422632bd69bc57b4e589.zip |
New folder-tree widget that replaces the shell's folder-tree widget.
2003-11-13 Jeffrey Stedfast <fejj@ximian.com>
* em-folder-tree.[c,h]: New folder-tree widget that replaces the
shell's folder-tree widget.
* em-folder-tree-model.[c,h]: New source files subclassing
GtkTreeStore for handling the mess that is drag&drop.
* em-folder-selection-button.c: Ported to use EMFolderTree.
* em-folder-selection.c: Ported to use EMFolderTree.
* em-folder-selector.c: Ported to use EMFolderTree.
* mail-component.c: Ported to use EMFolderTree.
* mail-offline-handler.c (storage_go_online): Updated to not pass
a storage argument.
* mail-folder-cache.c: Removed storage stuff.
* mail-send-recv.c (receive_update_got_store): Don't do EStorage*
stuff anymore.
svn path=/trunk/; revision=23331
-rw-r--r-- | mail/ChangeLog | 62 | ||||
-rw-r--r-- | mail/Makefile.am | 4 | ||||
-rw-r--r-- | mail/em-folder-selection-button.c | 322 | ||||
-rw-r--r-- | mail/em-folder-selection-button.h | 72 | ||||
-rw-r--r-- | mail/em-folder-selection.c | 31 | ||||
-rw-r--r-- | mail/em-folder-selection.h | 55 | ||||
-rw-r--r-- | mail/em-folder-selector.c | 434 | ||||
-rw-r--r-- | mail/em-folder-selector.h | 70 | ||||
-rw-r--r-- | mail/em-folder-tree-model.c | 284 | ||||
-rw-r--r-- | mail/em-folder-tree-model.h | 81 | ||||
-rw-r--r-- | mail/em-folder-tree.c | 1516 | ||||
-rw-r--r-- | mail/em-folder-tree.h | 13 | ||||
-rw-r--r-- | mail/em-marshal.list | 5 | ||||
-rw-r--r-- | mail/mail-component-factory.c | 2 | ||||
-rw-r--r-- | mail/mail-component.c | 1515 | ||||
-rw-r--r-- | mail/mail-component.h | 11 | ||||
-rw-r--r-- | mail/mail-folder-cache.c | 83 | ||||
-rw-r--r-- | mail/mail-folder-cache.h | 14 | ||||
-rw-r--r-- | mail/mail-offline-handler.c | 2 | ||||
-rw-r--r-- | mail/mail-send-recv.c | 16 |
20 files changed, 2277 insertions, 2315 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index 0413bf7094..ae41feb26a 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,27 @@ +2003-11-13 Jeffrey Stedfast <fejj@ximian.com> + + * em-folder-tree.[c,h]: New folder-tree widget that replaces the + shell's folder-tree widget. + + * em-folder-tree-model.[c,h]: New source files subclassing + GtkTreeStore for handling the mess that is drag&drop. + + * em-folder-selection-button.c: Ported to use EMFolderTree. + + * em-folder-selection.c: Ported to use EMFolderTree. + + * em-folder-selector.c: Ported to use EMFolderTree. + + * mail-component.c: Ported to use EMFolderTree. + + * mail-offline-handler.c (storage_go_online): Updated to not pass + a storage argument. + + * mail-folder-cache.c: Removed storage stuff. + + * mail-send-recv.c (receive_update_got_store): Don't do EStorage* + stuff anymore. + 2003-11-13 Ettore Perazzoli <ettore@ximian.com> * mail-component.c (impl__get_userCreatableItems): New, @@ -31,7 +55,8 @@ 2003-11-11 Not Zed <NotZed@Ximian.com> - * em-format-html.c (efh_application_xpkcs7mime): output icons of the status. + * em-format-html.c (efh_application_xpkcs7mime): output icons of + the status. (em_format_html_add_pobject): Changed to take a size specificier, return the pobject, and re-ordered args to be more consistent with puri stuff. @@ -77,6 +102,41 @@ * Makefile.am: build the marshall files right at the beginning +2003-11-11 Not Zed <NotZed@Ximian.com> + + * mail-security.glade: new glade file for security related stuff. + + * mail-config.glade: removed the message security dialogue, it + gets opened automatically by the config code :( + +2003-11-10 Ettore Perazzoli <ettore@ximian.com> + + * GNOME_Evolution_Mail.server.in.in: Set an + "evolution:component_alias" property with a value of "mail". + +2003-11-10 Not Zed <NotZed@Ximian.com> + + * em-format-html.c (em_format_html_multipart_signed_sign): changed + for cipher context api changes. + * em-format.c (emf_multipart_signed): ditto. + +2003-11-07 Not Zed <NotZed@Ximian.com> + + * mail-config.glade: added security_information_dialog (probably + temporarily in this file). + + * em-format.c (em_format_is_attachment): also treat pkcs7-mime as + non-attachment. + (emf_application_xpkcs7mime): no longer need to worry about + scanning the part. + +2003-11-07 Dan Winship <danw@ximian.com> + + * message-list.c: Don't #include e-name-western.h, since the code + that uses it is commented out, and we want to remove the local + copy, but we don't want to make the mailer depend on the e-d-s + copy if it's not even going to be using it. + 2003-11-07 JP Rosevear <jpr@ximian.com> * Makefile.am: Make sure the marshal files are listed above other diff --git a/mail/Makefile.am b/mail/Makefile.am index 417ee0be24..858f25c3de 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -77,6 +77,10 @@ libevolution_mail_la_SOURCES = \ em-folder-selection-button.h \ em-folder-selector.c \ em-folder-selector.h \ + em-folder-tree.c \ + em-folder-tree.h \ + em-folder-tree-model.c \ + em-folder-tree-model.h \ em-folder-view.c \ em-folder-view.h \ em-folder-browser.c \ diff --git a/mail/em-folder-selection-button.c b/mail/em-folder-selection-button.c index ac5a6e1d06..42964a10b2 100644 --- a/mail/em-folder-selection-button.c +++ b/mail/em-folder-selection-button.c @@ -1,51 +1,60 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* em-folder-selection-button.c +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> * - * Copyright (C) 2003 Ximian, Inc. + * Copyright 2003 Ximian, Inc. (www.ximian.com) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. + * This program is 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. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * 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. * - * Author: Ettore Perazzoli <ettore@ximian.com> */ + +#ifdef HAVE_CONFIG_H #include <config.h> +#endif #include <string.h> -#include "em-folder-selection-button.h" +#include <gtk/gtkimage.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkhbox.h> + +#include <gal/util/e-util.h> #include "mail-component.h" +#include "em-folder-tree.h" #include "em-folder-selector.h" -#include <gal/util/e-util.h> +#include "em-folder-selection-button.h" -#include <gtk/gtkimage.h> -#include <gtk/gtklabel.h> -#include <gtk/gtkhbox.h> +static void em_folder_selection_button_class_init (EMFolderSelectionButtonClass *klass); +static void em_folder_selection_button_init (EMFolderSelectionButton *emfsb); +static void em_folder_selection_button_destroy (GtkObject *obj); +static void em_folder_selection_button_finalize (GObject *obj); +static void em_folder_selection_button_clicked (GtkButton *button); -#define PARENT_TYPE gtk_button_get_type () static GtkButtonClass *parent_class = NULL; struct _EMFolderSelectionButtonPrivate { GtkWidget *icon; GtkWidget *label; - + char *uri; - + char *title; char *caption; }; @@ -54,10 +63,55 @@ enum { SELECTED, LAST_SIGNAL }; + static guint signals[LAST_SIGNAL] = { 0 }; -/* Utility functions. */ +GType +em_folder_selection_button_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (EMFolderSelectionButtonClass), + NULL, /* base_class_init */ + NULL, /* base_class_finalize */ + (GClassInitFunc) em_folder_selection_button_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EMFolderSelectionButton), + 0, /* n_preallocs */ + (GInstanceInitFunc) em_folder_selection_button_init, + }; + + type = g_type_register_static (GTK_TYPE_BUTTON, "EMFolderSelectionButton", &info, 0); + } + + return type; +} + +static void +em_folder_selection_button_class_init (EMFolderSelectionButtonClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass); + GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass); + + parent_class = g_type_class_ref (GTK_TYPE_BUTTON); + + object_class->finalize = em_folder_selection_button_finalize; + gtk_object_class->destroy = em_folder_selection_button_destroy; + button_class->clicked = em_folder_selection_button_clicked; + + signals[SELECTED] = g_signal_new ("selected", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EMFolderSelectionButtonClass, selected), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} static void set_contents_unselected (EMFolderSelectionButton *button) @@ -69,174 +123,140 @@ set_contents_unselected (EMFolderSelectionButton *button) static void set_contents (EMFolderSelectionButton *button) { - EMFolderSelectionButtonPrivate *priv = button->priv; - char *path, *tmp, *label; - - if (priv->uri == NULL) - goto unset; - - /* We set the button name directly from the storage set path, which is /accountname/path/foldername */ - path = e_storage_set_get_path_for_physical_uri(mail_component_peek_storage_set(mail_component_peek()), priv->uri); - - if (path == NULL) - goto unknown; - - tmp = strchr(path+1, '/'); - if (tmp == NULL) - goto unknown; - *tmp++ = 0; - - label = g_strdup_printf(_("\"%s\" in \"%s\""), tmp, path+1); - gtk_label_set_text (GTK_LABEL (priv->label), label); - g_free (label); - - g_free(path); - return; + struct _EMFolderSelectionButtonPrivate *priv = button->priv; + const char *path; + CamelURL *url; + + if (priv->uri == NULL) { + set_contents_unselected (button); + return; + } + + url = camel_url_new (priv->uri, NULL); + path = url->fragment ? url->fragment : url->path; + + if (path == NULL) { + camel_url_free (url); + set_contents_unselected (button); + return; + } + + gtk_label_set_text (GTK_LABEL (priv->label), path); + camel_url_free (url); +} -unknown: - g_free(path); -unset: - set_contents_unselected(button); +static void +em_folder_selection_button_init (EMFolderSelectionButton *emfsb) +{ + struct _EMFolderSelectionButtonPrivate *priv; + GtkWidget *box; + + priv = g_new0 (struct _EMFolderSelectionButtonPrivate, 1); + emfsb->priv = priv; + + box = gtk_hbox_new (FALSE, 4); + + priv->icon = gtk_image_new (); + gtk_widget_show (priv->icon); + gtk_box_pack_start (GTK_BOX (box), priv->icon, FALSE, TRUE, 0); + + priv->label = gtk_label_new (""); + gtk_widget_show (priv->label); + gtk_label_set_justify (GTK_LABEL (priv->label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.0); + gtk_box_pack_start (GTK_BOX (box), priv->label, TRUE, TRUE, 0); + + gtk_widget_show (box); + gtk_container_add (GTK_CONTAINER (emfsb), box); + + set_contents (emfsb); } static void -impl_finalize (GObject *object) +em_folder_selection_button_destroy (GtkObject *obj) { - EMFolderSelectionButtonPrivate *priv = EM_FOLDER_SELECTION_BUTTON (object)->priv; + GTK_OBJECT_CLASS (parent_class)->destroy (obj); +} +static void +em_folder_selection_button_finalize (GObject *obj) +{ + struct _EMFolderSelectionButtonPrivate *priv = ((EMFolderSelectionButton *) obj)->priv; + g_free (priv->title); g_free (priv->caption); - g_free(priv->uri); + g_free (priv->uri); g_free (priv); - - (* G_OBJECT_CLASS (parent_class)->finalize) (object); + + G_OBJECT_CLASS (parent_class)->finalize (obj); } static void -emfsb_selector_response(EMFolderSelector *emfs, int response, EMFolderSelectionButton *button) +emfsb_selector_response (EMFolderSelector *emfs, int response, EMFolderSelectionButton *button) { if (response == GTK_RESPONSE_OK) { - const char *uri = em_folder_selector_get_selected_uri(emfs); - - em_folder_selection_button_set_selection(button, uri); - g_signal_emit(button, signals[SELECTED], 0); + const char *uri = em_folder_selector_get_selected_uri (emfs); + + em_folder_selection_button_set_selection (button, uri); + g_signal_emit (button, signals[SELECTED], 0); } - - gtk_widget_destroy((GtkWidget *)emfs); + + gtk_widget_destroy ((GtkWidget *) emfs); } static void -impl_clicked (GtkButton *button) +em_folder_selection_button_clicked (GtkButton *button) { - EMFolderSelectionButtonPrivate *priv = EM_FOLDER_SELECTION_BUTTON (button)->priv; - EStorageSet *ess; - GtkWidget *w; - GtkWidget *toplevel; - + struct _EMFolderSelectionButtonPrivate *priv = EM_FOLDER_SELECTION_BUTTON (button)->priv; + EMFolderTreeModel *model; + EMFolderTree *emft; + GtkWidget *dialog; + if (GTK_BUTTON_CLASS (parent_class)->clicked != NULL) (* GTK_BUTTON_CLASS (parent_class)->clicked) (button); - - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button)); - ess = mail_component_peek_storage_set(mail_component_peek()); - w = em_folder_selector_new(ess, EM_FOLDER_SELECTOR_CAN_CREATE, priv->title, priv->caption); - em_folder_selector_set_selected_uri((EMFolderSelector *)w, priv->uri); - g_signal_connect(w, "response", G_CALLBACK(emfsb_selector_response), button); - gtk_widget_show(w); -} -#if 0 -{ - uri = em_folder_selection_run_dialog_uri((GtkWindow *)toplevel, - priv->title, - priv->caption, - priv->uri); - - em_folder_selection_button_set_selection (EM_FOLDER_SELECTION_BUTTON (button), uri); - g_free(uri); - - g_signal_emit (button, signals[SELECTED], 0); -} -#endif - -static void -class_init (EMFolderSelectionButtonClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (class); - GtkButtonClass *button_class = GTK_BUTTON_CLASS (class); - - object_class->finalize = impl_finalize; - - button_class->clicked = impl_clicked; - - parent_class = g_type_class_peek_parent (class); - - signals[SELECTED] = g_signal_new ("selected", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (EMFolderSelectionButtonClass, selected), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + + model = mail_component_get_tree_model (mail_component_peek ()); + emft = em_folder_tree_new_with_model (model); + + dialog = em_folder_selector_new (emft, EM_FOLDER_SELECTOR_CAN_CREATE, priv->title, priv->caption); + em_folder_selector_set_selected ((EMFolderSelector *) dialog, priv->uri); + g_signal_connect (dialog, "response", G_CALLBACK (emfsb_selector_response), button); + gtk_widget_show (dialog); } -static void -init (EMFolderSelectionButton *folder_selection_button) -{ - EMFolderSelectionButtonPrivate *priv; - GtkWidget *box; - - priv = g_new0 (EMFolderSelectionButtonPrivate, 1); - folder_selection_button->priv = priv; - - box = gtk_hbox_new (FALSE, 4); - - priv->icon = gtk_image_new (); - gtk_box_pack_start (GTK_BOX (box), priv->icon, FALSE, TRUE, 0); - - priv->label = gtk_label_new (""); - gtk_label_set_justify (GTK_LABEL (priv->label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.0); - gtk_box_pack_start (GTK_BOX (box), priv->label, TRUE, TRUE, 0); - - gtk_widget_show_all (box); - gtk_container_add (GTK_CONTAINER (folder_selection_button), box); - - set_contents (folder_selection_button); -} GtkWidget * -em_folder_selection_button_new(const char *title, const char *caption) +em_folder_selection_button_new (const char *title, const char *caption) { EMFolderSelectionButton *button = g_object_new (EM_TYPE_FOLDER_SELECTION_BUTTON, NULL); - + button->priv->title = g_strdup (title); button->priv->caption = g_strdup (caption); - + return GTK_WIDGET (button); } void -em_folder_selection_button_set_selection(EMFolderSelectionButton *button, const char *uri) +em_folder_selection_button_set_selection (EMFolderSelectionButton *button, const char *uri) { - EMFolderSelectionButtonPrivate *p = button->priv; - - g_return_if_fail(EM_IS_FOLDER_SELECTION_BUTTON(button)); - - if (p->uri != uri) { - g_free(p->uri); - p->uri = g_strdup(uri); + struct _EMFolderSelectionButtonPrivate *priv = button->priv; + + g_return_if_fail (EM_IS_FOLDER_SELECTION_BUTTON (button)); + + if (priv->uri != uri) { + g_free (priv->uri); + priv->uri = g_strdup (uri); } - - set_contents(button); + + set_contents (button); } const char * -em_folder_selection_button_get_selection(EMFolderSelectionButton *button) +em_folder_selection_button_get_selection (EMFolderSelectionButton *button) { g_return_val_if_fail (EM_IS_FOLDER_SELECTION_BUTTON (button), NULL); - + return button->priv->uri; } - -E_MAKE_TYPE (em_folder_selection_button, "EMFolderSelectionButton", EMFolderSelectionButton, class_init, init, PARENT_TYPE) diff --git a/mail/em-folder-selection-button.h b/mail/em-folder-selection-button.h index 1ab4eb461c..b8f64a4383 100644 --- a/mail/em-folder-selection-button.h +++ b/mail/em-folder-selection-button.h @@ -1,59 +1,69 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* em-folder-selection-button.h +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> * - * Copyright (C) 2003 Ximian, Inc. + * Copyright 2003 Ximian, Inc. (www.ximian.com) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. + * This program is 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. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * 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. * - * Author: Ettore Perazzoli <ettore@ximian.com> */ -#ifndef _EM_FOLDER_SELECTION_BUTTON_H_ -#define _EM_FOLDER_SELECTION_BUTTON_H_ + +#ifndef __EM_FOLDER_SELECTION_BUTTON_H__ +#define __EM_FOLDER_SELECTION_BUTTON_H__ #include <gtk/gtkbutton.h> -#define EM_TYPE_FOLDER_SELECTION_BUTTON (em_folder_selection_button_get_type ()) -#define EM_FOLDER_SELECTION_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EM_TYPE_FOLDER_SELECTION_BUTTON, EMFolderSelectionButton)) -#define EM_FOLDER_SELECTION_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EM_TYPE_FOLDER_SELECTION_BUTTON, EMFolderSelectionButtonClass)) -#define EM_IS_FOLDER_SELECTION_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EM_TYPE_FOLDER_SELECTION_BUTTON)) -#define EM_IS_FOLDER_SELECTION_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EM_TYPE_FOLDER_SELECTION_BUTTON)) +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +#define EM_TYPE_FOLDER_SELECTION_BUTTON (em_folder_selection_button_get_type ()) +#define EM_FOLDER_SELECTION_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EM_TYPE_FOLDER_SELECTION_BUTTON, EMFolderSelectionButton)) +#define EM_FOLDER_SELECTION_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EM_TYPE_FOLDER_SELECTION_BUTTON, EMFolderSelectionButtonClass)) +#define EM_IS_FOLDER_SELECTION_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EM_TYPE_FOLDER_SELECTION_BUTTON)) +#define EM_IS_FOLDER_SELECTION_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EM_TYPE_FOLDER_SELECTION_BUTTON)) typedef struct _EMFolderSelectionButton EMFolderSelectionButton; -typedef struct _EMFolderSelectionButtonPrivate EMFolderSelectionButtonPrivate; typedef struct _EMFolderSelectionButtonClass EMFolderSelectionButtonClass; struct _EMFolderSelectionButton { GtkButton parent; - - EMFolderSelectionButtonPrivate *priv; + + struct _EMFolderSelectionButtonPrivate *priv; }; struct _EMFolderSelectionButtonClass { GtkButtonClass parent_class; - + /* Signals. */ - + void (* selected) (EMFolderSelectionButton *button); }; + GType em_folder_selection_button_get_type (void); -GtkWidget *em_folder_selection_button_new(const char *title, const char *caption); +GtkWidget *em_folder_selection_button_new (const char *title, const char *caption); + +void em_folder_selection_button_set_selection (EMFolderSelectionButton *button, const char *uri); +const char *em_folder_selection_button_get_selection (EMFolderSelectionButton *button); -void em_folder_selection_button_set_selection(EMFolderSelectionButton *button, const char *uri); -const char *em_folder_selection_button_get_selection(EMFolderSelectionButton *button); +#ifdef __cplusplus +} +#endif /* __cplusplus */ -#endif /* _EM_FOLDER_SELECTION_BUTTON_H_ */ +#endif /* __EM_FOLDER_SELECTION_BUTTON_H__ */ diff --git a/mail/em-folder-selection.c b/mail/em-folder-selection.c index c65ad80fc7..5178facd2d 100644 --- a/mail/em-folder-selection.c +++ b/mail/em-folder-selection.c @@ -1,25 +1,26 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* em-folder-selection.c - UI for selecting folders. +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> * - * Copyright (C) 2002 Ximian, Inc. + * Copyright 2003 Ximian, Inc. (www.ximian.com) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. + * This program is 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. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * 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. * - * Author: Ettore Perazzoli <ettore@ximian.com> */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif diff --git a/mail/em-folder-selection.h b/mail/em-folder-selection.h index 374e1eec3f..8237e546f7 100644 --- a/mail/em-folder-selection.h +++ b/mail/em-folder-selection.h @@ -1,41 +1,54 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* em-folder-selection.h - UI for selecting folders. +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> * - * Copyright (C) 2002 Ximian, Inc. + * Copyright 2003 Ximian, Inc. (www.ximian.com) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. + * This program is 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. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * 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. * - * Author: Ettore Perazzoli <ettore@ximian.com> */ + #ifndef EM_FOLDER_SELECTION_H #define EM_FOLDER_SELECTION_H -#include <camel/camel-folder.h> +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ #include <gtk/gtkwindow.h> +#include <camel/camel-folder.h> CamelFolder *em_folder_selection_run_dialog (GtkWindow *parent_window, const char *title, const char *caption, CamelFolder *default_folder); -char *em_folder_selection_run_dialog_uri(GtkWindow *parent_window, - const char *title, - const char *caption, - const char *default_folder_uri); -void em_select_folder(GtkWindow *parent_window, const char *title, const char *text, const char *default_folder_uri, void (*done)(const char *uri, void *data), void *data); +char *em_folder_selection_run_dialog_uri (GtkWindow *parent_window, + const char *title, + const char *caption, + const char *default_folder_uri); + +void em_select_folder (GtkWindow *parent_window, const char *title, const char *text, + const char *default_folder_uri, + void (*done)(const char *uri, void *data), + void *data); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ #endif /* EM_FOLDER_SELECTION_H */ diff --git a/mail/em-folder-selector.c b/mail/em-folder-selector.c index 3ccf00e497..a670222c5e 100644 --- a/mail/em-folder-selector.c +++ b/mail/em-folder-selector.c @@ -1,33 +1,31 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> * - * Copyright(C) 2000, 2001, 2002, 2003 Ximian, Inc. + * Copyright 2003 Ximian, Inc. (www.ximian.com) * - * Authors: Ettore Perazzoli - * Michael Zucchi + * 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 free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * 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. * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif -#include "em-folder-selector.h" - -#include "shell/e-storage-set-view.h" -#include "shell/e-storage-set.h" +#include <string.h> #include <libgnome/gnome-i18n.h> @@ -44,306 +42,272 @@ #include <camel/camel-url.h> -#include <string.h> - -#define PARENT_TYPE (gtk_dialog_get_type()) -static GtkDialogClass *parent_class = NULL; - -static gboolean -check_folder_type_valid(EMFolderSelector *emfs) -{ - const char *selected; - EFolder *folder; +#include "em-folder-tree.h" +#include "em-folder-selector.h" - selected = e_storage_set_view_get_current_folder(emfs->essv); - if (selected == NULL) - return FALSE; +#define d(x) x - folder = e_storage_set_get_folder(emfs->ess, selected); - if (folder == NULL) - return FALSE; - return TRUE; -} +static void em_folder_selector_class_init (EMFolderSelectorClass *klass); +static void em_folder_selector_init (EMFolderSelector *emfs); +static void em_folder_selector_destroy (GtkObject *obj); +static void em_folder_selector_finalize (GObject *obj); +static void em_folder_selector_response (GtkDialog *dialog, int response); -#if 0 /* EPFIXME */ -static void -folder_creation_dialog_result_cb(EShell *shell, - EShellFolderCreationDialogResult result, - const char *path, - void *data) -{ - EMFolderSelector *dialog; - dialog = EM_FOLDER_SELECTOR(data); +static GtkDialogClass *parent_class = NULL; - if (result == E_SHELL_FOLDER_CREATION_DIALOG_RESULT_SUCCESS) - e_storage_set_view_set_current_folder(E_STORAGE_SET_VIEW(priv->storage_set_view), - path); -} -#endif -static void -emfs_dispose(GObject *object) +GType +em_folder_selector_get_type (void) { - EMFolderSelector *emfs = (EMFolderSelector *)object; - - if (emfs->ess != NULL) { - g_object_unref(emfs->ess); - emfs->ess = NULL; - emfs->essv = NULL; + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (EMFolderSelectorClass), + NULL, /* base_class_init */ + NULL, /* base_class_finalize */ + (GClassInitFunc) em_folder_selector_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EMFolderSelector), + 0, /* n_preallocs */ + (GInstanceInitFunc) em_folder_selector_init, + }; + + type = g_type_register_static (GTK_TYPE_DIALOG, "EMFolderSelector", &info, 0); } - - (* G_OBJECT_CLASS(parent_class)->dispose)(object); + + return type; } static void -emfs_finalize(GObject *object) +em_folder_selector_class_init (EMFolderSelectorClass *klass) { - /*EMFolderSelector *emfs = (EMFolderSelector *)object;*/ - - (* G_OBJECT_CLASS(parent_class)->finalize)(object); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass); + GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass); + + parent_class = g_type_class_ref (GTK_TYPE_DIALOG); + + object_class->finalize = em_folder_selector_finalize; + gtk_object_class->destroy = em_folder_selector_destroy; + + dialog_class->response = em_folder_selector_response; } static void -emfs_response(GtkDialog *dialog, int response) +em_folder_selector_init (EMFolderSelector *emfs) { - EMFolderSelector *emfs = (EMFolderSelector *)dialog; - const char *path; - - switch (response) { - case EM_FOLDER_SELECTOR_RESPONSE_NEW: - path = e_storage_set_view_get_current_folder(emfs->essv); - - printf("create new folder, default parent '%s'\n", path); - break; - } + emfs->selected_path = NULL; + emfs->selected_uri = NULL; } static void -emfs_class_init(EMFolderSelectorClass *klass) +em_folder_selector_destroy (GtkObject *obj) { - GObjectClass *object_class; - GtkDialogClass *dialog_class; - - parent_class = g_type_class_ref(PARENT_TYPE); - object_class = G_OBJECT_CLASS(klass); - dialog_class = GTK_DIALOG_CLASS(klass); - - object_class->dispose = emfs_dispose; - object_class->finalize = emfs_finalize; - - dialog_class->response = emfs_response; + GTK_OBJECT_CLASS (parent_class)->destroy (obj); } static void -emfs_init(EMFolderSelector *emfs) +em_folder_selector_finalize (GObject *obj) { - emfs->flags = 0; + EMFolderSelector *emfs = (EMFolderSelector *) obj; + + g_free (emfs->selected_path); + g_free (emfs->selected_uri); + + G_OBJECT_CLASS (parent_class)->finalize (obj); } static void -folder_selected_cb(EStorageSetView *essv, const char *path, EMFolderSelector *emfs) +em_folder_selector_response (GtkDialog *dialog, int response) { - if (check_folder_type_valid(emfs)) - gtk_dialog_set_response_sensitive(GTK_DIALOG(emfs), GTK_RESPONSE_OK, TRUE); - else - gtk_dialog_set_response_sensitive(GTK_DIALOG(emfs), GTK_RESPONSE_OK, FALSE); + EMFolderSelector *emfs = (EMFolderSelector *) dialog; + + switch (response) { + case EM_FOLDER_SELECTOR_RESPONSE_NEW: + /* FIXME: implement me */ + break; + } } + + static void -double_click_cb(EStorageSetView *essv, int row, ETreePath path, int col, GdkEvent *event, EMFolderSelector *emfs) +folder_selected_cb (EMFolderTree *emft, const char *path, const char *uri, EMFolderSelector *emfs) { - if (check_folder_type_valid(emfs)) { - /*g_signal_emit(emfs, signals[FOLDER_SELECTED], 0, - em_folder_selector_get_selected(emfs));*/ - printf("double clicked!\n"); - } + gtk_dialog_set_response_sensitive (GTK_DIALOG (emfs), GTK_RESPONSE_OK, TRUE); } void -em_folder_selector_construct(EMFolderSelector *emfs, EStorageSet *ess, guint32 flags, const char *title, const char *text) +em_folder_selector_construct (EMFolderSelector *emfs, EMFolderTree *emft, guint32 flags, const char *title, const char *text) { GtkWidget *scrolled_window; - GtkWidget *text_label; - - gtk_window_set_default_size(GTK_WINDOW(emfs), 350, 300); - gtk_window_set_modal(GTK_WINDOW(emfs), TRUE); - gtk_window_set_title(GTK_WINDOW(emfs), title); - gtk_container_set_border_width(GTK_CONTAINER(emfs), 6); - + GtkWidget *label; + + gtk_window_set_default_size (GTK_WINDOW (emfs), 350, 300); + gtk_window_set_modal (GTK_WINDOW (emfs), TRUE); + gtk_window_set_title (GTK_WINDOW (emfs), title); + gtk_container_set_border_width (GTK_CONTAINER (emfs), 6); + + gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (emfs)->vbox), 6); + gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (emfs)->vbox), 6); + emfs->flags = flags; if (flags & EM_FOLDER_SELECTOR_CAN_CREATE) - gtk_dialog_add_buttons(GTK_DIALOG(emfs), GTK_STOCK_NEW, EM_FOLDER_SELECTOR_RESPONSE_NEW, NULL); - - gtk_dialog_add_buttons(GTK_DIALOG(emfs), - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, - NULL); - - gtk_dialog_set_response_sensitive(GTK_DIALOG(emfs), GTK_RESPONSE_OK, FALSE); - gtk_dialog_set_default_response(GTK_DIALOG(emfs), GTK_RESPONSE_OK); - - emfs->ess = ess; - g_object_ref(ess); - - emfs->essv = (EStorageSetView *)e_storage_set_create_new_view(ess, NULL); - e_storage_set_view_set_allow_dnd(emfs->essv, FALSE); - e_storage_set_view_enable_search(emfs->essv, TRUE); - - g_signal_connect(emfs->essv, "double_click", G_CALLBACK(double_click_cb), emfs); - g_signal_connect(emfs->essv, "folder_selected", G_CALLBACK(folder_selected_cb), emfs); - - scrolled_window = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), + gtk_dialog_add_buttons (GTK_DIALOG (emfs), GTK_STOCK_NEW, EM_FOLDER_SELECTOR_RESPONSE_NEW, NULL); + + gtk_dialog_add_buttons (GTK_DIALOG (emfs), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); + + gtk_dialog_set_response_sensitive (GTK_DIALOG (emfs), GTK_RESPONSE_OK, FALSE); + gtk_dialog_set_default_response (GTK_DIALOG (emfs), GTK_RESPONSE_OK); + + emfs->emft = emft; + gtk_widget_show ((GtkWidget *) emfs->emft); + + g_signal_connect (emfs->emft, "folder-selected", G_CALLBACK (folder_selected_cb), emfs); + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - - gtk_container_add(GTK_CONTAINER(scrolled_window), (GtkWidget *)emfs->essv); - - gtk_box_pack_end(GTK_BOX(GTK_DIALOG(emfs)->vbox), scrolled_window, TRUE, TRUE, 6); - gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(emfs)->vbox), 6); + gtk_widget_show (scrolled_window); - gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(emfs)->vbox), 6); + gtk_container_add (GTK_CONTAINER (scrolled_window), (GtkWidget *) emft); + + gtk_box_pack_end (GTK_BOX (GTK_DIALOG (emfs)->vbox), scrolled_window, TRUE, TRUE, 6); - gtk_widget_show((GtkWidget *)emfs->essv); - gtk_widget_show(scrolled_window); - if (text != NULL) { - text_label = gtk_label_new(text); - gtk_label_set_justify(GTK_LABEL(text_label), GTK_JUSTIFY_LEFT); - gtk_widget_show(text_label); - - gtk_box_pack_end(GTK_BOX(GTK_DIALOG(emfs)->vbox), text_label, FALSE, TRUE, 6); - gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(emfs)->vbox), 6); + label = gtk_label_new (text); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_widget_show (label); + + gtk_box_pack_end (GTK_BOX (GTK_DIALOG (emfs)->vbox), label, FALSE, TRUE, 6); } - - GTK_WIDGET_SET_FLAGS((GtkWidget *)emfs->essv, GTK_CAN_FOCUS); - gtk_widget_grab_focus((GtkWidget *)emfs->essv); + + GTK_WIDGET_SET_FLAGS ((GtkWidget *) emfs->emft, GTK_CAN_FOCUS); + gtk_widget_grab_focus ((GtkWidget *) emfs->emft); } GtkWidget * -em_folder_selector_new(EStorageSet *ess, guint32 flags, const char *title, const char *text) +em_folder_selector_new (EMFolderTree *emft, guint32 flags, const char *title, const char *text) { EMFolderSelector *emfs; - - g_return_val_if_fail(E_IS_STORAGE_SET(ess), NULL); - - emfs = g_object_new(em_folder_selector_get_type(), NULL); - em_folder_selector_construct(emfs, ess, flags, title, text); - - return GTK_WIDGET(emfs); + + emfs = g_object_new (em_folder_selector_get_type (), NULL); + em_folder_selector_construct (emfs, emft, flags, title, text); + + return (GtkWidget *) emfs; } static void -emfs_create_name_changed(GtkEntry *entry, EMFolderSelector *emfs) +emfs_create_name_changed (GtkEntry *entry, EMFolderSelector *emfs) { - int active; - - active = e_storage_set_view_get_current_folder(emfs->essv) != NULL - && emfs->name_entry->text_length > 0; - - gtk_dialog_set_response_sensitive((GtkDialog *)emfs, GTK_RESPONSE_OK, active); + gboolean active; + + /* FIXME: need to port this... */ + active = /* folder does not exist && */ emfs->name_entry->text_length > 0; + + gtk_dialog_set_response_sensitive ((GtkDialog *) emfs, GTK_RESPONSE_OK, active); } static void -emfs_create_name_activate(GtkEntry *entry, EMFolderSelector *emfs) +emfs_create_name_activate (GtkEntry *entry, EMFolderSelector *emfs) { - printf("entry activated, woop\n"); + /* FIXME: create the folder... */ + printf ("entry activated, woop\n"); } GtkWidget * -em_folder_selector_create_new(EStorageSet *ess, guint32 flags, const char *title, const char *text) +em_folder_selector_create_new (EMFolderTree *emft, guint32 flags, const char *title, const char *text) { EMFolderSelector *emfs; GtkWidget *hbox, *w; - - g_return_val_if_fail(E_IS_STORAGE_SET(ess), NULL); - - emfs = g_object_new(em_folder_selector_get_type(), NULL); - em_folder_selector_construct(emfs, ess, flags, title, text); - - hbox = gtk_hbox_new(FALSE, 0); - w = gtk_label_new_with_mnemonic(_("Folder _name")); - gtk_box_pack_start((GtkBox *)hbox, w, FALSE, FALSE, 6); - emfs->name_entry = (GtkEntry *)gtk_entry_new(); - g_signal_connect(emfs->name_entry, "changed", G_CALLBACK(emfs_create_name_changed), emfs); - g_signal_connect(emfs->name_entry, "activate", G_CALLBACK(emfs_create_name_activate), emfs); - gtk_box_pack_start((GtkBox *)hbox, (GtkWidget *)emfs->name_entry, TRUE, FALSE, 6); - gtk_widget_show_all(hbox); - - gtk_box_pack_start((GtkBox *)((GtkDialog *)emfs)->vbox, hbox, FALSE, TRUE, 0); - - return GTK_WIDGET(emfs); + + emfs = g_object_new (em_folder_selector_get_type (), NULL); + em_folder_selector_construct (emfs, emft, flags, title, text); + + hbox = gtk_hbox_new (FALSE, 0); + w = gtk_label_new_with_mnemonic (_("Folder _name")); + gtk_box_pack_start ((GtkBox *) hbox, w, FALSE, FALSE, 6); + emfs->name_entry = (GtkEntry *) gtk_entry_new (); + g_signal_connect (emfs->name_entry, "changed", G_CALLBACK (emfs_create_name_changed), emfs); + g_signal_connect (emfs->name_entry, "activate", G_CALLBACK (emfs_create_name_activate), emfs); + gtk_box_pack_start ((GtkBox *) hbox, (GtkWidget *) emfs->name_entry, TRUE, FALSE, 6); + gtk_widget_show_all (hbox); + + gtk_box_pack_start ((GtkBox *) ((GtkDialog *) emfs)->vbox, hbox, FALSE, TRUE, 0); + + return (GtkWidget *) emfs; } -void -em_folder_selector_set_selected(EMFolderSelector *emfs, const char *path) -{ - e_storage_set_view_set_current_folder(emfs->essv, path); -} void -em_folder_selector_set_selected_uri(EMFolderSelector *emfs, const char *uri) +em_folder_selector_set_selected (EMFolderSelector *emfs, const char *uri) { - const char *path; - - path = e_storage_set_get_path_for_physical_uri(emfs->ess, uri); - if (path) - e_storage_set_view_set_current_folder(emfs->essv, path); + em_folder_tree_set_selected (emfs->emft, uri); } + const char * -em_folder_selector_get_selected(EMFolderSelector *emfs) +em_folder_selector_get_selected_uri (EMFolderSelector *emfs) { - const char *path; - - path = e_storage_set_view_get_current_folder(emfs->essv); - if (emfs->name_entry) { - g_free(emfs->selected); - emfs->selected = g_strdup_printf("%s/%s", path, gtk_entry_get_text(emfs->name_entry)); - path = emfs->selected; + const char *uri; + + if (!(uri = em_folder_tree_get_selected_uri (emfs->emft))) { + d(printf ("no selected folder?\n")); + return NULL; } - - return path; + + if (uri && emfs->name_entry) { + CamelURL *url; + char *newpath; + + url = camel_url_new (uri, NULL); + newpath = g_strdup_printf ("%s/%s", url->fragment ? url->fragment : url->path, gtk_entry_get_text (emfs->name_entry)); + if (url->fragment) + camel_url_set_fragment (url, newpath); + else + camel_url_set_path (url, newpath); + + g_free (emfs->selected_path); + emfs->selected_path = newpath; + + g_free (emfs->selected_uri); + emfs->selected_uri = camel_url_to_string (url, 0); + + camel_url_free (url); + uri = emfs->selected_uri; + } + + return uri; } + const char * -em_folder_selector_get_selected_uri(EMFolderSelector *emfs) +em_folder_selector_get_selected_path (EMFolderSelector *emfs) { const char *path; - EFolder *folder; - - path = e_storage_set_view_get_current_folder(emfs->essv); - if (path == NULL) { - printf("current folder is null?\n"); - return NULL; + + if (emfs->selected_path) { + /* already did the work in a previous call */ + return emfs->selected_path; } - - folder = e_storage_set_get_folder(emfs->ess, path); - if (folder == NULL) { - printf("path ok, but can't get folder?\n"); + + if (!(path = em_folder_tree_get_selected_path (emfs->emft))) { + d(printf ("no selected folder?\n")); return NULL; } - - path = e_folder_get_physical_uri(folder); + if (path && emfs->name_entry) { - CamelURL *url; char *newpath; - - url = camel_url_new(path, NULL); - newpath = g_strdup_printf("%s/%s", url->fragment?url->fragment:url->path, gtk_entry_get_text(emfs->name_entry)); - if (url->fragment) - camel_url_set_fragment(url, newpath); - else - camel_url_set_path(url, newpath); - g_free(emfs->selected_uri); - emfs->selected_uri = camel_url_to_string(url, 0); - camel_url_free(url); - path = emfs->selected_uri; + + path = newpath = g_strdup_printf ("%s/%s", path, gtk_entry_get_text (emfs->name_entry)); + emfs->selected_path = newpath; } - + return path; } - -E_MAKE_TYPE(em_folder_selector, "EMFolderSelector", EMFolderSelector, emfs_class_init, emfs_init, PARENT_TYPE) diff --git a/mail/em-folder-selector.h b/mail/em-folder-selector.h index 48fc6758b5..76fb5888ff 100644 --- a/mail/em-folder-selector.h +++ b/mail/em-folder-selector.h @@ -1,27 +1,26 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* e-folder-selection-dialog.h +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> * - * Copyright (C) 2000, 2001, 2002, 2003 Ximian, Inc. + * Copyright 2003 Ximian, Inc. (www.ximian.com) * - * Authors: Ettore Perazzoli - * Michael Zucchi + * 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 free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * 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. * */ + #ifndef EM_FOLDER_SELECTOR_H #define EM_FOLDER_SELECTOR_H @@ -42,29 +41,20 @@ typedef struct _EMFolderSelector EMFolderSelector; typedef struct _EMFolderSelectorPrivate EMFolderSelectorPrivate; typedef struct _EMFolderSelectorClass EMFolderSelectorClass; -struct _EStorageSet; -struct _EStorageSetView; - struct _EMFolderSelector { GtkDialog parent; - + guint32 flags; - struct _EStorageSet *ess; - struct _EStorageSetView *essv; - + struct _EMFolderTree *emft; + struct _GtkEntry *name_entry; - char *selected; + char *selected_path; char *selected_uri; }; struct _EMFolderSelectorClass { GtkDialogClass parent_class; - -#if 0 - void (* folder_selected) (EMFolderSelector *folder_selection_dialog, - const char *path); - void (* cancelled) (EMFolderSelector *folder_selection_dialog); -#endif + }; enum { @@ -75,19 +65,21 @@ enum { EM_FOLDER_SELECTOR_RESPONSE_NEW = 1, }; -GtkType em_folder_selector_get_type (void); -void em_folder_selector_construct(EMFolderSelector *, struct _EStorageSet *, guint32, const char *, const char *); + +GType em_folder_selector_get_type (void); + +void em_folder_selector_construct (EMFolderSelector *emfs, struct _EMFolderTree *emft, guint32 flags, const char *title, const char *text); + /* for selecting folders */ -GtkWidget *em_folder_selector_new (struct _EStorageSet *, guint32, const char *, const char *); +GtkWidget *em_folder_selector_new (struct _EMFolderTree *emft, guint32 flags, const char *title, const char *text); /* for creating folders */ -GtkWidget *em_folder_selector_create_new(struct _EStorageSet *ess, guint32 flags, const char *title, const char *text); +GtkWidget *em_folder_selector_create_new (struct _EMFolderTree *emft, guint32 flags, const char *title, const char *text); -void em_folder_selector_set_selected (EMFolderSelector *emfs, const char *path); -void em_folder_selector_set_selected_uri(EMFolderSelector *emfs, const char *uri); +void em_folder_selector_set_selected (EMFolderSelector *emfs, const char *uri); -const char *em_folder_selector_get_selected (EMFolderSelector *emfs); -const char *em_folder_selector_get_selected_uri(EMFolderSelector *emfs); +const char *em_folder_selector_get_selected_uri (EMFolderSelector *emfs); +const char *em_folder_selector_get_selected_path (EMFolderSelector *emfs); #ifdef cplusplus } diff --git a/mail/em-folder-tree-model.c b/mail/em-folder-tree-model.c new file mode 100644 index 0000000000..786ac94d68 --- /dev/null +++ b/mail/em-folder-tree-model.c @@ -0,0 +1,284 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> + * + * Copyright 2003 Ximian, Inc. (www.ximian.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. + * + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "em-marshal.h" +#include "em-folder-tree-model.h" + + +/* GObject virtual method overrides */ +static void em_folder_tree_model_class_init (EMFolderTreeModelClass *klass); +static void em_folder_tree_model_init (EMFolderTreeModel *model); +static void em_folder_tree_model_finalize (GObject *obj); + +/* interface init methods */ +static void tree_model_iface_init (GtkTreeModelIface *iface); +static void tree_drag_dest_iface_init (GtkTreeDragDestIface *iface); +static void tree_drag_source_iface_init (GtkTreeDragSourceIface *iface); + +/* drag & drop iface methods */ +static gboolean model_drag_data_received (GtkTreeDragDest *drag_dest, + GtkTreePath *dest_path, + GtkSelectionData *selection_data); +static gboolean model_row_drop_possible (GtkTreeDragDest *drag_dest, + GtkTreePath *dest_path, + GtkSelectionData *selection_data); +static gboolean model_row_draggable (GtkTreeDragSource *drag_source, + GtkTreePath *src_path); +static gboolean model_drag_data_get (GtkTreeDragSource *drag_source, + GtkTreePath *src_path, + GtkSelectionData *selection_data); +static gboolean model_drag_data_delete (GtkTreeDragSource *drag_source, + GtkTreePath *src_path); + + +enum { + DRAG_DATA_RECEIVED, + ROW_DROP_POSSIBLE, + ROW_DRAGGABLE, + DRAG_DATA_GET, + DRAG_DATA_DELETE, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0, }; + + +static GtkTreeStore *parent_class = NULL; + + +GType +em_folder_tree_model_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (EMFolderTreeModelClass), + NULL, /* base_class_init */ + NULL, /* base_class_finalize */ + (GClassInitFunc) em_folder_tree_model_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EMFolderTreeModel), + 0, /* n_preallocs */ + (GInstanceInitFunc) em_folder_tree_model_init, + }; + static const GInterfaceInfo tree_model_info = { + (GInterfaceInitFunc) tree_model_iface_init, + NULL, + NULL + }; + static const GInterfaceInfo drag_dest_info = { + (GInterfaceInitFunc) tree_drag_dest_iface_init, + NULL, + NULL + }; + static const GInterfaceInfo drag_source_info = { + (GInterfaceInitFunc) tree_drag_source_iface_init, + NULL, + NULL + }; + + type = g_type_register_static (GTK_TYPE_TREE_STORE, "EMFolderTreeModel", &info, 0); + + g_type_add_interface_static (type, GTK_TYPE_TREE_MODEL, + &tree_model_info); + g_type_add_interface_static (type, GTK_TYPE_TREE_DRAG_DEST, + &drag_dest_info); + g_type_add_interface_static (type, GTK_TYPE_TREE_DRAG_SOURCE, + &drag_source_info); + } + + return type; +} + + +static void +em_folder_tree_model_class_init (EMFolderTreeModelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_ref (GTK_TYPE_TREE_STORE); + + object_class->finalize = em_folder_tree_model_finalize; + + /* signals */ + signals[DRAG_DATA_RECEIVED] = + g_signal_new ("drag-data-received", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_NO_HOOKS, + G_STRUCT_OFFSET (EMFolderTreeModelClass, drag_data_received), + NULL, NULL, + em_marshal_BOOLEAN__POINTER_POINTER, + G_TYPE_BOOLEAN, 2, + G_TYPE_POINTER, + G_TYPE_POINTER); + + signals[ROW_DROP_POSSIBLE] = + g_signal_new ("row-drop-possible", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_NO_HOOKS, + G_STRUCT_OFFSET (EMFolderTreeModelClass, row_drop_possible), + NULL, NULL, + em_marshal_BOOLEAN__POINTER_POINTER, + G_TYPE_BOOLEAN, 2, + G_TYPE_POINTER, + G_TYPE_POINTER); + + signals[ROW_DRAGGABLE] = + g_signal_new ("row-draggable", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_NO_HOOKS, + G_STRUCT_OFFSET (EMFolderTreeModelClass, row_draggable), + NULL, NULL, + em_marshal_BOOLEAN__POINTER, + G_TYPE_BOOLEAN, 1, + G_TYPE_POINTER); + + signals[DRAG_DATA_GET] = + g_signal_new ("drag-data-get", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_NO_HOOKS, + G_STRUCT_OFFSET (EMFolderTreeModelClass, drag_data_get), + NULL, NULL, + em_marshal_BOOLEAN__POINTER_POINTER, + G_TYPE_BOOLEAN, 2, + G_TYPE_POINTER, + G_TYPE_POINTER); + + signals[DRAG_DATA_DELETE] = + g_signal_new ("drag-data-delete", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_NO_HOOKS, + G_STRUCT_OFFSET (EMFolderTreeModelClass, drag_data_delete), + NULL, NULL, + em_marshal_BOOLEAN__POINTER, + G_TYPE_BOOLEAN, 1, + G_TYPE_POINTER); +} + +static void +em_folder_tree_model_init (EMFolderTreeModel *model) +{ + ; +} + +static void +em_folder_tree_model_finalize (GObject *obj) +{ + G_OBJECT_CLASS (parent_class)->finalize (obj); +} + + +static void +tree_model_iface_init (GtkTreeModelIface *iface) +{ + ; +} + +static void +tree_drag_dest_iface_init (GtkTreeDragDestIface *iface) +{ + iface->drag_data_received = model_drag_data_received; + iface->row_drop_possible = model_row_drop_possible; +} + +static void +tree_drag_source_iface_init (GtkTreeDragSourceIface *iface) +{ + iface->row_draggable = model_row_draggable; + iface->drag_data_get = model_drag_data_get; + iface->drag_data_delete = model_drag_data_delete; +} + + +static gboolean +model_drag_data_received (GtkTreeDragDest *drag_dest, GtkTreePath *dest_path, GtkSelectionData *selection_data) +{ + EMFolderTreeModel *model = (EMFolderTreeModel *) drag_dest; + gboolean retval = FALSE; + + g_signal_emit (model, signals[DRAG_DATA_RECEIVED], 0, &retval, dest_path, selection_data); + + return retval; +} + +static gboolean +model_row_drop_possible (GtkTreeDragDest *drag_dest, GtkTreePath *dest_path, GtkSelectionData *selection_data) +{ + EMFolderTreeModel *model = (EMFolderTreeModel *) drag_dest; + gboolean retval = FALSE; + + g_signal_emit (model, signals[ROW_DROP_POSSIBLE], 0, &retval, dest_path, selection_data); + + return retval; +} + +static gboolean +model_row_draggable (GtkTreeDragSource *drag_source, GtkTreePath *src_path) +{ + EMFolderTreeModel *model = (EMFolderTreeModel *) drag_source; + gboolean retval = FALSE; + + g_signal_emit (model, signals[ROW_DRAGGABLE], 0, &retval, src_path); + + return retval; +} + +static gboolean +model_drag_data_get (GtkTreeDragSource *drag_source, GtkTreePath *src_path, GtkSelectionData *selection_data) +{ + EMFolderTreeModel *model = (EMFolderTreeModel *) drag_source; + gboolean retval = FALSE; + + g_signal_emit (model, signals[DRAG_DATA_GET], 0, &retval, src_path, selection_data); + + return retval; +} + +static gboolean +model_drag_data_delete (GtkTreeDragSource *drag_source, GtkTreePath *src_path) +{ + EMFolderTreeModel *model = (EMFolderTreeModel *) drag_source; + gboolean retval = FALSE; + + g_signal_emit (model, signals[DRAG_DATA_DELETE], 0, &retval, src_path); + + return retval; +} + + +EMFolderTreeModel * +em_folder_tree_model_new (int n_columns, GType *types) +{ + EMFolderTreeModel *model; + + model = g_object_new (EM_TYPE_FOLDER_TREE_MODEL, NULL); + gtk_tree_store_set_column_types ((GtkTreeStore *) model, n_columns, types); + + return model; +} diff --git a/mail/em-folder-tree-model.h b/mail/em-folder-tree-model.h new file mode 100644 index 0000000000..c52509ad63 --- /dev/null +++ b/mail/em-folder-tree-model.h @@ -0,0 +1,81 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> + * + * Copyright 2003 Ximian, Inc. (www.ximian.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. + * + */ + + +#ifndef __EM_FOLDER_TREE_MODEL_H__ +#define __EM_FOLDER_TREE_MODEL_H__ + +#include <gtk/gtktreednd.h> +#include <gtk/gtktreestore.h> + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +#define EM_TYPE_FOLDER_TREE_MODEL (em_folder_tree_model_get_type ()) +#define EM_FOLDER_TREE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EM_TYPE_FOLDER_TREE_MODEL, EMFolderTreeModel)) +#define EM_FOLDER_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EM_TYPE_FOLDER_TREE_MODEL, EMFolderTreeModelClass)) +#define EM_IS_FOLDER_TREE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EM_TYPE_FOLDER_TREE_MODEL)) +#define EM_IS_FOLDER_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EM_TYPE_FOLDER_TREE_MODEL)) +#define EM_FOLDER_TREE_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EM_TYPE_FOLDER_TREE_MODEL, EMFolderTreeModelClass)) + +typedef struct _EMFolderTreeModel EMFolderTreeModel; +typedef struct _EMFolderTreeModelClass EMFolderTreeModelClass; + +struct _EMFolderTreeModel { + GtkTreeStore parent_object; + +}; + +struct _EMFolderTreeModelClass { + GtkTreeStoreClass parent_class; + + /* signals */ + gboolean (* drag_data_received) (EMFolderTreeModel *model, + GtkTreePath *dest_path, + GtkSelectionData *selection_data); + gboolean (* row_drop_possible) (EMFolderTreeModel *model, + GtkTreePath *dest_path, + GtkSelectionData *selection_data); + + gboolean (* row_draggable) (EMFolderTreeModel *model, + GtkTreePath *src_path); + gboolean (* drag_data_get) (EMFolderTreeModel *model, + GtkTreePath *src_path, + GtkSelectionData *selection_data); + gboolean (* drag_data_delete) (EMFolderTreeModel *model, + GtkTreePath *src_path); +}; + + +GType em_folder_tree_model_get_type (void); + + +EMFolderTreeModel *em_folder_tree_model_new (int n_columns, GType *types); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EM_FOLDER_TREE_MODEL_H__ */ diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c index e6274abe37..49efb8a2ec 100644 --- a/mail/em-folder-tree.c +++ b/mail/em-folder-tree.c @@ -25,13 +25,41 @@ #include <config.h> #endif +#include <stdio.h> +#include <stdlib.h> #include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> #include <gtk/gtk.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <camel/camel-session.h> +#include <camel/camel-store.h> +#include <camel/camel-folder.h> +#include <camel/camel-stream-mem.h> + +#include "e-util/e-mktemp.h" +#include "e-util/e-request.h" +#include "e-util/e-dialog-utils.h" + +#include "mail-mt.h" +#include "mail-ops.h" +#include "mail-tools.h" + +#include "em-utils.h" +#include "em-popup.h" +#include "em-marshal.h" #include "em-folder-tree.h" +#include "em-folder-selector.h" +#include "em-folder-selection.h" +#define d(x) x + enum { COL_STRING_DISPLAY_NAME, /* string that appears in the tree */ COL_POINTER_CAMEL_STORE, /* CamelStore object */ @@ -50,29 +78,94 @@ enum { static GType col_types[] = { G_TYPE_STRING, /* display name */ G_TYPE_POINTER, /* store object */ - G_TYPE_STRING, /* full_name */ + G_TYPE_STRING, /* path */ G_TYPE_STRING, /* uri */ G_TYPE_UINT, /* unread count */ G_TYPE_BOOLEAN, /* is a store node */ G_TYPE_BOOLEAN, /* has not-yet-loaded subfolders */ }; +struct _emft_store_info { + CamelStore *store; + GtkTreeRowReference *row; + GHashTable *path_hash; /* maps CamelFolderInfo::path's to GtkTreeRowReferences */ + + char *display_name; + + unsigned int created_id; + unsigned int deleted_id; + unsigned int renamed_id; + unsigned int subscribed_id; + unsigned int unsubscribed_id; +}; + struct _EMFolderTreePrivate { GtkTreeView *treeview; - GHashTable *store_hash; /* maps CamelStore's to GtkTreePath's */ + GHashTable *store_hash; /* maps CamelStore's to store-info's */ + GHashTable *uri_hash; /* maps URI's to GtkTreeRowReferences */ char *selected_uri; + char *selected_path; + + /* dnd signal ids */ + guint ddr, rdp, rd, ddg, ddd; +}; + +enum { + FOLDER_SELECTED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + + +#define MESSAGE_RFC822_TYPE "message/rfc822" +#define TEXT_URI_LIST_TYPE "text/uri-list" +#define UID_LIST_TYPE "x-uid-list" +#define FOLDER_TYPE "x-folder" + +/* Drag & Drop types */ +enum DndDragType { + DND_DRAG_TYPE_FOLDER, /* drag an evo folder */ + DND_DRAG_TYPE_TEXT_URI_LIST, /* drag to an mbox file */ }; +enum DndDropType { + DND_DROP_TYPE_UID_LIST, /* drop a list of message uids */ + DND_DROP_TYPE_FOLDER, /* drop an evo folder */ + DND_DROP_TYPE_MESSAGE_RFC822, /* drop a message/rfc822 stream */ + DND_DROP_TYPE_TEXT_URI_LIST, /* drop an mbox file */ +}; + +static GtkTargetEntry drag_types[] = { + { UID_LIST_TYPE, 0, DND_DRAG_TYPE_FOLDER }, + { TEXT_URI_LIST_TYPE, 0, DND_DRAG_TYPE_TEXT_URI_LIST }, +}; + +static const int num_drag_types = sizeof (drag_types) / sizeof (drag_types[0]); + +static GtkTargetEntry drop_types[] = { + { UID_LIST_TYPE, 0, DND_DROP_TYPE_UID_LIST }, + { FOLDER_TYPE, 0, DND_DROP_TYPE_FOLDER }, + { MESSAGE_RFC822_TYPE, 0, DND_DROP_TYPE_MESSAGE_RFC822 }, + { TEXT_URI_LIST_TYPE, 0, DND_DROP_TYPE_TEXT_URI_LIST }, +}; + +static const int num_drop_types = sizeof (drop_types) / sizeof (drop_types[0]); + + +extern CamelSession *session; + + static void em_folder_tree_class_init (EMFolderTreeClass *klass); -static void em_folder_tree_init (EMFolderTree *tree); +static void em_folder_tree_init (EMFolderTree *emft); static void em_folder_tree_destroy (GtkObject *obj); static void em_folder_tree_finalize (GObject *obj); -static void tree_row_expanded (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePath *path, EMFolderTree *ftree); -static gboolean tree_button_press (GtkWidget *treeview, GdkEventButton *event, EMFolderTree *ftree); -static void tree_selection_changed (GtkTreeSelection *selection, EMFolderTree *ftree); +static void tree_row_expanded (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePath *path, EMFolderTree *emft); +static gboolean tree_button_press (GtkWidget *treeview, GdkEventButton *event, EMFolderTree *emft); +static void tree_selection_changed (GtkTreeSelection *selection, EMFolderTree *emft); static GtkVBoxClass *parent_class = NULL; @@ -113,7 +206,16 @@ em_folder_tree_class_init (EMFolderTreeClass *klass) object_class->finalize = em_folder_tree_finalize; gtk_object_class->destroy = em_folder_tree_destroy; - /* FIXME: init signals */ + signals[FOLDER_SELECTED] = + g_signal_new ("folder-selected", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EMFolderTreeClass, folder_selected), + NULL, NULL, + em_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_STRING); } @@ -144,8 +246,7 @@ enum { FOLDER_ICON_NORMAL, FOLDER_ICON_INBOX, FOLDER_ICON_OUTBOX, - FOLDER_ICON_TRASH, - FOLDER_ICON_JUNK + FOLDER_ICON_TRASH }; static GdkPixbuf *folder_icons[4]; @@ -160,31 +261,28 @@ render_pixbuf (GtkTreeViewColumn *column, GtkCellRenderer *renderer, char *path; if (!initialised) { - folder_icons[0] = gdk_pixbuf_load_from_file (EVOLUTION_ICONSDIR "/folder-mini.png"); - folder_icons[1] = gdk_pixbuf_load_from_file (EVOLUTION_ICONSDIR "/inbox-mini.png"); - folder_icons[2] = gdk_pixbuf_load_from_file (EVOLUTION_ICONSDIR "/outbox-mini.png"); - folder_icons[3] = gdk_pixbuf_load_from_file (EVOLUTION_ICONSDIR "/evolution-trash-mini.png"); - folder_icons[4] = gdk_pixbuf_load_from_file (EVOLUTION_ICONSDIR "/evolution-junk-mini.png"); + folder_icons[0] = gdk_pixbuf_new_from_file (EVOLUTION_ICONSDIR "/folder-mini.png", NULL); + folder_icons[1] = gdk_pixbuf_new_from_file (EVOLUTION_ICONSDIR "/inbox-mini.png", NULL); + folder_icons[2] = gdk_pixbuf_new_from_file (EVOLUTION_ICONSDIR "/outbox-mini.png", NULL); + folder_icons[3] = gdk_pixbuf_new_from_file (EVOLUTION_ICONSDIR "/evolution-trash-mini.png", NULL); initialised = TRUE; } gtk_tree_model_get (model, iter, COL_STRING_FOLDER_PATH, &path, - COL_BOO_IS_STORE, &is_store, -1); + COL_BOOL_IS_STORE, &is_store, -1); - if (!is_store) { - if (!strcasecmp (name, "/Inbox")) + if (!is_store && path != NULL) { + if (!strcasecmp (path, "/Inbox")) pixbuf = folder_icons[FOLDER_ICON_INBOX]; - else if (!strcasecmp (name, "/Outbox")) + else if (!strcasecmp (path, "/Outbox")) pixbuf = folder_icons[FOLDER_ICON_OUTBOX]; - else if (!strcasecmp (name, "/Trash")) + else if (!strcasecmp (path, "/Trash")) pixbuf = folder_icons[FOLDER_ICON_TRASH]; - else if (!strcasecmp (name, "/Junk")) - pixbuf = folder_icons[FOLDER_ICON_JUNK]; else pixbuf = folder_icons[FOLDER_ICON_NORMAL]; } - g_object_set (renderer, "pixbuf", pixbuf, -1); + g_object_set (renderer, "pixbuf", pixbuf, NULL); } static void @@ -193,10 +291,11 @@ render_display_name (GtkTreeViewColumn *column, GtkCellRenderer *renderer, { gboolean is_store, bold; unsigned int unread; + char *display; char *name; gtk_tree_model_get (model, iter, COL_STRING_DISPLAY_NAME, &name, - COL_BOO_IS_STORE, &is_store, + COL_BOOL_IS_STORE, &is_store, COL_UINT_UNREAD, &unread, -1); if (!(bold = is_store || unread)) { @@ -204,22 +303,131 @@ render_display_name (GtkTreeViewColumn *column, GtkCellRenderer *renderer, bold = subdirs_contain_unread (model, iter); } - g_object_set (renderer, "text", name, + if (!is_store && unread) + display = g_strdup_printf ("%s (%u)", name, unread); + else + display = g_strdup (name); + + g_object_set (renderer, "text", display, "weight", bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, "foreground_set", unread ? TRUE : FALSE, "foreground", unread ? "#0000ff" : "#000000", NULL); + + g_free (display); +} + +static void +em_folder_tree_init (EMFolderTree *emft) +{ + struct _EMFolderTreePrivate *priv; + + priv = g_new0 (struct _EMFolderTreePrivate, 1); + priv->store_hash = g_hash_table_new (g_direct_hash, g_direct_equal); + priv->uri_hash = g_hash_table_new (g_str_hash, g_str_equal); + priv->selected_uri = NULL; + priv->selected_path = NULL; + priv->treeview = NULL; + emft->priv = priv; +} + +static void +path_hash_free (gpointer key, gpointer value, gpointer user_data) +{ + g_free (key); + gtk_tree_row_reference_free (value); +} + +static void +store_info_free (struct _emft_store_info *si) +{ + camel_object_remove_event (si->store, si->created_id); + camel_object_remove_event (si->store, si->deleted_id); + camel_object_remove_event (si->store, si->renamed_id); + camel_object_remove_event (si->store, si->subscribed_id); + camel_object_remove_event (si->store, si->unsubscribed_id); + + g_free (si->display_name); + camel_object_unref (si->store); + gtk_tree_row_reference_free (si->row); + g_hash_table_foreach (si->path_hash, path_hash_free, NULL); + g_free (si); +} + +static void +store_hash_free (gpointer key, gpointer value, gpointer user_data) +{ + struct _emft_store_info *si = value; + + store_info_free (si); +} + +static void +uri_hash_free (gpointer key, gpointer value, gpointer user_data) +{ + g_free (key); + gtk_tree_row_reference_free (value); +} + +static void +em_folder_tree_finalize (GObject *obj) +{ + EMFolderTree *emft = (EMFolderTree *) obj; + + g_hash_table_foreach (emft->priv->store_hash, store_hash_free, NULL); + g_hash_table_destroy (emft->priv->store_hash); + + g_hash_table_foreach (emft->priv->uri_hash, uri_hash_free, NULL); + g_hash_table_destroy (emft->priv->uri_hash); + + g_free (emft->priv->selected_uri); + g_free (emft->priv->selected_path); + g_free (emft->priv); + + G_OBJECT_CLASS (parent_class)->finalize (obj); } +static void +em_folder_tree_destroy (GtkObject *obj) +{ + struct _EMFolderTreePrivate *priv = ((EMFolderTree *) obj)->priv; + + if (priv->ddr != 0) { + g_signal_handler_disconnect (obj, priv->ddr); + priv->ddr = 0; + } + + if (priv->rdp != 0) { + g_signal_handler_disconnect (obj, priv->rdp); + priv->rdp = 0; + } + + if (priv->rd != 0) { + g_signal_handler_disconnect (obj, priv->rd); + priv->rd = 0; + } + + if (priv->ddg != 0) { + g_signal_handler_disconnect (obj, priv->ddg); + priv->ddg = 0; + } + + if (priv->ddd != 0) { + g_signal_handler_disconnect (obj, priv->ddd); + priv->ddd = 0; + } + + GTK_OBJECT_CLASS (parent_class)->destroy (obj); +} + + static GtkTreeView * -folder_tree_new (void) +folder_tree_new (EMFolderTreeModel *model) { GtkTreeSelection *selection; GtkTreeViewColumn *column; GtkCellRenderer *renderer; - GtkTreeStore *model; GtkWidget *tree; - model = gtk_tree_store_newv (COL_LAST, col_types); tree = gtk_tree_view_new_with_model ((GtkTreeModel *) model); column = gtk_tree_view_column_new (); @@ -244,126 +452,578 @@ folder_tree_new (void) } static void -em_folder_tree_init (EMFolderTree *tree) +em_folder_tree_construct (EMFolderTree *emft, EMFolderTreeModel *model) { - struct _EMFolderTreePrivate *priv; + struct _EMFolderTreePrivate *priv = emft->priv; GtkTreeSelection *selection; GtkWidget *scrolled; - priv = g_new (struct _EMFolderTreePrivate, 1); - priv->store_hash = g_hash_table_new (g_direct_hash, g_direct_equal); - priv->uri_hash = g_hash_table_new (g_str_hash, g_str_equal); - priv->selected_uri = NULL; - scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), GTK_SHADOW_IN); - priv->treeview = folder_tree_new (); + priv->treeview = folder_tree_new (model); gtk_widget_show ((GtkWidget *) priv->treeview); - g_signal_connect (priv->treeview, "row-expanded", G_CALLBACK (tree_row_expanded), tree); - g_signal_connect (priv->treeview, "button-press-event", G_CALLBACK (tree_button_press), tree); + g_signal_connect (priv->treeview, "row-expanded", G_CALLBACK (tree_row_expanded), emft); + g_signal_connect (priv->treeview, "button-press-event", G_CALLBACK (tree_button_press), emft); selection = gtk_tree_view_get_selection ((GtkTreeView *) priv->treeview); - g_signal_connect (selection, "changed", G_CALLBACK (tree_selection_changed), tree); + g_signal_connect (selection, "changed", G_CALLBACK (tree_selection_changed), emft); gtk_container_add ((GtkContainer *) scrolled, (GtkWidget *) priv->treeview); gtk_widget_show (scrolled); - gtk_box_pack_start ((GtkBox *) tree, scrolled, TRUE, TRUE, 0); + gtk_box_pack_start ((GtkBox *) emft, scrolled, TRUE, TRUE, 0); } + + static void -store_hash_free (gpointer key, gpointer value, gpointer user_data) +drop_uid_list (EMFolderTree *emft, CamelFolder *dest, gboolean move, GtkSelectionData *selection, CamelException *ex) { - gtk_tree_path_free (value); - camel_object_unref (key); + CamelFolder *src; + GPtrArray *uids; + char *src_uri; + + em_utils_selection_get_uidlist (selection, &src_uri, &uids); + + if (!(src = mail_tool_uri_to_folder (src_uri, 0, ex))) { + em_utils_uids_free (uids); + g_free (src_uri); + return; + } + + g_free (src_uri); + + camel_folder_transfer_messages_to (src, uids, dest, NULL, move, ex); + em_utils_uids_free (uids); + camel_object_unref (src); } static void -em_folder_tree_finalize (GObject *obj) +drop_folder (EMFolderTree *emft, CamelFolder *dest, gboolean move, GtkSelectionData *selection, CamelException *ex) { - EMFolderTree *tree = (EMFolderTree *) obj; + CamelFolder *src; - g_hash_table_foreach (tree->priv->store_hash, store_hash_free, NULL); - g_hash_table_destroy (tree->priv->store_hash); + /* get the folder being dragged */ + if (!(src = mail_tool_uri_to_folder (selection->data, 0, ex))) + return; - g_free (tree->priv->selected_uri); - g_free (tree->priv); + if (src->parent_store == dest->parent_store && move) { + /* simple rename() action */ + char *old_name, *new_name; + + old_name = g_strdup (src->full_name); + new_name = g_strdup_printf ("%s/%s", dest->full_name, src->name); + + camel_store_rename_folder (dest->parent_store, old_name, new_name, ex); + + g_free (old_name); + g_free (new_name); + } else { + /* copy the folder to the new location */ + CamelFolder *folder; + char *path; + + path = g_strdup_printf ("%s/%s", dest->full_name, src->name); + if ((folder = camel_store_get_folder (dest->parent_store, path, CAMEL_STORE_FOLDER_CREATE, ex))) { + GPtrArray *uids; + + uids = camel_folder_get_uids (src); + camel_folder_transfer_messages_to (src, uids, folder, NULL, FALSE, ex); + camel_folder_free_uids (src, uids); + + camel_object_unref (folder); + } + + g_free (path); + } - G_OBJECT_CLASS (parent_class)->finalize (obj); + camel_object_unref (src); +} + +static gboolean +import_message_rfc822 (CamelFolder *dest, CamelStream *stream, gboolean scan_from, CamelException *ex) +{ + CamelMimeParser *mp; + + mp = camel_mime_parser_new (); + camel_mime_parser_scan_from (mp, scan_from); + camel_mime_parser_init_with_stream (mp, stream); + + while (camel_mime_parser_step (mp, 0, 0) == CAMEL_MIME_PARSER_STATE_FROM) { + CamelMessageInfo *info; + CamelMimeMessage *msg; + + msg = camel_mime_message_new (); + if (camel_mime_part_construct_from_parser (CAMEL_MIME_PART (msg), mp) == -1) { + camel_object_unref (msg); + camel_object_unref (mp); + return FALSE; + } + + /* append the message to the folder... */ + info = g_new0 (CamelMessageInfo, 1); + camel_folder_append_message (dest, msg, info, NULL, ex); + camel_object_unref (msg); + + if (camel_exception_is_set (ex)) { + camel_object_unref (mp); + return FALSE; + } + + /* skip over the FROM_END state */ + camel_mime_parser_step (mp, 0, 0); + } + + camel_object_unref (mp); + + return TRUE; } static void -em_folder_tree_destroy (GtkObject *obj) +drop_message_rfc822 (EMFolderTree *emft, CamelFolder *dest, GtkSelectionData *selection, CamelException *ex) { - GTK_OBJECT_CLASS (parent_class)->destroy (obj); + CamelStream *stream; + gboolean scan_from; + + scan_from = selection->length > 5 && !strncmp (selection->data, "From ", 5); + stream = camel_stream_mem_new_with_buffer (selection->data, selection->length); + + import_message_rfc822 (dest, stream, scan_from, ex); + + camel_object_unref (stream); +} + +static void +drop_text_uri_list (EMFolderTree *emft, CamelFolder *dest, GtkSelectionData *selection, CamelException *ex) +{ + char **urls, *url, *tmp; + CamelStream *stream; + CamelURL *uri; + int fd, i; + + tmp = g_strndup (selection->data, selection->length); + urls = g_strsplit (tmp, "\n", 0); + g_free (tmp); + + for (i = 0; urls[i] != NULL; i++) { + /* get the path component */ + url = g_strstrip (urls[i]); + uri = camel_url_new (url, NULL); + g_free (url); + + if (!uri || strcmp (uri->protocol, "file") != 0) { + camel_url_free (uri); + continue; + } + + url = uri->path; + uri->path = NULL; + camel_url_free (uri); + + if ((fd = open (url, O_RDONLY)) == -1) { + g_free (url); + continue; + } + + stream = camel_stream_fs_new_with_fd (fd); + if (!import_message_rfc822 (dest, stream, TRUE, ex)) { + /* FIXME: should we abort now? or continue? */ + /* for now lets just continue... */ + camel_exception_clear (ex); + } + + camel_object_unref (stream); + g_free (url); + } + + g_free (urls); +} + +static gboolean +drag_data_received_cb (EMFolderTreeModel *model, GtkTreePath *dest_path, GtkSelectionData *selection, EMFolderTree *emft) +{ + CamelFolder *folder; + CamelStore *store; + CamelException ex; + GtkTreeIter iter; + char *path; + + /* this means we are receiving no data */ + if (!selection->data || selection->length == -1) + return FALSE; + + gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, dest_path); + gtk_tree_model_get ((GtkTreeModel *) model, &iter, + COL_POINTER_CAMEL_STORE, &store, + COL_STRING_FOLDER_PATH, &path, -1); + + camel_exception_init (&ex); + if ((folder = camel_store_get_folder (store, path, 0, &ex))) { + /* FIXME: would have been nicer if we could 'move' + * messages and/or folders. but alas, gtktreeview + * drag&drop sucks ass and doesn't give us the + * context->action to check for GDK_ACTION_MOVE, so we + * can't. Yay. */ + gboolean move = FALSE; + + if (selection->target == gdk_atom_intern ("x-uid-list", FALSE)) { + /* import a list of uids from another evo folder */ + drop_uid_list (emft, folder, move, selection, &ex); + d(printf ("* dropped a x-uid-list\n")); + } else if (selection->target == gdk_atom_intern ("x-folder", FALSE)) { + /* copy or move (aka rename) a folder */ + drop_folder (emft, folder, move, selection, &ex); + d(printf ("* dropped a x-folder\n")); + } else if (selection->target == gdk_atom_intern ("message/rfc822", FALSE)) { + /* import a message/rfc822 stream */ + drop_message_rfc822 (emft, folder, selection, &ex); + d(printf ("* dropped a message/rfc822\n")); + } else if (selection->target == gdk_atom_intern ("text/uri-list", FALSE)) { + /* import an mbox, maildir, or mh folder? */ + drop_text_uri_list (emft, folder, selection, &ex); + d(printf ("* dropped a text/uri-list\n")); + } else { + g_assert_not_reached (); + } + } + + if (camel_exception_is_set (&ex)) { + /* FIXME: error dialog? */ + camel_exception_clear (&ex); + return FALSE; + } + + return TRUE; +} + +static gboolean +row_drop_possible_cb (EMFolderTreeModel *model, GtkTreePath *dest_path, GtkSelectionData *selection, EMFolderTree *emft) +{ + GtkTreeIter iter; + gboolean is_store; + + gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, dest_path); + gtk_tree_model_get ((GtkTreeModel *) model, &iter, COL_BOOL_IS_STORE, &is_store, -1); + + if (selection->target == gdk_atom_intern ("x-uid-list", FALSE)) { + if (is_store) + return FALSE; + + return TRUE; + } else if (selection->target == gdk_atom_intern ("x-folder", FALSE)) { + return TRUE; + } else if (selection->target == gdk_atom_intern ("message/rfc822", FALSE)) { + if (is_store) + return FALSE; + + return TRUE; + } else if (selection->target == gdk_atom_intern ("text/uri-list", FALSE)) { + if (is_store) + return FALSE; + + return TRUE; + } else { + g_assert_not_reached (); + return FALSE; + } +} + +static gboolean +row_draggable_cb (EMFolderTreeModel *model, GtkTreePath *src_path, EMFolderTree *emft) +{ + GtkTreeIter iter; + gboolean is_store; + + gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, src_path); + gtk_tree_model_get ((GtkTreeModel *) model, &iter, COL_BOOL_IS_STORE, &is_store, -1); + + return !is_store; +} + +static void +drag_text_uri_list (EMFolderTree *emft, CamelFolder *src, GtkSelectionData *selection, CamelException *ex) +{ + CamelFolder *dest; + const char *tmpdir; + CamelStore *store; + GPtrArray *uids; + char *url; + + if (!(tmpdir = e_mkdtemp ("drag-n-drop-XXXXXX"))) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Could not create temporary directory: %s"), + g_strerror (errno)); + return; + } + + url = g_strdup_printf ("mbox:%s", tmpdir); + if (!(store = camel_session_get_store (session, url, ex))) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Could not create temporary mbox store: %s"), + camel_exception_get_description (ex)); + g_free (url); + + return; + } + + if (!(dest = camel_store_get_folder (store, "mbox", CAMEL_STORE_FOLDER_CREATE, ex))) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Could not create temporary mbox folder: %s"), + camel_exception_get_description (ex)); + + camel_object_unref (store); + g_free (url); + + return; + } + + camel_object_unref (store); + uids = camel_folder_get_uids (src); + + camel_folder_transfer_messages_to (src, uids, dest, NULL, FALSE, ex); + if (camel_exception_is_set (ex)) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Could not copy messages to temporary mbox folder: %s"), + camel_exception_get_description (ex)); + } else { + memcpy (url, "file", 4); + gtk_selection_data_set (selection, selection->target, 8, url, strlen (url)); + } + + camel_folder_free_uids (src, uids); + camel_object_unref (dest); + g_free (url); +} + +static gboolean +drag_data_get_cb (EMFolderTreeModel *model, GtkTreePath *src_path, GtkSelectionData *selection, EMFolderTree *emft) +{ + CamelFolder *folder; + CamelStore *store; + CamelException ex; + GtkTreeIter iter; + char *path, *uri; + + gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, src_path); + gtk_tree_model_get ((GtkTreeModel *) model, &iter, + COL_POINTER_CAMEL_STORE, &store, + COL_STRING_FOLDER_PATH, &path, + COL_STRING_URI, &uri, -1); + + camel_exception_init (&ex); + + if (selection->target == gdk_atom_intern ("x-folder", FALSE)) { + /* dragging to a new location in the folder tree */ + gtk_selection_data_set (selection, selection->target, 8, uri, strlen (uri) + 1); + } else if (selection->target == gdk_atom_intern ("text/uri-list", FALSE)) { + /* dragging to nautilus or something, probably */ + if ((folder = camel_store_get_folder (store, path, 0, &ex))) { + drag_text_uri_list (emft, folder, selection, &ex); + camel_object_unref (folder); + } + } else { + g_assert_not_reached (); + } + + if (camel_exception_is_set (&ex)) { + /* FIXME: error dialog? */ + camel_exception_clear (&ex); + return FALSE; + } + + return TRUE; +} + +static gboolean +drag_data_delete_cb (EMFolderTreeModel *model, GtkTreePath *src_path, EMFolderTree *emft) +{ + gboolean is_store; + CamelStore *store; + CamelException ex; + GtkTreeIter iter; + char *path; + + gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, src_path); + gtk_tree_model_get ((GtkTreeModel *) model, &iter, + COL_POINTER_CAMEL_STORE, &store, + COL_STRING_FOLDER_PATH, &path, + COL_BOOL_IS_STORE, &is_store, -1); + + if (is_store) + return FALSE; + + camel_exception_init (&ex); + camel_store_delete_folder (store, path, &ex); + if (camel_exception_is_set (&ex)) { + /* FIXME: error dialog? */ + camel_exception_clear (&ex); + return FALSE; + } + + return TRUE; } GtkWidget * em_folder_tree_new (void) { - return g_object_new (EM_TYPE_FOLDER_TREE, NULL); + struct _EMFolderTreePrivate *priv; + EMFolderTreeModel *model; + EMFolderTree *emft; + + model = em_folder_tree_model_new (COL_LAST, col_types); + emft = (EMFolderTree *) em_folder_tree_new_with_model (model); + + priv = emft->priv; + priv->ddr = g_signal_connect (model, "drag-data-received", G_CALLBACK (drag_data_received_cb), emft); + priv->rdp = g_signal_connect (model, "row-drop-possible", G_CALLBACK (row_drop_possible_cb), emft); + priv->rd = g_signal_connect (model, "row-draggable", G_CALLBACK (row_draggable_cb), emft); + priv->ddg = g_signal_connect (model, "drag-data-get", G_CALLBACK (drag_data_get_cb), emft); + priv->ddd = g_signal_connect (model, "drag-data-delete", G_CALLBACK (drag_data_delete_cb), emft); + + gtk_drag_source_set ((GtkWidget *) emft, 0, drag_types, num_drag_types, GDK_ACTION_COPY | GDK_ACTION_MOVE); + gtk_drag_dest_set ((GtkWidget *) emft, GTK_DEST_DEFAULT_ALL, drop_types, num_drop_types, GDK_ACTION_COPY | GDK_ACTION_MOVE); + + return (GtkWidget *) emft; +} + + +GtkWidget * +em_folder_tree_new_with_model (EMFolderTreeModel *model) +{ + EMFolderTree *emft; + + emft = g_object_new (EM_TYPE_FOLDER_TREE, NULL); + em_folder_tree_construct (emft, model); + + return (GtkWidget *) emft; } static void -tree_row_expanded (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePath *path, EMFolderTree *ftree) +tree_store_set_folder_info (GtkTreeStore *model, GtkTreeIter *iter, + struct _EMFolderTreePrivate *priv, + struct _emft_store_info *si, + CamelFolderInfo *fi) { + GtkTreeRowReference *uri_row, *path_row; + unsigned int unread; + GtkTreePath *path; + GtkTreeIter sub; + gboolean load; + + load = (fi->flags & CAMEL_FOLDER_CHILDREN) && !(fi->flags & CAMEL_FOLDER_NOINFERIORS); + + path = gtk_tree_model_get_path ((GtkTreeModel *) model, iter); + uri_row = gtk_tree_row_reference_new ((GtkTreeModel *) model, path); + path_row = gtk_tree_row_reference_copy (uri_row); + gtk_tree_path_free (path); + + g_hash_table_insert (priv->uri_hash, g_strdup (fi->url), uri_row); + g_hash_table_insert (si->path_hash, g_strdup (fi->path), path_row); + + unread = fi->unread_message_count == -1 ? 0 : fi->unread_message_count; + + gtk_tree_store_set (model, iter, + COL_STRING_DISPLAY_NAME, fi->name, + COL_POINTER_CAMEL_STORE, si->store, + COL_STRING_FOLDER_PATH, fi->path, + COL_STRING_URI, fi->url, + COL_UINT_UNREAD, unread, + COL_BOOL_IS_STORE, FALSE, + COL_BOOL_LOAD_SUBDIRS, load, + -1); + + if (load) { + /* create a placeholder node for our subfolders... */ + gtk_tree_store_append (model, &sub, iter); + gtk_tree_store_set (model, &sub, + COL_STRING_DISPLAY_NAME, _("Loading..."), + COL_POINTER_CAMEL_STORE, si->store, + COL_STRING_FOLDER_PATH, fi->path, + COL_BOOL_LOAD_SUBDIRS, TRUE, + COL_BOOL_IS_STORE, FALSE, + COL_STRING_URI, fi->url, + COL_UINT_UNREAD, 0, + -1); + } +} + +static void +tree_row_expanded (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePath *tree_path, EMFolderTree *emft) +{ + /* FIXME: might be best to call get_folder_info in another thread and add the nodes to the treeview in the callback? */ + struct _EMFolderTreePrivate *priv = emft->priv; + struct _emft_store_info *si; CamelFolderInfo *fi, *child; CamelStore *store; + CamelException ex; GtkTreeStore *model; GtkTreeIter iter; - char *full_name; gboolean load; + char *path; + char *top; model = (GtkTreeStore *) gtk_tree_view_get_model (treeview); gtk_tree_model_get ((GtkTreeModel *) model, root, - COL_STRING_FOLDER_NAME, &full_name, + COL_STRING_FOLDER_PATH, &path, COL_POINTER_CAMEL_STORE, &store, COL_BOOL_LOAD_SUBDIRS, &load, -1); if (!load) return; + if (!(si = g_hash_table_lookup (emft->priv->store_hash, store))) { + g_assert_not_reached (); + return; + } + /* get the first child (which will be a dummy if we haven't loaded the child folders yet) */ gtk_tree_model_iter_children ((GtkTreeModel *) model, &iter, root); + /* FIXME: this sucks ass, need to fix camel so that using path as @top will Just Work (tm) */ + /* NOTE: CamelImapStore will handle "" as toplevel, but CamelMboxStore wants NULL */ + if (!path || !strcmp (path, "/")) + top = NULL; + else + top = path + 1; + /* FIXME: are there any flags we want to pass when getting folder-info's? */ camel_exception_init (&ex); - if (!(fi = camel_store_get_folder_info (store, full_name, 0, &ex))) { + if (!(fi = camel_store_get_folder_info (store, top, 0, &ex))) { /* FIXME: report error to user? or simply re-collapse node? or both? */ + g_warning ("can't get folder-info's for store '%s' at path='%s'", si->display_name, path); + gtk_tree_store_remove (model, &iter); camel_exception_clear (&ex); return; } - if (!(child = fi->child)) { + /* FIXME: camel is totally on crack here, @top's folder info + * should be @fi and fi->childs should be what we want to fill + * our tree with... *sigh* */ + if (!strcmp (fi->path, path)) + child = fi->sibling; + else + child = fi; + + if (child == NULL) { /* no children afterall... remove the "Loading..." placeholder node */ gtk_tree_store_remove (model, &iter); } else { do { - load = (child->flags & CAMEL_FOLDER_CHILDREN) && !(child->flags & CAMEL_FOLDER_NOINFERIORS); - - gtk_tree_store_set (model, &iter, - COL_STRING_DISPLAY_NAME, child->name, - COL_POINTER_CAMEL_STORE, store, - COL_STRING_FOLDER_PATH, child->path, - COL_STRING_URI, child->url, - COL_UINT_UNREAD, child->unread_message_count, - COL_BOOL_IS_STORE, FALSE, - COL_BOOL_LOAD_SUBDIRS, load, - -1); + tree_store_set_folder_info (model, &iter, priv, si, child); if ((child = child->sibling) != NULL) gtk_tree_store_append (model, &iter, root); } while (child != NULL); } - gtk_tree_store_set (model, root, COL_BOOL_LOAD_SUBDIRS, FALSE); + gtk_tree_store_set (model, root, COL_BOOL_LOAD_SUBDIRS, FALSE, -1); camel_store_free_folder_info (store, fi); } @@ -371,273 +1031,305 @@ tree_row_expanded (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePath *path, #if 0 static void -emc_popup_view(GtkWidget *w, MailComponent *mc) +emft_popup_view (GtkWidget *item, EMFolderTree *emft) { } static void -emc_popup_open_new(GtkWidget *w, MailComponent *mc) +emft_popup_open_new (GtkWidget *item, EMFolderTree *emft) { } #endif /* FIXME: This must be done in another thread */ static void -em_copy_folders(CamelStore *tostore, const char *tobase, CamelStore *fromstore, const char *frombase, int delete) +em_copy_folders (CamelStore *tostore, const char *tobase, CamelStore *fromstore, const char *frombase, int delete) { GString *toname, *fromname; CamelFolderInfo *fi; GList *pending = NULL, *deleting = NULL, *l; guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE; - CamelException *ex = camel_exception_new(); + CamelException ex; int fromlen; const char *tmp; - - if (camel_store_supports_subscriptions(fromstore)) + + camel_exception_init (&ex); + + if (camel_store_supports_subscriptions (fromstore)) flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED; - - fi = camel_store_get_folder_info(fromstore, frombase, flags, ex); - if (camel_exception_is_set(ex)) + + fi = camel_store_get_folder_info (fromstore, frombase, flags, &ex); + if (camel_exception_is_set (&ex)) goto done; - - pending = g_list_append(pending, fi); - - toname = g_string_new(""); - fromname = g_string_new(""); - - tmp = strrchr(frombase, '/'); + + pending = g_list_append (pending, fi); + + toname = g_string_new (""); + fromname = g_string_new (""); + + tmp = strrchr (frombase, '/'); if (tmp == NULL) fromlen = 0; else - fromlen = tmp-frombase+1; - - printf("top name is '%s'\n", fi->full_name); - + fromlen = tmp - frombase + 1; + + d(printf ("top name is '%s'\n", fi->full_name)); + while (pending) { CamelFolderInfo *info = pending->data; - - pending = g_list_remove_link(pending, pending); + + pending = g_list_remove_link (pending, pending); while (info) { CamelFolder *fromfolder, *tofolder; GPtrArray *uids; - + if (info->child) - pending = g_list_append(pending, info->child); + pending = g_list_append (pending, info->child); if (tobase[0]) - g_string_printf(toname, "%s/%s", tobase, info->full_name + fromlen); + g_string_printf (toname, "%s/%s", tobase, info->full_name + fromlen); else - g_string_printf(toname, "%s", info->full_name + fromlen); - - printf("Copying from '%s' to '%s'\n", info->full_name, toname->str); - + g_string_printf (toname, "%s", info->full_name + fromlen); + + d(printf ("Copying from '%s' to '%s'\n", info->full_name, toname->str)); + /* This makes sure we create the same tree, e.g. from a nonselectable source */ /* Not sure if this is really the 'right thing', e.g. for spool stores, but it makes the ui work */ if ((info->flags & CAMEL_FOLDER_NOSELECT) == 0) { - printf("this folder is selectable\n"); - fromfolder = camel_store_get_folder(fromstore, info->full_name, 0, ex); + d(printf ("this folder is selectable\n")); + fromfolder = camel_store_get_folder (fromstore, info->full_name, 0, &ex); if (fromfolder == NULL) goto exception; - - tofolder = camel_store_get_folder(tostore, toname->str, CAMEL_STORE_FOLDER_CREATE, ex); + + tofolder = camel_store_get_folder (tostore, toname->str, CAMEL_STORE_FOLDER_CREATE, &ex); if (tofolder == NULL) { - camel_object_unref(fromfolder); + camel_object_unref (fromfolder); goto exception; } - - if (camel_store_supports_subscriptions(tostore) - && !camel_store_folder_subscribed(tostore, toname->str)) - camel_store_subscribe_folder(tostore, toname->str, NULL); - - uids = camel_folder_get_uids(fromfolder); - camel_folder_transfer_messages_to(fromfolder, uids, tofolder, NULL, delete, ex); - camel_folder_free_uids(fromfolder, uids); - - camel_object_unref(fromfolder); - camel_object_unref(tofolder); + + if (camel_store_supports_subscriptions (tostore) + && !camel_store_folder_subscribed (tostore, toname->str)) + camel_store_subscribe_folder (tostore, toname->str, NULL); + + uids = camel_folder_get_uids (fromfolder); + camel_folder_transfer_messages_to (fromfolder, uids, tofolder, NULL, delete, &ex); + camel_folder_free_uids (fromfolder, uids); + + camel_object_unref (fromfolder); + camel_object_unref (tofolder); } - - if (camel_exception_is_set(ex)) + + if (camel_exception_is_set (&ex)) goto exception; else if (delete) - deleting = g_list_prepend(deleting, info); - + deleting = g_list_prepend (deleting, info); + info = info->sibling; } } - + /* delete the folders in reverse order from how we copyied them, if we are deleting any */ l = deleting; while (l) { CamelFolderInfo *info = l->data; - - printf("deleting folder '%s'\n", info->full_name); - - if (camel_store_supports_subscriptions(fromstore)) - camel_store_unsubscribe_folder(fromstore, info->full_name, NULL); - - camel_store_delete_folder(fromstore, info->full_name, NULL); + + d(printf ("deleting folder '%s'\n", info->full_name)); + + if (camel_store_supports_subscriptions (fromstore)) + camel_store_unsubscribe_folder (fromstore, info->full_name, NULL); + + camel_store_delete_folder (fromstore, info->full_name, NULL); l = l->next; } - -exception: - camel_store_free_folder_info(fromstore, fi); - g_list_free(deleting); - - g_string_free(toname, TRUE); - g_string_free(fromname, TRUE); -done: - printf("exception: %s\n", ex->desc?ex->desc:"<none>"); - camel_exception_free(ex); + + exception: + + camel_store_free_folder_info (fromstore, fi); + g_list_free (deleting); + + g_string_free (toname, TRUE); + g_string_free (fromname, TRUE); + + done: + + d(printf ("exception: %s\n", ex.desc ? ex.desc : "<none>")); + camel_exception_clear (&ex); } struct _copy_folder_data { - MailComponent *mc; - int delete; + EMFolderTree *emft; + gboolean delete; }; static void -emc_popup_copy_folder_selected(const char *uri, void *data) +emft_popup_copy_folder_selected (const char *uri, void *data) { - struct _copy_folder_data *d = data; - + struct _copy_folder_data *cfd = data; + struct _EMFolderTreePrivate *priv; + CamelStore *fromstore, *tostore; + char *tobase, *frombase; + CamelException ex; + CamelURL *url; + if (uri == NULL) { - g_free(d); + g_free (cfd); return; } - - if (uri) { - EFolder *folder = e_storage_set_get_folder(d->mc->priv->storage_set, d->mc->priv->context_path); - CamelException *ex = camel_exception_new(); - CamelStore *fromstore, *tostore; - char *tobase, *frombase; - CamelURL *url; - - printf("copying folder '%s' to '%s'\n", d->mc->priv->context_path, uri); - - fromstore = camel_session_get_store(session, e_folder_get_physical_uri(folder), ex); - frombase = strchr(d->mc->priv->context_path+1, '/')+1; - - tostore = camel_session_get_store(session, uri, ex); - url = camel_url_new(uri, NULL); - if (url->fragment) - tobase = url->fragment; - else if (url->path && url->path[0]) - tobase = url->path+1; - else - tobase = ""; - - em_copy_folders(tostore, tobase, fromstore, frombase, d->delete); - - camel_url_free(url); - camel_exception_free(ex); + + priv = cfd->emft->priv; + + d(printf ("copying folder '%s' to '%s'\n", priv->selected_path, uri)); + + camel_exception_init (&ex); + if (!(fromstore = camel_session_get_store (session, priv->selected_uri, &ex))) { + /* FIXME: error dialog? */ + camel_exception_clear (&ex); + return; } - g_free(d); + + frombase = priv->selected_path + 1; + + if (!(tostore = camel_session_get_store (session, uri, &ex))) { + /* FIXME: error dialog? */ + camel_object_unref (fromstore); + camel_exception_clear (&ex); + return; + } + + url = camel_url_new (uri, NULL); + if (url->fragment) + tobase = url->fragment; + else if (url->path && url->path[0]) + tobase = url->path + 1; + else + tobase = ""; + + em_copy_folders (tostore, tobase, fromstore, frombase, cfd->delete); + + camel_url_free (url); + g_free (cfd); } static void -emc_popup_copy(GtkWidget *w, MailComponent *mc) +emft_popup_copy (GtkWidget *item, EMFolderTree *emft) { - struct _copy_folder_data *d; - - d = g_malloc(sizeof(*d)); - d->mc = mc; - d->delete = 0; - em_select_folder(NULL, _("Select folder"), _("Select destination to copy folder into"), NULL, emc_popup_copy_folder_selected, d); + struct _copy_folder_data *cfd; + + cfd = g_malloc (sizeof (*cfd)); + cfd->emft = emft; + cfd->delete = FALSE; + + em_select_folder (NULL, _("Select folder"), + _("Select destination to copy folder into"), + NULL, emft_popup_copy_folder_selected, cfd); } static void -emc_popup_move(GtkWidget *w, MailComponent *mc) +emft_popup_move (GtkWidget *item, EMFolderTree *emft) { - struct _copy_folder_data *d; - - d = g_malloc(sizeof(*d)); - d->mc = mc; - d->delete = 1; - em_select_folder(NULL, _("Select folder"), _("Select destination to move folder into"), NULL, emc_popup_copy_folder_selected, d); + struct _copy_folder_data *cfd; + + cfd = g_malloc (sizeof (*cfd)); + cfd->emft = emft; + cfd->delete = TRUE; + + em_select_folder (NULL, _("Select folder"), + _("Select destination to move folder into"), + NULL, emft_popup_copy_folder_selected, cfd); } static void -emc_popup_new_folder_create(EStorageSet *ess, EStorageResult result, void *data) +emft_popup_new_folder_response (EMFolderSelector *emfs, int response, EMFolderTree *emft) { - d(printf ("folder created %s\n", result == E_STORAGE_OK ? "ok" : "failed")); + /* FIXME: ugh, kludge-a-licious: EMFolderSelector uses EMFolderTree so we can poke emfs->emft internals */ + struct _EMFolderTreePrivate *priv = emfs->emft->priv; + struct _emft_store_info *si; + const char *uri, *parent; + CamelException ex; + char *path, *name; + + if (response != GTK_RESPONSE_OK) { + gtk_widget_destroy ((GtkWidget *) emfs); + return; + } + + uri = em_folder_selector_get_selected_uri (emfs); + path = (char *) em_folder_selector_get_selected_path (emfs); + d(printf ("Creating folder: %s (%s)\n", path, uri)); + + if (!(si = g_hash_table_lookup (priv->store_hash, uri))) + goto done; + + /* FIXME: camel_store_create_folder should just take full path names */ + path = g_strdup (path); + if (!(name = strrchr (path, '/'))) { + name = path; + parent = ""; + } else { + *name++ = '\0'; + parent = path; + } + + d(printf ("creating folder name='%s' path='%s'\n", name, path)); + + camel_exception_init (&ex); + camel_store_create_folder (si->store, parent, name, &ex); + if (camel_exception_is_set (&ex)) { + d(printf ("Create failed: %s\n", ex.desc)); + /* FIXME: error dialog? */ + } else if (camel_store_supports_subscriptions (si->store)) { + camel_store_subscribe_folder (si->store, path, &ex); + if (camel_exception_is_set (&ex)) { + d(printf ("Subscribe failed: %s\n", ex.desc)); + /* FIXME: error dialog? */ + } + } + + camel_exception_clear (&ex); + + done: + + g_free (path); + + gtk_widget_destroy ((GtkWidget *) emfs); } static void -emc_popup_new_folder_response (EMFolderSelector *emfs, guint response, MailComponent *mc) +store_hash_add_store (gpointer key, gpointer value, gpointer user_data) { - /* FIXME: port this too :\ */ - if (response == GTK_RESPONSE_OK) { - char *path, *tmp, *name, *full; - EStorage *storage; - CamelStore *store; - CamelException *ex; - - printf("Creating folder: %s (%s)\n", em_folder_selector_get_selected(emfs), - em_folder_selector_get_selected_uri(emfs)); - - path = g_strdup(em_folder_selector_get_selected(emfs)); - tmp = strchr(path+1, '/'); - *tmp++ = 0; - /* FIXME: camel_store_create_folder should just take full path names */ - full = g_strdup(tmp); - name = strrchr(tmp, '/'); - if (name == NULL) { - name = tmp; - tmp = ""; - } else - *name++ = 0; - - storage = e_storage_set_get_storage(mc->priv->storage_set, path+1); - store = g_object_get_data((GObject *)storage, "em-store"); - - printf("creating folder '%s' / '%s' on '%s'\n", tmp, name, path+1); - - ex = camel_exception_new(); - camel_store_create_folder(store, tmp, name, ex); - if (camel_exception_is_set(ex)) { - printf("Create failed: %s\n", ex->desc); - } else if (camel_store_supports_subscriptions(store)) { - camel_store_subscribe_folder(store, full, ex); - if (camel_exception_is_set(ex)) { - printf("Subscribe failed: %s\n", ex->desc); - } - } - - camel_exception_free (ex); - - g_free (full); - g_free (path); - - /* Blah, this should just use camel, we get better error reporting if we do too */ - /*e_storage_set_async_create_folder(mc->priv->storage_set, path, "mail", "", emc_popup_new_folder_create, mc);*/ - } + struct _emft_store_info *si = value; + EMFolderTree *emft = user_data; - gtk_widget_destroy ((GtkWidget *) emfs); + em_folder_tree_add_store (emft, si->store, si->display_name); } static void -emc_popup_new_folder (GtkWidget *w, EMFolderTree *folder_tree) +emft_popup_new_folder (GtkWidget *item, EMFolderTree *emft) { + EMFolderTree *folder_tree; GtkWidget *dialog; - /* FIXME: ugh, need to port this (and em_folder_selector*) to use EMFolderTree I guess */ - dialog = em_folder_selector_create_new (mc->priv->storage_set, 0, _("Create folder"), _("Specify where to create the folder:")); - em_folder_selector_set_selected ((EMFolderSelector *) dialog, mc->priv->context_path); - g_signal_connect (dialog, "response", G_CALLBACK (emc_popup_new_folder_response), mc); + folder_tree = (EMFolderTree *) em_folder_tree_new (); + g_hash_table_foreach (emft->priv->store_hash, store_hash_add_store, folder_tree); + + dialog = em_folder_selector_create_new (folder_tree, 0, _("Create folder"), _("Specify where to create the folder:")); + em_folder_selector_set_selected ((EMFolderSelector *) dialog, emft->priv->selected_uri); + g_signal_connect (dialog, "response", G_CALLBACK (emft_popup_new_folder_response), emft); gtk_widget_show (dialog); } static void -em_delete_rec (CamelStore *store, CamelFolderInfo *fi, CamelException *ex) +emft_popup_delete_rec (CamelStore *store, CamelFolderInfo *fi, CamelException *ex) { while (fi) { CamelFolder *folder; - if (fi->child) - em_delete_rec (store, fi->child, ex); - if (camel_exception_is_set (ex)) - return; + if (fi->child) { + emft_popup_delete_rec (store, fi->child, ex); + + if (camel_exception_is_set (ex)) + return; + } d(printf ("deleting folder '%s'\n", fi->full_name)); @@ -667,7 +1359,7 @@ em_delete_rec (CamelStore *store, CamelFolderInfo *fi, CamelException *ex) } static void -em_delete_folders (CamelStore *store, const char *base, CamelException *ex) +emft_popup_delete_folders (CamelStore *store, const char *base, CamelException *ex) { guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE; CamelFolderInfo *fi; @@ -679,14 +1371,14 @@ em_delete_folders (CamelStore *store, const char *base, CamelException *ex) if (camel_exception_is_set (ex)) return; - em_delete_rec (store, fi, ex); + emft_popup_delete_rec (store, fi, ex); camel_store_free_folder_info (store, fi); } static void -emc_popup_delete_response (GtkWidget *dialog, guint response, EMFolderTree *folder_tree) +emft_popup_delete_response (GtkWidget *dialog, guint response, EMFolderTree *emft) { - struct _EMFolderTreePrivate *priv = folder_tree->priv; + struct _EMFolderTreePrivate *priv = emft->priv; GtkTreeSelection *selection; GtkTreeModel *model; CamelStore *store; @@ -703,9 +1395,8 @@ emc_popup_delete_response (GtkWidget *dialog, guint response, EMFolderTree *fold gtk_tree_model_get (model, &iter, COL_STRING_FOLDER_PATH, &path, COL_POINTER_CAMEL_STORE, &store, -1); - /* FIXME: need to hook onto store changed event and delete view as well, somewhere else tho */ camel_exception_init (&ex); - em_delete_folders (store, path, &ex); + emft_popup_delete_folders (store, path, &ex); if (camel_exception_is_set (&ex)) { e_notice (NULL, GTK_MESSAGE_ERROR, _("Could not delete folder: %s"), ex.desc); camel_exception_clear (&ex); @@ -713,9 +1404,9 @@ emc_popup_delete_response (GtkWidget *dialog, guint response, EMFolderTree *fold } static void -emc_popup_delete_folder (GtkWidget *item, EMFolderTree *folder_tree) +emft_popup_delete_folder (GtkWidget *item, EMFolderTree *emft) { - struct _EMFolderTreePrivate *priv = folder_tree->priv; + struct _EMFolderTreePrivate *priv = emft->priv; GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; @@ -742,14 +1433,14 @@ emc_popup_delete_folder (GtkWidget *item, EMFolderTree *folder_tree) gtk_window_set_title ((GtkWindow *) dialog, title); g_free (title); - g_signal_connect (dialog, "response", G_CALLBACK (emc_popup_delete_response), folder_tree); + g_signal_connect (dialog, "response", G_CALLBACK (emft_popup_delete_response), emft); gtk_widget_show (dialog); } static void -emc_popup_rename_folder (GtkWidget *item, EMFolderTree *folder_tree) +emft_popup_rename_folder (GtkWidget *item, EMFolderTree *emft) { - struct _EMFolderTreePrivate *priv = folder_tree->priv; + struct _EMFolderTreePrivate *priv = emft->priv; char *prompt, *folder_path, *name, *new_name, *uri; GtkTreeSelection *selection; gboolean done = FALSE; @@ -761,14 +1452,14 @@ emc_popup_rename_folder (GtkWidget *item, EMFolderTree *folder_tree) gtk_tree_selection_get_selected (selection, &model, &iter); gtk_tree_model_get (model, &iter, COL_STRING_FOLDER_PATH, &folder_path, COL_STRING_DISPLAY_NAME, &name, - COL_POINTER_STORE, &store, + COL_POINTER_CAMEL_STORE, &store, COL_STRING_URI, &uri, -1); prompt = g_strdup_printf (_("Rename the \"%s\" folder to:"), name); while (!done) { const char *why; - new = e_request_string (NULL, _("Rename Folder"), prompt, name); + new_name = e_request_string (NULL, _("Rename Folder"), prompt, name); if (new_name == NULL || !strcmp (name, new_name)) { /* old name == new name */ done = TRUE; @@ -794,7 +1485,7 @@ emc_popup_rename_folder (GtkWidget *item, EMFolderTree *folder_tree) oldpath = folder_path + 1; newpath = path + 1; - printf ("renaming %s to %s\n", oldpath, newpath); + d(printf ("renaming %s to %s\n", oldpath, newpath)); camel_exception_clear (&ex); camel_store_rename_folder (store, oldpath, newpath, &ex); @@ -821,7 +1512,7 @@ struct _prop_data { }; static void -emc_popup_properties_response (GtkWidget *dialog, int response, struct _prop_data *prop_data) +emft_popup_properties_response (GtkWidget *dialog, int response, struct _prop_data *prop_data) { CamelArgV *argv = prop_data->argv; int i; @@ -840,7 +1531,7 @@ emc_popup_properties_response (GtkWidget *dialog, int response, struct _prop_dat break; case CAMEL_ARG_STR: g_free (arg->ca_str); - arg->ca_str = gtk_entry_get_text ((GtkEntry *) prop_data->widgets[i]); + arg->ca_str = (char *) gtk_entry_get_text ((GtkEntry *) prop_data->widgets[i]); break; default: g_assert_not_reached (); @@ -853,7 +1544,7 @@ emc_popup_properties_response (GtkWidget *dialog, int response, struct _prop_dat } static void -emc_popup_properties_free (void *data) +emft_popup_properties_free (void *data) { struct _prop_data *prop_data = data; int i; @@ -869,7 +1560,7 @@ emc_popup_properties_free (void *data) } static void -emc_popup_properties_got_folder (char *uri, CamelFolder *folder, void *data) +emft_popup_properties_got_folder (char *uri, CamelFolder *folder, void *data) { GtkWidget *dialog, *w, *table, *label; struct _prop_data *prop_data; @@ -983,15 +1674,15 @@ emc_popup_properties_got_folder (char *uri, CamelFolder *folder, void *data) /* we do 'apply on ok' ... since instant apply may apply some very long running tasks */ - g_signal_connect (dialog, "response", G_CALLBACK (emc_popup_properties_response), prop_data); - g_object_set_data_full ((GObject *) dialog, "e-prop-data", prop_data, emc_popup_properties_free); + g_signal_connect (dialog, "response", G_CALLBACK (emft_popup_properties_response), prop_data); + g_object_set_data_full ((GObject *) dialog, "e-prop-data", prop_data, emft_popup_properties_free); gtk_widget_show (dialog); } static void -emc_popup_properties (GtkWidget *item, EMFolderTree *folder_tree) +emft_popup_properties (GtkWidget *item, EMFolderTree *emft) { - struct _EMFolderTreePrivate *priv = folder_tree->priv; + struct _EMFolderTreePrivate *priv = emft->priv; GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; @@ -1001,30 +1692,30 @@ emc_popup_properties (GtkWidget *item, EMFolderTree *folder_tree) gtk_tree_selection_get_selected (selection, &model, &iter); gtk_tree_model_get (model, &iter, COL_STRING_URI, &uri, -1); - mail_get_folder (uri, 0, emc_popup_properties_got_folder, folder_tree, mail_thread_new); + mail_get_folder (uri, 0, emft_popup_properties_got_folder, emft, mail_thread_new); } -static EMPopupItem emc_popup_menu[] = { +static EMPopupItem emft_popup_menu[] = { #if 0 - { EM_POPUP_ITEM, "00.emc.00", N_("_View"), G_CALLBACK (emc_popup_view), NULL, NULL, 0 }, - { EM_POPUP_ITEM, "00.emc.01", N_("Open in _New Window"), G_CALLBACK (emc_popup_open_new), NULL, NULL, 0 }, + { EM_POPUP_ITEM, "00.emc.00", N_("_View"), G_CALLBACK (emft_popup_view), NULL, NULL, 0 }, + { EM_POPUP_ITEM, "00.emc.01", N_("Open in _New Window"), G_CALLBACK (emft_popup_open_new), NULL, NULL, 0 }, { EM_POPUP_BAR, "10.emc" }, #endif - { EM_POPUP_ITEM, "10.emc.00", N_("_Copy"), G_CALLBACK (emc_popup_copy), NULL, "folder-copy-16.png", 0 }, - { EM_POPUP_ITEM, "10.emc.01", N_("_Move"), G_CALLBACK (emc_popup_move), NULL, "folder-move-16.png", 0 }, - + { EM_POPUP_ITEM, "10.emc.00", N_("_Copy"), G_CALLBACK (emft_popup_copy), NULL, "folder-copy-16.png", 0 }, + { EM_POPUP_ITEM, "10.emc.01", N_("_Move"), G_CALLBACK (emft_popup_move), NULL, "folder-move-16.png", 0 }, + { EM_POPUP_BAR, "20.emc" }, - { EM_POPUP_ITEM, "20.emc.00", N_("_New Folder..."), G_CALLBACK (emc_popup_new_folder), NULL, "folder-mini.png", 0 }, - { EM_POPUP_ITEM, "20.emc.01", N_("_Delete"), G_CALLBACK (emc_popup_delete_folder), NULL, "evolution-trash-mini.png", 0 }, - { EM_POPUP_ITEM, "20.emc.01", N_("_Rename"), G_CALLBACK (emc_popup_rename_folder), NULL, NULL, 0 }, - + { EM_POPUP_ITEM, "20.emc.00", N_("_New Folder..."), G_CALLBACK (emft_popup_new_folder), NULL, "folder-mini.png", 0 }, + { EM_POPUP_ITEM, "20.emc.01", N_("_Delete"), G_CALLBACK (emft_popup_delete_folder), NULL, "evolution-trash-mini.png", 0 }, + { EM_POPUP_ITEM, "20.emc.01", N_("_Rename"), G_CALLBACK (emft_popup_rename_folder), NULL, NULL, 0 }, + { EM_POPUP_BAR, "80.emc" }, - { EM_POPUP_ITEM, "80.emc.00", N_("_Properties..."), G_CALLBACK (emc_popup_properties), NULL, "configure_16_folder.xpm", 0 }, + { EM_POPUP_ITEM, "80.emc.00", N_("_Properties..."), G_CALLBACK (emft_popup_properties), NULL, "configure_16_folder.xpm", 0 }, }; static gboolean -tree_button_press (GtkWidget *treeview, GdkEventButton *event, EMFolderTree *ftree) +tree_button_press (GtkWidget *treeview, GdkEventButton *event, EMFolderTree *emft) { GSList *menus = NULL; GtkMenu *menu; @@ -1037,10 +1728,10 @@ tree_button_press (GtkWidget *treeview, GdkEventButton *event, EMFolderTree *ftr /* handle right-click by opening a context menu */ emp = em_popup_new ("com.ximian.mail.storageset.popup.select"); - for (i = 0; i < sizeof (emc_popup_menu) / sizeof (emc_popup_menu[0]); i++) { - EMPopupItem *item = &emc_popup_menu[i]; + for (i = 0; i < sizeof (emft_popup_menu) / sizeof (emft_popup_menu[0]); i++) { + EMPopupItem *item = &emft_popup_menu[i]; - item->activate_data = ftree; + item->activate_data = emft; menus = g_slist_prepend (menus, item); } @@ -1050,9 +1741,9 @@ tree_button_press (GtkWidget *treeview, GdkEventButton *event, EMFolderTree *ftr if (event == NULL || event->type == GDK_KEY_PRESS) { /* FIXME: menu pos function */ - gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, event->key.time); + gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, event->time); } else { - gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button.button, event->button.time); + gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button, event->time); } return TRUE; @@ -1060,32 +1751,202 @@ tree_button_press (GtkWidget *treeview, GdkEventButton *event, EMFolderTree *ftr static void -tree_selection_changed (GtkTreeSelection *selection, EMFolderTRee *ftree) +tree_selection_changed (GtkTreeSelection *selection, EMFolderTree *emft) { - /* new folder has been selected */ + struct _EMFolderTreePrivate *priv = emft->priv; + GtkTreeModel *model; + GtkTreeIter iter; + char *path, *uri; + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, COL_STRING_FOLDER_PATH, &path, + COL_STRING_URI, &uri, -1); + + g_free (priv->selected_uri); + priv->selected_uri = g_strdup (uri); + + g_free (priv->selected_path); + priv->selected_path = g_strdup (path); + + g_signal_emit (emft, signals[FOLDER_SELECTED], 0, path, uri); +} + + +static void +folder_subscribed_cb (CamelStore *store, void *event_data, EMFolderTree *emft) +{ + CamelFolderInfo *fi = event_data; + struct _emft_store_info *si; + GtkTreeRowReference *row; + GtkTreeIter parent, iter; + GtkTreeModel *model; + GtkTreePath *path; + gboolean load; + char *dirname; + + if (!(si = g_hash_table_lookup (emft->priv->store_hash, store))) + return; + + /* make sure we don't already know about it? */ + if (g_hash_table_lookup (si->path_hash, fi->path)) + return; + + /* get our parent folder's path */ + if (!(dirname = g_path_get_dirname (fi->path))) + return; + + if (!strcmp (dirname, "/")) { + /* user subscribed to a toplevel folder */ + row = si->row; + g_free (dirname); + } else { + row = g_hash_table_lookup (si->path_hash, dirname); + g_free (dirname); + + /* if row is NULL, don't bother adding to the tree, + * when the user expands enough nodes - it will be + * added auto-magically */ + if (row == NULL) + return; + } + + path = gtk_tree_row_reference_get_path (row); + model = gtk_tree_view_get_model (emft->priv->treeview); + if (!(gtk_tree_model_get_iter (model, &parent, path))) { + gtk_tree_path_free (path); + return; + } + + gtk_tree_path_free (path); + + /* make sure parent's subfolders have already been loaded */ + gtk_tree_model_get (model, &parent, COL_BOOL_LOAD_SUBDIRS, &load, -1); + if (load) + return; + + /* append a new node */ + gtk_tree_store_append ((GtkTreeStore *) model, &iter, &parent); + + tree_store_set_folder_info ((GtkTreeStore *) model, &iter, emft->priv, si, fi); +} + +static void +remove_folders (EMFolderTree *emft, GtkTreeModel *model, struct _emft_store_info *si, GtkTreeIter *toplevel) +{ + struct _EMFolderTreePrivate *priv = emft->priv; + GtkTreeRowReference *row; + char *uri, *folder_path; + gboolean is_store, go; + GtkTreeIter iter; + + if (gtk_tree_model_iter_children (model, &iter, toplevel)) { + do { + GtkTreeIter next = iter; + + go = gtk_tree_model_iter_next (model, &next); + remove_folders (emft, model, si, &iter); + iter = next; + } while (go); + } + + gtk_tree_model_get (model, toplevel, COL_STRING_URI, &uri, + COL_STRING_FOLDER_PATH, &folder_path, + COL_BOOL_IS_STORE, &is_store, -1); + + if ((row = g_hash_table_lookup (si->path_hash, folder_path))) { + g_hash_table_remove (si->path_hash, folder_path); + gtk_tree_row_reference_free (row); + } + + if ((row = g_hash_table_lookup (priv->uri_hash, uri))) { + g_hash_table_remove (priv->uri_hash, uri); + gtk_tree_row_reference_free (row); + } + + gtk_tree_store_remove ((GtkTreeStore *) model, toplevel); + + if (is_store) { + g_hash_table_remove (priv->store_hash, si->store); + store_info_free (si); + } +} + +static void +folder_unsubscribed_cb (CamelStore *store, void *event_data, EMFolderTree *emft) +{ + CamelFolderInfo *fi = event_data; + struct _emft_store_info *si; + GtkTreeRowReference *row; + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + + if (!(si = g_hash_table_lookup (emft->priv->store_hash, store))) + return; + + if (!(row = g_hash_table_lookup (si->path_hash, fi->path))) + return; + + path = gtk_tree_row_reference_get_path (row); + model = gtk_tree_view_get_model (emft->priv->treeview); + if (!(gtk_tree_model_get_iter (model, &iter, path))) { + gtk_tree_path_free (path); + return; + } + + remove_folders (emft, model, si, &iter); +} + +static void +folder_created_cb (CamelStore *store, void *event_data, EMFolderTree *emft) +{ + /* we only want created events to do more work if we don't support subscriptions */ + if (!camel_store_supports_subscriptions (store)) + folder_subscribed_cb (store, event_data, emft); +} + +static void +folder_deleted_cb (CamelStore *store, void *event_data, EMFolderTree *emft) +{ + /* we only want deleted events to do more work if we don't support subscriptions */ + if (!camel_store_supports_subscriptions (store)) + folder_unsubscribed_cb (store, event_data, emft); +} + +static void +folder_renamed_cb (CamelStore *store, void *event_data, EMFolderTree *emft) +{ + /* FIXME: implement me */ } void -em_folder_tree_add_store (EMFolderTree *tree, CamelStore *store, const char *display_name) +em_folder_tree_add_store (EMFolderTree *emft, CamelStore *store, const char *display_name) { struct _EMFolderTreePrivate *priv; + struct _emft_store_info *si; + GtkTreeRowReference *row; GtkTreeIter root, iter; GtkTreeStore *model; GtkTreePath *path; char *uri; - g_return_if_fail (EM_IS_FOLDER_TREE (tree)); + g_return_if_fail (EM_IS_FOLDER_TREE (emft)); g_return_if_fail (CAMEL_IS_STORE (store)); g_return_if_fail (display_name != NULL); - priv = tree->priv; + priv = emft->priv; model = (GtkTreeStore *) gtk_tree_view_get_model (priv->treeview); - if ((path = g_hash_table_lookup (priv->store_hash, store))) { + if ((si = g_hash_table_lookup (priv->store_hash, store))) { const char *name; + path = gtk_tree_row_reference_get_path (si->row); gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, path); + gtk_tree_path_free (path); + gtk_tree_model_get ((GtkTreeModel *) model, &iter, COL_STRING_DISPLAY_NAME, (char **) &name, -1); g_warning ("the store `%s' is already in the folder tree as `%s'", @@ -1102,13 +1963,21 @@ em_folder_tree_add_store (EMFolderTree *tree, CamelStore *store, const char *dis COL_STRING_DISPLAY_NAME, display_name, COL_POINTER_CAMEL_STORE, store, COL_STRING_FOLDER_PATH, "/", + COL_BOOL_LOAD_SUBDIRS, TRUE, COL_BOOL_IS_STORE, TRUE, COL_STRING_URI, uri, -1); - camel_object_ref (store); path = gtk_tree_model_get_path ((GtkTreeModel *) model, &iter); - g_hash_table_insert (priv->store_hash, store, path); - g_free (uri); + row = gtk_tree_row_reference_new ((GtkTreeModel *) model, path); + gtk_tree_path_free (path); + + si = g_new (struct _emft_store_info, 1); + si->display_name = g_strdup (display_name); + camel_object_ref (store); + si->store = store; + si->row = row; + si->path_hash = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (priv->store_hash, store, si); /* each store has folders... but we don't load them until the user demands them */ root = iter; @@ -1116,38 +1985,77 @@ em_folder_tree_add_store (EMFolderTree *tree, CamelStore *store, const char *dis gtk_tree_store_set (model, &iter, COL_STRING_DISPLAY_NAME, _("Loading..."), COL_POINTER_CAMEL_STORE, store, + COL_STRING_FOLDER_PATH, "/", COL_BOOL_LOAD_SUBDIRS, TRUE, COL_BOOL_IS_STORE, FALSE, COL_STRING_URI, uri, COL_UINT_UNREAD, 0, -1); + + g_free (uri); + + /* listen to store events */ +#define CAMEL_CALLBACK(func) ((CamelObjectEventHookFunc) func) + si->created_id = camel_object_hook_event (store, "folder_created", CAMEL_CALLBACK (folder_created_cb), emft); + si->deleted_id = camel_object_hook_event (store, "folder_deleted", CAMEL_CALLBACK (folder_deleted_cb), emft); + si->renamed_id = camel_object_hook_event (store, "folder_renamed", CAMEL_CALLBACK (folder_renamed_cb), emft); + si->subscribed_id = camel_object_hook_event (store, "folder_subscribed", CAMEL_CALLBACK (folder_subscribed_cb), emft); + si->unsubscribed_id = camel_object_hook_event (store, "folder_unsubscribed", CAMEL_CALLBACK (folder_unsubscribed_cb), emft); } void -em_folder_tree_remove_store (EMFolderTree *tree, CamelStore *store) +em_folder_tree_remove_store (EMFolderTree *emft, CamelStore *store) { struct _EMFolderTreePrivate *priv; - GtkTreeStore *model; + struct _emft_store_info *si; + GtkTreeModel *model; + GtkTreePath *path; GtkTreeIter iter; - g_return_if_fail (EM_IS_FOLDER_TREE (tree)); + g_return_if_fail (EM_IS_FOLDER_TREE (emft)); g_return_if_fail (CAMEL_IS_STORE (store)); - priv = tree->priv; - model = (GtkTreeStore *) gtk_tree_view_get_model (priv->treeview); + priv = emft->priv; + model = gtk_tree_view_get_model (priv->treeview); - if (!(path = g_hash_table_lookup (priv->store_hash, store))) { - g_warning ("the store `%s' is not in the folder tree", display_name); + if (!(si = g_hash_table_lookup (priv->store_hash, store))) { + g_warning ("the store `%s' is not in the folder tree", si->display_name); return; } - gtk_tree_model_get_iter ((GtkTreeModel *) model, &iter, path); + path = gtk_tree_row_reference_get_path (si->row); + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_path_free (path); + + /* recursively remove subfolders and finally the toplevel store */ + remove_folders (emft, model, si, &iter); +} + + +void +em_folder_tree_set_selected (EMFolderTree *emft, const char *uri) +{ + g_return_if_fail (EM_IS_FOLDER_TREE (emft)); - gtk_tree_store_remove (model, &iter); - g_hash_table_remove (priv->store_hash, store); + /* FIXME: implement me */ +} + + +const char * +em_folder_tree_get_selected_uri (EMFolderTree *emft) +{ + g_return_val_if_fail (EM_IS_FOLDER_TREE (emft), NULL); - camel_object_unref (store); - gtk_tree_path_free (path); + return emft->priv->selected_uri; +} + + +const char * +em_folder_tree_get_selected_path (EMFolderTree *emft) +{ + g_return_val_if_fail (EM_IS_FOLDER_TREE (emft), NULL); + + return emft->priv->selected_path; } diff --git a/mail/em-folder-tree.h b/mail/em-folder-tree.h index 7a5ce72cc3..938813b34a 100644 --- a/mail/em-folder-tree.h +++ b/mail/em-folder-tree.h @@ -27,6 +27,8 @@ #include <gtk/gtkvbox.h> #include <camel/camel-store.h> +#include "em-folder-tree-model.h" + #ifdef __cplusplus extern "C" { #pragma } @@ -51,15 +53,22 @@ struct _EMFolderTree { struct _EMFolderTreeClass { GtkVBoxClass parent_class; + /* signals */ + void (* folder_selected) (EMFolderTree *emft, const char *path, const char *uri); }; GType em_folder_tree_get_type (void); GtkWidget *em_folder_tree_new (void); +GtkWidget *em_folder_tree_new_with_model (EMFolderTreeModel *model); + +void em_folder_tree_add_store (EMFolderTree *emft, CamelStore *store, const char *display_name); +void em_folder_tree_remove_store (EMFolderTree *emft, CamelStore *store); -void em_folder_tree_add_store (EMFolderTree *tree, CamelStore *store, const char *display_name); -void em_folder_tree_remove_store (EMFolderTree *tree, CamelStore *store); +void em_folder_tree_set_selected (EMFolderTree *emft, const char *uri); +const char *em_folder_tree_get_selected_uri (EMFolderTree *emft); +const char *em_folder_tree_get_selected_path (EMFolderTree *emft); #ifdef __cplusplus } diff --git a/mail/em-marshal.list b/mail/em-marshal.list index 0c8bfbbbfb..4a19a91441 100644 --- a/mail/em-marshal.list +++ b/mail/em-marshal.list @@ -1,2 +1,5 @@ BOOLEAN:BOXED,POINTER,POINTER -NONE:POINTER +BOOLEAN:POINTER,POINTER +VOID:STRING,STRING +BOOLEAN:POINTER +VOID:POINTER diff --git a/mail/mail-component-factory.c b/mail/mail-component-factory.c index d941e8edbc..326f9177db 100644 --- a/mail/mail-component-factory.c +++ b/mail/mail-component-factory.c @@ -37,6 +37,8 @@ #include "mail-config.h" #include "mail-mt.h" +#include "shell/evolution-shell-client.h" + #include <bonobo-activation/bonobo-activation.h> #include <bonobo/bonobo-shlib-factory.h> diff --git a/mail/mail-component.c b/mail/mail-component.c index 12cc03ca78..f2e6a903c4 100644 --- a/mail/mail-component.c +++ b/mail/mail-component.c @@ -33,10 +33,8 @@ #include <fcntl.h> #include <errno.h> -#include "e-storage.h" -#include "e-storage-set.h" -#include "e-storage-browser.h" -#include "e-storage-set-view.h" +#include "em-folder-tree.h" +#include "em-folder-browser.h" #include "em-folder-selector.h" #include "em-folder-selection.h" @@ -72,164 +70,38 @@ #define d(x) x -#define MESSAGE_RFC822_TYPE "message/rfc822" -#define TEXT_URI_LIST_TYPE "text/uri-list" -#define UID_LIST_TYPE "x-uid-list" -#define FOLDER_TYPE "x-folder" - -/* Drag & Drop types */ -enum DndDragType { - DND_DRAG_TYPE_FOLDER, /* drag an evo folder */ - DND_DRAG_TYPE_TEXT_URI_LIST, /* drag to an mbox file */ -}; - -enum DndDropType { - DND_DROP_TYPE_UID_LIST, /* drop a list of message uids */ - DND_DROP_TYPE_FOLDER, /* drop an evo folder */ - DND_DROP_TYPE_MESSAGE_RFC822, /* drop a message/rfc822 stream */ - DND_DROP_TYPE_TEXT_URI_LIST, /* drop an mbox file */ -}; - -static GtkTargetEntry drag_types[] = { - { UID_LIST_TYPE, 0, DND_DRAG_TYPE_FOLDER }, - { TEXT_URI_LIST_TYPE, 0, DND_DRAG_TYPE_TEXT_URI_LIST }, -}; - -static const int num_drag_types = sizeof (drag_types) / sizeof (drag_types[0]); - -static GtkTargetEntry drop_types[] = { - { UID_LIST_TYPE, 0, DND_DROP_TYPE_UID_LIST }, - { FOLDER_TYPE, 0, DND_DROP_TYPE_FOLDER }, - { MESSAGE_RFC822_TYPE, 0, DND_DROP_TYPE_MESSAGE_RFC822 }, - { TEXT_URI_LIST_TYPE, 0, DND_DROP_TYPE_TEXT_URI_LIST }, -}; - -static const int num_drop_types = sizeof (drop_types) / sizeof (drop_types[0]); - #define PARENT_TYPE bonobo_object_get_type () static BonoboObjectClass *parent_class = NULL; struct _MailComponentPrivate { char *base_directory; - + + EMFolderTree *emft; + MailAsyncEvent *async_event; - GHashTable *storages_hash; /* storage by store */ - - EFolderTypeRegistry *folder_type_registry; - EStorageSet *storage_set; - + GHashTable *store_hash; /* display_name by store */ + RuleContext *search_context; - + char *context_path; /* current path for right-click menu */ - + CamelStore *local_store; }; -static int emc_tree_right_click(ETree *tree, gint row, ETreePath path, gint col, GdkEvent *event, MailComponent *component); - /* Utility functions. */ -/* EPFIXME: Eeek, this totally sucks. See comment in e-storage.h, - async_open_folder() should NOT be a signal. */ - -struct _StorageConnectedData { - EStorage *storage; - char *path; - EStorageDiscoveryCallback callback; - void *callback_data; -}; -typedef struct _StorageConnectedData StorageConnectedData; - -static void -storage_connected_callback (CamelStore *store, - CamelFolderInfo *info, - StorageConnectedData *data) -{ - EStorageResult result; - - if (info != NULL) - result = E_STORAGE_OK; - else - result = E_STORAGE_GENERICERROR; - - (* data->callback) (data->storage, result, data->path, data->callback_data); - - g_object_unref (data->storage); - g_free (data->path); - g_free (data); -} - static void -storage_async_open_folder_callback (EStorage *storage, - const char *path, - EStorageDiscoveryCallback callback, - void *callback_data, - CamelStore *store) +add_storage (MailComponent *component, const char *name, CamelService *store, CamelException *ex) { - StorageConnectedData *storage_connected_data = g_new0 (StorageConnectedData, 1); - - g_object_ref (storage); - - storage_connected_data->storage = storage; - storage_connected_data->path = g_strdup (path); - storage_connected_data->callback = callback; - storage_connected_data->callback_data = callback_data; - - mail_note_store (store, NULL, storage, - (void *) storage_connected_callback, storage_connected_data); + camel_object_ref (store); + g_hash_table_insert (component->priv->store_hash, store, g_strdup (name)); + em_folder_tree_add_store (component->priv->emft, (CamelStore *) store, name); + mail_note_store ((CamelStore *) store, NULL, NULL, NULL); } static void -add_storage (MailComponent *component, - const char *name, - CamelService *store, - CamelException *ex) -{ - EStorage *storage; - EFolder *root_folder; - - root_folder = e_folder_new (name, "noselect", ""); - storage = e_storage_new (name, root_folder); - e_storage_declare_has_subfolders(storage, "/", _("Connecting...")); - - camel_object_ref(store); - - g_object_set_data((GObject *)storage, "em-store", store); - g_hash_table_insert (component->priv->storages_hash, store, storage); - - g_signal_connect(storage, "async_open_folder", - G_CALLBACK (storage_async_open_folder_callback), store); - -#if 0 /* Some private test code - zed */ - { - static void *model; - - if (model == NULL) { - model = em_store_model_new(); - em_store_model_view_new(model); - } - - em_store_model_add_store(model, store); - } -#endif - -#if 0 - /* EPFIXME these are not needed anymore. */ - g_signal_connect(storage, "create_folder", G_CALLBACK(storage_create_folder), store); - g_signal_connect(storage, "remove_folder", G_CALLBACK(storage_remove_folder), store); - g_signal_connect(storage, "xfer_folder", G_CALLBACK(storage_xfer_folder), store); -#endif - - e_storage_set_add_storage (component->priv->storage_set, storage); - - mail_note_store ((CamelStore *) store, NULL, storage, NULL, NULL); - - g_object_unref (storage); -} - -static void -load_accounts(MailComponent *component, EAccountList *accounts) +load_accounts (MailComponent *component, EAccountList *accounts) { EIterator *iter; @@ -247,7 +119,7 @@ load_accounts(MailComponent *component, EAccountList *accounts) account = (EAccount *) e_iterator_get (iter); service = account->source; name = account->name; - + if (account->enabled && service->url != NULL) mail_component_load_storage_by_uri (component, service->url, name); @@ -257,39 +129,21 @@ load_accounts(MailComponent *component, EAccountList *accounts) g_object_unref (iter); } -static inline gboolean -type_is_mail (const char *type) -{ - return !strcmp (type, "mail") || !strcmp (type, "mail/public"); -} - -static inline gboolean -type_is_vtrash (const char *type) -{ - return !strcmp (type, "vtrash"); -} - -static inline gboolean -type_is_vjunk (const char *type) -{ - return !strcmp (type, "vjunk"); -} - static void storage_go_online (gpointer key, gpointer value, gpointer data) { CamelStore *store = key; CamelService *service = CAMEL_SERVICE (store); - + if (! (service->provider->flags & CAMEL_PROVIDER_IS_REMOTE) || (service->provider->flags & CAMEL_PROVIDER_IS_EXTERNAL)) return; - + if ((CAMEL_IS_DISCO_STORE (service) && camel_disco_store_status (CAMEL_DISCO_STORE (service)) == CAMEL_DISCO_STORE_OFFLINE) || service->status != CAMEL_SERVICE_DISCONNECTED) { mail_store_set_offline (store, FALSE, NULL, NULL); - mail_note_store (store, NULL, NULL, NULL, NULL); + mail_note_store (store, NULL, NULL, NULL); } } @@ -369,7 +223,6 @@ setup_local_store(MailComponent *component) g_free(store_uri); } -/* EStorageBrowser callbacks. */ static BonoboControl * create_noselect_control (void) @@ -378,498 +231,51 @@ create_noselect_control (void) label = gtk_label_new (_("This folder cannot contain messages.")); gtk_widget_show (label); + return bonobo_control_new (label); } static GtkWidget * -create_view_callback (EStorageBrowser *browser, - const char *path, - void *unused_data) +create_view_widget (EMFolderTree *emft, const char *path, const char *uri) { BonoboControl *control; - EFolder *folder; - const char *folder_type; - const char *physical_uri; - - folder = e_storage_set_get_folder (e_storage_browser_peek_storage_set (browser), path); - if (folder == NULL) { - g_warning ("No folder at %s", path); - return gtk_label_new ("(You should not be seeing this label)"); - } - - folder_type = e_folder_get_type_string (folder); - physical_uri = e_folder_get_physical_uri (folder); - - if (type_is_mail (folder_type)) { - const char *noselect; - CamelURL *url; - - url = camel_url_new (physical_uri, NULL); - noselect = url ? camel_url_get_param (url, "noselect") : NULL; - if (noselect && !strcasecmp (noselect, "yes")) - control = create_noselect_control (); - else - control = folder_browser_factory_new_control (physical_uri); - camel_url_free (url); - } else if (type_is_vtrash (folder_type)) { - if (!strncasecmp (physical_uri, "file:", 5)) - control = folder_browser_factory_new_control ("vtrash:file:/"); - else - control = folder_browser_factory_new_control (physical_uri); - } else if (type_is_vjunk (folder_type)) { - if (!strncasecmp (physical_uri, "file:", 5)) - control = folder_browser_factory_new_control ("vjunk:file:/"); - else - control = folder_browser_factory_new_control (physical_uri); - } else - return NULL; + const char *noselect; + CamelURL *url; + + url = camel_url_new (uri, NULL); + noselect = url ? camel_url_get_param (url, "noselect") : NULL; + if (noselect && !strcasecmp (noselect, "yes")) + control = create_noselect_control (); + else + control = folder_browser_factory_new_control (uri); + camel_url_free (url); if (!control) return NULL; - - /* EPFIXME: This leaks the control. */ - return bonobo_widget_new_control_from_objref (BONOBO_OBJREF (control), CORBA_OBJECT_NIL); -} - -static void -browser_page_switched_callback (EStorageBrowser *browser, - GtkWidget *old_page, - GtkWidget *new_page, - BonoboControl *parent_control) -{ - if (BONOBO_IS_WIDGET (old_page)) { - BonoboControlFrame *control_frame = bonobo_widget_get_control_frame (BONOBO_WIDGET (old_page)); - - bonobo_control_frame_control_deactivate (control_frame); - } - - if (BONOBO_IS_WIDGET (new_page)) { - BonoboControlFrame *control_frame = bonobo_widget_get_control_frame (BONOBO_WIDGET (new_page)); - Bonobo_UIContainer ui_container = bonobo_control_get_remote_ui_container (parent_control, NULL); - - /* This is necessary because we are not embedding the folder browser control - directly; we are putting the folder browser control into a notebook which - is then exported to the shell as a control. So we need to forward the - notebook's UIContainer to the folder browser. */ - bonobo_control_frame_set_ui_container (control_frame, ui_container, NULL); - - bonobo_control_frame_control_activate (control_frame); - } -} - -static CamelFolder * -foo_get_folder (EStorageSetView *view, const char *path, CamelException *ex) -{ - /* <NotZed> either do - mail_tool_uri_to_folder(ess_get_folder(path).physicaluri), - or split the path into 'path' and 'storage name' and do get - ess_get_storage() -> store -> open_folder - */ - CamelFolder *folder; - EStorageSet *set; - EFolder *efolder; - const char *uri; - - set = e_storage_set_view_get_storage_set (view); - efolder = e_storage_set_get_folder (set, path); - uri = e_folder_get_physical_uri (efolder); - - folder = mail_tool_uri_to_folder (uri, 0, ex); - - return folder; -} - -static void -drag_text_uri_list (EStorageSetView *view, const char *path, GtkSelectionData *selection, gpointer user_data) -{ - CamelFolder *src, *dest; - const char *tmpdir; - CamelStore *store; - CamelException ex; - GtkWidget *dialog; - GPtrArray *uids; - char *uri; - - camel_exception_init (&ex); - - if (!(src = foo_get_folder (view, path, &ex))) { - dialog = gtk_message_dialog_new ((GtkWindow *) view, GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - _("Could not open source folder: %s"), - camel_exception_get_description (&ex)); - - gtk_dialog_run ((GtkDialog *) dialog); - gtk_widget_destroy (dialog); - - camel_exception_clear (&ex); - - return; - } - if (!(tmpdir = e_mkdtemp ("drag-n-drop-XXXXXX"))) { - dialog = gtk_message_dialog_new ((GtkWindow *) view, GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - _("Could not create temporary directory: %s"), - g_strerror (errno)); - - gtk_dialog_run ((GtkDialog *) dialog); - gtk_widget_destroy (dialog); - - camel_object_unref (src); - - return; - } - - uri = g_strdup_printf ("mbox:%s", tmpdir); - if (!(store = camel_session_get_store (session, uri, &ex))) { - dialog = gtk_message_dialog_new ((GtkWindow *) view, GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - _("Could not create temporary mbox store: %s"), - camel_exception_get_description (&ex)); - - gtk_dialog_run ((GtkDialog *) dialog); - gtk_widget_destroy (dialog); - - camel_exception_clear (&ex); - camel_object_unref (src); - g_free (uri); - - return; - } - - if (!(dest = camel_store_get_folder (store, "mbox", CAMEL_STORE_FOLDER_CREATE, &ex))) { - dialog = gtk_message_dialog_new ((GtkWindow *) view, GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - _("Could not create temporary mbox folder: %s"), - camel_exception_get_description (&ex)); - - gtk_dialog_run ((GtkDialog *) dialog); - gtk_widget_destroy (dialog); - - camel_exception_clear (&ex); - camel_object_unref (store); - camel_object_unref (src); - g_free (uri); - - return; - } - - camel_object_unref (store); - uids = camel_folder_get_uids (src); - - camel_folder_transfer_messages_to (src, uids, dest, NULL, FALSE, &ex); - if (camel_exception_is_set (&ex)) { - dialog = gtk_message_dialog_new ((GtkWindow *) view, GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - _("Could not copy messages to temporary mbox folder: %s"), - camel_exception_get_description (&ex)); - - gtk_dialog_run ((GtkDialog *) dialog); - gtk_widget_destroy (dialog); - - camel_folder_free_uids (src, uids); - camel_exception_clear (&ex); - camel_object_unref (dest); - camel_object_unref (src); - g_free (uri); - - return; - } - - camel_folder_free_uids (src, uids); - camel_object_unref (dest); - camel_object_unref (src); - - memcpy (uri, "file", 4); - - gtk_selection_data_set (selection, selection->target, 8, - uri, strlen (uri)); - - g_free (uri); -} - -static void -folder_dragged_cb (EStorageSetView *view, const char *path, GdkDragContext *context, - GtkSelectionData *selection, guint info, guint time, gpointer user_data) -{ - printf ("dragging folder `%s'\n", path); - - switch (info) { - case DND_DRAG_TYPE_FOLDER: - /* dragging @path to a new location in the folder tree */ - gtk_selection_data_set (selection, selection->target, 8, path, strlen (path) + 1); - break; - case DND_DRAG_TYPE_TEXT_URI_LIST: - /* dragging @path to some place external to evolution */ - drag_text_uri_list (view, path, selection, user_data); - break; - default: - g_assert_not_reached (); - } -} - -static void -drop_uid_list (EStorageSetView *view, const char *path, gboolean move, GtkSelectionData *selection, gpointer user_data) -{ - CamelFolder *src, *dest; - CamelException ex; - GPtrArray *uids; - char *src_uri; - - em_utils_selection_get_uidlist (selection, &src_uri, &uids); - - camel_exception_init (&ex); - - if (!(src = mail_tool_uri_to_folder (src_uri, 0, &ex))) { - /* FIXME: report error to user? */ - camel_exception_clear (&ex); - em_utils_uids_free (uids); - g_free (src_uri); - return; - } - - g_free (src_uri); - - if (!(dest = foo_get_folder (view, path, &ex))) { - /* FIXME: report error to user? */ - camel_exception_clear (&ex); - em_utils_uids_free (uids); - camel_object_unref (src); - return; - } - - camel_folder_transfer_messages_to (src, uids, dest, NULL, move, &ex); - if (camel_exception_is_set (&ex)) { - /* FIXME: report error to user? */ - camel_exception_clear (&ex); - em_utils_uids_free (uids); - camel_object_unref (dest); - camel_object_unref (src); - return; - } - - em_utils_uids_free (uids); - camel_object_unref (dest); - camel_object_unref (src); -} - -static void -drop_folder (EStorageSetView *view, const char *path, gboolean move, GtkSelectionData *selection, gpointer user_data) -{ - CamelFolder *src, *dest; - CamelFolder *store; - CamelException ex; - - camel_exception_init (&ex); - - /* get the destination folder (where the user dropped). this - * will become the parent folder of the folder that got - * dragged */ - if (!(dest = foo_get_folder (view, path, &ex))) { - /* FIXME: report error to user? */ - camel_exception_clear (&ex); - return; - } - - /* get the folder being dragged */ - if (!(src = foo_get_folder (view, selection->data, &ex))) { - /* FIXME: report error to user? */ - camel_exception_clear (&ex); - camel_object_unref (dest); - return; - } - - if (src->parent_store == dest->parent_store && move) { - /* simple rename() action */ - char *old_name, *new_name; - - old_name = g_strdup (src->full_name); - new_name = g_strdup_printf ("%s/%s", dest->full_name, src->name); - camel_object_unref (src); - - camel_store_rename_folder (dest->parent_store, old_name, new_name, &ex); - if (camel_exception_is_set (&ex)) { - /* FIXME: report error to user? */ - camel_exception_clear (&ex); - camel_object_unref (dest); - g_free (old_name); - g_free (new_name); - return; - } - - camel_object_unref (dest); - g_free (old_name); - g_free (new_name); - } else { - /* copy the folder */ - camel_object_unref (dest); - camel_object_unref (src); - } -} - -static gboolean -import_message_rfc822 (CamelFolder *dest, CamelStream *stream, gboolean scan_from, CamelException *ex) -{ - CamelMimeParser *mp; - - mp = camel_mime_parser_new (); - camel_mime_parser_scan_from (mp, scan_from); - camel_mime_parser_init_with_stream (mp, stream); - - while (camel_mime_parser_step (mp, 0, 0) == CAMEL_MIME_PARSER_STATE_FROM) { - CamelMessageInfo *info; - CamelMimeMessage *msg; - - msg = camel_mime_message_new (); - if (camel_mime_part_construct_from_parser (CAMEL_MIME_PART (msg), mp) == -1) { - camel_object_unref (msg); - camel_object_unref (mp); - return FALSE; - } - - /* append the message to the folder... */ - info = g_new0 (CamelMessageInfo, 1); - camel_folder_append_message (dest, msg, info, NULL, ex); - camel_object_unref (msg); - - if (camel_exception_is_set (ex)) { - camel_object_unref (mp); - return FALSE; - } - - /* skip over the FROM_END state */ - camel_mime_parser_step (mp, 0, 0); - } - - camel_object_unref (mp); - - return TRUE; -} - -static void -drop_message_rfc822 (EStorageSetView *view, const char *path, GtkSelectionData *selection, gpointer user_data) -{ - CamelFolder *folder; - CamelStream *stream; - CamelException ex; - gboolean scan_from; - - camel_exception_init (&ex); - - if (!(folder = foo_get_folder (view, path, &ex))) { - /* FIXME: report error to user? */ - camel_exception_clear (&ex); - return; - } - - scan_from = selection->length > 5 && !strncmp (selection->data, "From ", 5); - stream = camel_stream_mem_new_with_buffer (selection->data, selection->length); - - if (!import_message_rfc822 (folder, stream, scan_from, &ex)) { - /* FIXME: report to user? */ - } - - camel_exception_clear (&ex); - - camel_object_unref (stream); - camel_object_unref (folder); + /* EPFIXME: This leaks the control. */ + return bonobo_widget_new_control_from_objref (BONOBO_OBJREF (control), CORBA_OBJECT_NIL); } static void -drop_text_uri_list (EStorageSetView *view, const char *path, GtkSelectionData *selection, gpointer user_data) +folder_selected_cb (EMFolderTree *emft, const char *path, const char *uri, GtkBox *vbox) { - CamelFolder *folder; - CamelStream *stream; - CamelException ex; - char **urls, *tmp; - int i; - - camel_exception_init (&ex); - - if (!(folder = foo_get_folder (view, path, &ex))) { - /* FIXME: report to user? */ - camel_exception_clear (&ex); - return; - } - - tmp = g_strndup (selection->data, selection->length); - urls = g_strsplit (tmp, "\n", 0); - g_free (tmp); + GtkWidget *view; + GList *l, *n; - for (i = 0; urls[i] != NULL; i++) { - CamelURL *uri; - char *url; - int fd; - - /* get the path component */ - url = g_strstrip (urls[i]); - uri = camel_url_new (url, NULL); - g_free (url); - - if (!uri || strcmp (uri->protocol, "file") != 0) { - camel_url_free (uri); - continue; - } - - url = uri->path; - uri->path = NULL; - camel_url_free (uri); - - if ((fd = open (url, O_RDONLY)) == -1) { - g_free (url); - continue; - } - - stream = camel_stream_fs_new_with_fd (fd); - if (!import_message_rfc822 (folder, stream, TRUE, &ex)) { - /* FIXME: report to user? */ - } - - camel_exception_clear (&ex); - camel_object_unref (stream); - g_free (url); + /* there should only ever be 1 child */ + l = gtk_container_get_children (GTK_CONTAINER (vbox)); + while (l != NULL) { + n = l->next; + gtk_widget_destroy (l->data); + g_list_free_1 (l); + l = n; } - camel_object_unref (folder); - g_free (urls); -} - -static void -folder_receive_drop_cb (EStorageSetView *view, const char *path, GdkDragContext *context, - GtkSelectionData *selection, guint info, guint time, gpointer user_data) -{ - gboolean move = context->action == GDK_ACTION_MOVE; - - /* this means we are receiving no data */ - if (!selection->data || selection->length == -1) - return; - - switch (info) { - case DND_DROP_TYPE_UID_LIST: - /* import a list of uids from another evo folder */ - drop_uid_list (view, path, move, selection, user_data); - printf ("* dropped a x-uid-list\n"); - break; - case DND_DROP_TYPE_FOLDER: - /* rename a folder */ - drop_folder (view, path, move, selection, user_data); - printf ("* dropped a x-folder\n"); - break; - case DND_DROP_TYPE_MESSAGE_RFC822: - /* import a message/rfc822 stream */ - drop_message_rfc822 (view, path, selection, user_data); - printf ("* dropped a message/rfc822\n"); - break; - case DND_DROP_TYPE_TEXT_URI_LIST: - /* import an mbox, maildir, or mh folder? */ - drop_text_uri_list (view, path, selection, user_data); - printf ("* dropped a text/uri-list\n"); - break; - default: - g_assert_not_reached (); - } + view = create_view_widget (emft, path, uri); + gtk_widget_show (view); - gtk_drag_finish (context, TRUE, TRUE, time); + gtk_box_pack_start_defaults (vbox, view); } @@ -879,49 +285,50 @@ static void impl_dispose (GObject *object) { MailComponentPrivate *priv = MAIL_COMPONENT (object)->priv; - - if (priv->storage_set != NULL) { - g_object_unref (priv->storage_set); - priv->storage_set = NULL; - } - - if (priv->folder_type_registry != NULL) { - g_object_unref (priv->folder_type_registry); - priv->folder_type_registry = NULL; - } - + if (priv->search_context != NULL) { g_object_unref (priv->search_context); priv->search_context = NULL; } - + if (priv->local_store != NULL) { camel_object_unref (CAMEL_OBJECT (priv->local_store)); priv->local_store = NULL; } - + (* G_OBJECT_CLASS (parent_class)->dispose) (object); } static void +store_hash_free (gpointer key, gpointer value, gpointer user_data) +{ + CamelStore *store = key; + char *name = value; + + g_free (name); + camel_object_unref (store); +} + +static void impl_finalize (GObject *object) { MailComponentPrivate *priv = MAIL_COMPONENT (object)->priv; - + g_free (priv->base_directory); - + mail_async_event_destroy (priv->async_event); - - g_hash_table_destroy (priv->storages_hash); /* EPFIXME free the data within? */ - + + g_hash_table_foreach (priv->store_hash, store_hash_free, NULL); + g_hash_table_destroy (priv->store_hash); + if (mail_async_event_destroy (priv->async_event) == -1) { g_warning("Cannot destroy async event: would deadlock"); g_warning(" system may be unstable at exit"); } - - g_free(priv->context_path); + + g_free (priv->context_path); g_free (priv); - + (* G_OBJECT_CLASS (parent_class)->finalize) (object); } @@ -930,45 +337,30 @@ impl_finalize (GObject *object) static void impl_createControls (PortableServer_Servant servant, - Bonobo_Control *corba_sidebar_control, + Bonobo_Control *corba_tree_control, Bonobo_Control *corba_view_control, CORBA_Environment *ev) { MailComponent *mail_component = MAIL_COMPONENT (bonobo_object_from_servant (servant)); MailComponentPrivate *priv = mail_component->priv; - EStorageBrowser *browser; + BonoboControl *tree_control; + BonoboControl *view_control; GtkWidget *tree_widget; - GtkWidget *tree_widget_scrolled; GtkWidget *view_widget; - BonoboControl *sidebar_control; - BonoboControl *view_control; - - browser = e_storage_browser_new (priv->storage_set, "/", create_view_callback, NULL); - - tree_widget = e_storage_browser_peek_tree_widget (browser); - tree_widget_scrolled = e_storage_browser_peek_tree_widget_scrolled (browser); - view_widget = e_storage_browser_peek_view_widget (browser); - - e_storage_set_view_set_drag_types ((EStorageSetView *) tree_widget, drag_types, num_drag_types); - e_storage_set_view_set_drop_types ((EStorageSetView *) tree_widget, drop_types, num_drop_types); - e_storage_set_view_set_allow_dnd ((EStorageSetView *) tree_widget, TRUE); - g_signal_connect (tree_widget, "folder_dragged", G_CALLBACK (folder_dragged_cb), browser); - g_signal_connect (tree_widget, "folder_receive_drop", G_CALLBACK (folder_receive_drop_cb), browser); + tree_widget = (GtkWidget *) priv->emft; + view_widget = gtk_vbox_new (0, TRUE); - gtk_widget_show (tree_widget_scrolled); + gtk_widget_show (tree_widget); gtk_widget_show (view_widget); - - sidebar_control = bonobo_control_new (tree_widget_scrolled); + + tree_control = bonobo_control_new (tree_widget); view_control = bonobo_control_new (view_widget); - - *corba_sidebar_control = CORBA_Object_duplicate (BONOBO_OBJREF (sidebar_control), ev); + + *corba_tree_control = CORBA_Object_duplicate (BONOBO_OBJREF (tree_control), ev); *corba_view_control = CORBA_Object_duplicate (BONOBO_OBJREF (view_control), ev); - - g_signal_connect_object (browser, "page_switched", - G_CALLBACK (browser_page_switched_callback), view_control, 0); - - g_signal_connect(tree_widget, "right_click", G_CALLBACK(emc_tree_right_click), mail_component); + + g_signal_connect (tree_widget, "folder-selected", G_CALLBACK (folder_selected_cb), view_widget); } @@ -1042,14 +434,13 @@ mail_component_init (MailComponent *component) if (camel_mkdir (priv->base_directory, 0777) == -1 && errno != EEXIST) abort (); + priv->emft = em_folder_tree_new (); + /* EPFIXME: Turn into an object? */ mail_session_init (priv->base_directory); priv->async_event = mail_async_event_new(); - priv->storages_hash = g_hash_table_new (NULL, NULL); - - priv->folder_type_registry = e_folder_type_registry_new (); - priv->storage_set = e_storage_set_new (priv->folder_type_registry); + priv->store_hash = g_hash_table_new (NULL, NULL); /* migrate evolution 1.x folders to 2.0's location/format */ mail_dir = g_strdup_printf ("%s/mail", priv->base_directory); @@ -1218,35 +609,34 @@ store_disconnect (CamelStore *store, void *data) { camel_service_disconnect (CAMEL_SERVICE (store), TRUE, NULL); - camel_object_unref (CAMEL_OBJECT (store)); + camel_object_unref (store); } void -mail_component_remove_storage (MailComponent *component, - CamelStore *store) +mail_component_remove_storage (MailComponent *component, CamelStore *store) { MailComponentPrivate *priv = component->priv; - EStorage *storage; + char *name; - /* Because the storages_hash holds a reference to each store + /* Because the store_hash holds a reference to each store * used as a key in it, none of them will ever be gc'ed, meaning * any call to camel_session_get_{service,store} with the same * URL will always return the same object. So this works. */ - storage = g_hash_table_lookup (priv->storages_hash, store); - if (!storage) + if (!(name = g_hash_table_lookup (priv->store_hash, store))) return; - g_hash_table_remove (priv->storages_hash, store); + g_hash_table_remove (priv->store_hash, store); + g_free (name); /* so i guess potentially we could have a race, add a store while one being removed. ?? */ mail_note_store_remove (store); - - e_storage_set_remove_storage (priv->storage_set, storage); - mail_async_event_emit(priv->async_event, MAIL_ASYNC_THREAD, (MailAsyncFunc) store_disconnect, store, NULL, NULL); + em_folder_tree_remove_store (priv->emft, store); + + mail_async_event_emit (priv->async_event, MAIL_ASYNC_THREAD, (MailAsyncFunc) store_disconnect, store, NULL, NULL); } @@ -1272,46 +662,29 @@ mail_component_remove_storage_by_uri (MailComponent *component, } -EStorage * -mail_component_lookup_storage (MailComponent *component, - CamelStore *store) -{ - EStorage *storage; - - /* Because the storages_hash holds a reference to each store - * used as a key in it, none of them will ever be gc'ed, meaning - * any call to camel_session_get_{service,store} with the same - * URL will always return the same object. So this works. - */ - - storage = g_hash_table_lookup (component->priv->storages_hash, store); - if (storage) - g_object_ref (storage); - - return storage; -} - - int mail_component_get_storage_count (MailComponent *component) { - return g_hash_table_size (component->priv->storages_hash); + return g_hash_table_size (component->priv->store_hash); } -EStorageSet * -mail_component_peek_storage_set (MailComponent *component) +void +mail_component_storages_foreach (MailComponent *component, GHFunc func, void *user_data) { - return component->priv->storage_set; + g_hash_table_foreach (component->priv->store_hash, func, user_data); } -void -mail_component_storages_foreach (MailComponent *component, - GHFunc func, - void *data) +EMFolderTreeModel * +mail_component_get_tree_model (MailComponent *component) { - g_hash_table_foreach (component->priv->storages_hash, func, data); + EMFolderTreeModel *model; + + model = (EMFolderTreeModel *) gtk_tree_view_get_model ((GtkTreeView *) component->priv->emft); + g_object_ref (model); + + return model; } extern struct _CamelSession *session; @@ -1502,681 +875,3 @@ mail_component_evomail_uri_from_folder (MailComponent *component, BONOBO_TYPE_FUNC_FULL (MailComponent, GNOME_Evolution_Component, PARENT_TYPE, mail_component) - - -/* ********************************************************************** */ -#if 0 -static void -emc_popup_view(GtkWidget *w, MailComponent *mc) -{ - -} - -static void -emc_popup_open_new(GtkWidget *w, MailComponent *mc) -{ -} -#endif - -/* FIXME: This must be done in another thread */ -static void -em_copy_folders(CamelStore *tostore, const char *tobase, CamelStore *fromstore, const char *frombase, int delete) -{ - GString *toname, *fromname; - CamelFolderInfo *fi; - GList *pending = NULL, *deleting = NULL, *l; - guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE; - CamelException *ex = camel_exception_new(); - int fromlen; - const char *tmp; - - if (camel_store_supports_subscriptions(fromstore)) - flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED; - - fi = camel_store_get_folder_info(fromstore, frombase, flags, ex); - if (camel_exception_is_set(ex)) - goto done; - - pending = g_list_append(pending, fi); - - toname = g_string_new(""); - fromname = g_string_new(""); - - tmp = strrchr(frombase, '/'); - if (tmp == NULL) - fromlen = 0; - else - fromlen = tmp-frombase+1; - - printf("top name is '%s'\n", fi->full_name); - - while (pending) { - CamelFolderInfo *info = pending->data; - - pending = g_list_remove_link(pending, pending); - while (info) { - CamelFolder *fromfolder, *tofolder; - GPtrArray *uids; - - if (info->child) - pending = g_list_append(pending, info->child); - if (tobase[0]) - g_string_printf(toname, "%s/%s", tobase, info->full_name + fromlen); - else - g_string_printf(toname, "%s", info->full_name + fromlen); - - printf("Copying from '%s' to '%s'\n", info->full_name, toname->str); - - /* This makes sure we create the same tree, e.g. from a nonselectable source */ - /* Not sure if this is really the 'right thing', e.g. for spool stores, but it makes the ui work */ - if ((info->flags & CAMEL_FOLDER_NOSELECT) == 0) { - printf("this folder is selectable\n"); - fromfolder = camel_store_get_folder(fromstore, info->full_name, 0, ex); - if (fromfolder == NULL) - goto exception; - - tofolder = camel_store_get_folder(tostore, toname->str, CAMEL_STORE_FOLDER_CREATE, ex); - if (tofolder == NULL) { - camel_object_unref(fromfolder); - goto exception; - } - - if (camel_store_supports_subscriptions(tostore) - && !camel_store_folder_subscribed(tostore, toname->str)) - camel_store_subscribe_folder(tostore, toname->str, NULL); - - uids = camel_folder_get_uids(fromfolder); - camel_folder_transfer_messages_to(fromfolder, uids, tofolder, NULL, delete, ex); - camel_folder_free_uids(fromfolder, uids); - - camel_object_unref(fromfolder); - camel_object_unref(tofolder); - } - - if (camel_exception_is_set(ex)) - goto exception; - else if (delete) - deleting = g_list_prepend(deleting, info); - - info = info->sibling; - } - } - - /* delete the folders in reverse order from how we copyied them, if we are deleting any */ - l = deleting; - while (l) { - CamelFolderInfo *info = l->data; - - printf("deleting folder '%s'\n", info->full_name); - - if (camel_store_supports_subscriptions(fromstore)) - camel_store_unsubscribe_folder(fromstore, info->full_name, NULL); - - camel_store_delete_folder(fromstore, info->full_name, NULL); - l = l->next; - } - -exception: - camel_store_free_folder_info(fromstore, fi); - g_list_free(deleting); - - g_string_free(toname, TRUE); - g_string_free(fromname, TRUE); -done: - printf("exception: %s\n", ex->desc?ex->desc:"<none>"); - camel_exception_free(ex); -} - -struct _copy_folder_data { - MailComponent *mc; - int delete; -}; - -static void -emc_popup_copy_folder_selected(const char *uri, void *data) -{ - struct _copy_folder_data *d = data; - - if (uri == NULL) { - g_free(d); - return; - } - - if (uri) { - EFolder *folder = e_storage_set_get_folder(d->mc->priv->storage_set, d->mc->priv->context_path); - CamelException *ex = camel_exception_new(); - CamelStore *fromstore, *tostore; - char *tobase, *frombase; - CamelURL *url; - - printf("copying folder '%s' to '%s'\n", d->mc->priv->context_path, uri); - - fromstore = camel_session_get_store(session, e_folder_get_physical_uri(folder), ex); - frombase = strchr(d->mc->priv->context_path+1, '/')+1; - - tostore = camel_session_get_store(session, uri, ex); - url = camel_url_new(uri, NULL); - if (url->fragment) - tobase = url->fragment; - else if (url->path && url->path[0]) - tobase = url->path+1; - else - tobase = ""; - - em_copy_folders(tostore, tobase, fromstore, frombase, d->delete); - - camel_url_free(url); - camel_exception_free(ex); - } - g_free(d); -} - -static void -emc_popup_copy(GtkWidget *w, MailComponent *mc) -{ - struct _copy_folder_data *d; - - d = g_malloc(sizeof(*d)); - d->mc = mc; - d->delete = 0; - em_select_folder(NULL, _("Select folder"), _("Select destination to copy folder into"), NULL, emc_popup_copy_folder_selected, d); -} - -static void -emc_popup_move(GtkWidget *w, MailComponent *mc) -{ - struct _copy_folder_data *d; - - d = g_malloc(sizeof(*d)); - d->mc = mc; - d->delete = 1; - em_select_folder(NULL, _("Select folder"), _("Select destination to move folder into"), NULL, emc_popup_copy_folder_selected, d); -} -static void -emc_popup_new_folder_create(EStorageSet *ess, EStorageResult result, void *data) -{ - printf("folder created %s\n", result == E_STORAGE_OK?"ok":"failed"); -} - -static void -emc_popup_new_folder_response(EMFolderSelector *emfs, guint response, MailComponent *mc) -{ - if (response == GTK_RESPONSE_OK) { - char *path, *tmp, *name, *full; - EStorage *storage; - CamelStore *store; - CamelException *ex; - - printf("Creating folder: %s (%s)\n", em_folder_selector_get_selected(emfs), - em_folder_selector_get_selected_uri(emfs)); - - path = g_strdup(em_folder_selector_get_selected(emfs)); - tmp = strchr(path+1, '/'); - *tmp++ = 0; - /* FIXME: camel_store_create_folder should just take full path names */ - full = g_strdup(tmp); - name = strrchr(tmp, '/'); - if (name == NULL) { - name = tmp; - tmp = ""; - } else - *name++ = 0; - - storage = e_storage_set_get_storage(mc->priv->storage_set, path+1); - store = g_object_get_data((GObject *)storage, "em-store"); - - printf("creating folder '%s' / '%s' on '%s'\n", tmp, name, path+1); - - ex = camel_exception_new(); - camel_store_create_folder(store, tmp, name, ex); - if (camel_exception_is_set(ex)) { - printf("Create failed: %s\n", ex->desc); - } else if (camel_store_supports_subscriptions(store)) { - camel_store_subscribe_folder(store, full, ex); - if (camel_exception_is_set(ex)) { - printf("Subscribe failed: %s\n", ex->desc); - } - } - - camel_exception_free(ex); - - g_free(full); - g_free(path); - - /* Blah, this should just use camel, we get better error reporting if we do too */ - /*e_storage_set_async_create_folder(mc->priv->storage_set, path, "mail", "", emc_popup_new_folder_create, mc);*/ - } - gtk_widget_destroy((GtkWidget *)emfs); -} - -static void -emc_popup_new_folder (GtkWidget *w, MailComponent *mc) -{ - GtkWidget *dialog; - - dialog = em_folder_selector_create_new(mc->priv->storage_set, 0, _("Create folder"), _("Specify where to create the folder:")); - em_folder_selector_set_selected((EMFolderSelector *)dialog, mc->priv->context_path); - g_signal_connect(dialog, "response", G_CALLBACK(emc_popup_new_folder_response), mc); - gtk_widget_show(dialog); -} - -static void -em_delete_rec(CamelStore *store, CamelFolderInfo *fi, CamelException *ex) -{ - while (fi) { - CamelFolder *folder; - - if (fi->child) - em_delete_rec(store, fi->child, ex); - if (camel_exception_is_set(ex)) - return; - - printf("deleting folder '%s'\n", fi->full_name); - - /* shouldn't camel do this itself? */ - if (camel_store_supports_subscriptions(store)) - camel_store_unsubscribe_folder(store, fi->full_name, NULL); - - folder = camel_store_get_folder(store, fi->full_name, 0, NULL); - if (folder) { - GPtrArray *uids = camel_folder_get_uids(folder); - int i; - - camel_folder_freeze(folder); - for (i = 0; i < uids->len; i++) - camel_folder_delete_message(folder, uids->pdata[i]); - camel_folder_sync(folder, TRUE, NULL); - camel_folder_thaw(folder); - camel_folder_free_uids(folder, uids); - } - - camel_store_delete_folder(store, fi->full_name, ex); - if (camel_exception_is_set(ex)) - return; - fi = fi->sibling; - } -} - -static void -em_delete_folders(CamelStore *store, const char *base, CamelException *ex) -{ - CamelFolderInfo *fi; - guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE; - - if (camel_store_supports_subscriptions(store)) - flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED; - - fi = camel_store_get_folder_info(store, base, flags, ex); - if (camel_exception_is_set(ex)) - return; - - em_delete_rec(store, fi, ex); - camel_store_free_folder_info(store, fi); -} - -static void -emc_popup_delete_response(GtkWidget *w, guint response, MailComponent *mc) -{ - gtk_widget_destroy(w); - - if (response == GTK_RESPONSE_OK) { - const char *path = strchr(mc->priv->context_path+1, '/')+1; - EFolder *folder = e_storage_set_get_folder(mc->priv->storage_set, mc->priv->context_path); - CamelException *ex = camel_exception_new(); - CamelStore *store; - - /* FIXME: need to hook onto store changed event and delete view as well, somewhere else tho */ - store = camel_session_get_store(session, e_folder_get_physical_uri(folder), ex); - if (camel_exception_is_set(ex)) - goto exception; - - em_delete_folders(store, path, ex); - if (!camel_exception_is_set(ex)) - goto noexception; - exception: - e_notice(NULL, GTK_MESSAGE_ERROR, - _("Could not delete folder: %s"), ex->desc); - noexception: - camel_exception_free(ex); - if (store) - camel_object_unref(store); - } -} - -static void -emc_popup_delete_folder(GtkWidget *w, MailComponent *mc) -{ - GtkWidget *dialog; - char *title; - const char *path = strchr(mc->priv->context_path+1, '/')+1; - EFolder *folder; - - folder = e_storage_set_get_folder(mc->priv->storage_set, mc->priv->context_path); - if (folder == NULL) - return; - - dialog = gtk_message_dialog_new(NULL, - GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_NONE, - _("Really delete folder \"%s\" and all of its subfolders?"), path); - - gtk_dialog_add_button((GtkDialog *)dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); - gtk_dialog_add_button((GtkDialog *)dialog, GTK_STOCK_DELETE, GTK_RESPONSE_OK); - - gtk_dialog_set_default_response((GtkDialog *)dialog, GTK_RESPONSE_OK); - gtk_container_set_border_width((GtkContainer *)dialog, 6); - gtk_box_set_spacing((GtkBox *)((GtkDialog *)dialog)->vbox, 6); - - title = g_strdup_printf(_("Delete \"%s\""), path); - gtk_window_set_title((GtkWindow *)dialog, title); - g_free(title); - - g_signal_connect(dialog, "response", G_CALLBACK(emc_popup_delete_response), mc); - gtk_widget_show(dialog); -} - -static void -emc_popup_rename_folder(GtkWidget *w, MailComponent *mc) -{ - char *prompt, *new; - EFolder *folder; - const char *old, *why; - int done = 0; - - folder = e_storage_set_get_folder(mc->priv->storage_set, mc->priv->context_path); - if (folder == NULL) - return; - - old = e_folder_get_name(folder); - prompt = g_strdup_printf (_("Rename the \"%s\" folder to:"), e_folder_get_name(folder)); - while (!done) { - new = e_request_string(NULL, _("Rename Folder"), prompt, old); - if (new == NULL || strcmp(old, new) == 0) - done = 1; -#if 0 - else if (!e_shell_folder_name_is_valid(new, &why)) - e_notice(NULL, GTK_MESSAGE_ERROR, _("The specified folder name is not valid: %s"), why); -#endif - else { - char *base, *path; - - /* FIXME: we can't use the os independent path crap here, since we want to control the format */ - base = g_path_get_dirname(mc->priv->context_path); - path = g_build_filename(base, new, NULL); - - if (e_storage_set_get_folder(mc->priv->storage_set, path) != NULL) { - e_notice(NULL, GTK_MESSAGE_ERROR, - _("A folder named \"%s\" already exists. Please use a different name."), new); - } else { - CamelStore *store; - CamelException *ex = camel_exception_new(); - const char *oldpath, *newpath; - - oldpath = strchr(mc->priv->context_path+1, '/'); - g_assert(oldpath); - newpath = strchr(path+1, '/'); - g_assert(newpath); - oldpath++; - newpath++; - - printf("renaming %s to %s\n", oldpath, newpath); - - store = camel_session_get_store(session, e_folder_get_physical_uri(folder), ex); - if (camel_exception_is_set(ex)) - goto exception; - - camel_store_rename_folder(store, oldpath, newpath, ex); - if (!camel_exception_is_set(ex)) - goto noexception; - - exception: - e_notice(NULL, GTK_MESSAGE_ERROR, - _("Could not rename folder: %s"), ex->desc); - noexception: - if (store) - camel_object_unref(store); - camel_exception_free(ex); - - done = 1; - } - g_free(path); - g_free(base); - } - g_free(new); - } -} - -struct _prop_data { - void *object; - CamelArgV *argv; - GtkWidget **widgets; -}; - -static void -emc_popup_properties_response(GtkWidget *dialog, int response, struct _prop_data *prop_data) -{ - int i; - CamelArgV *argv = prop_data->argv; - - if (response != GTK_RESPONSE_OK) { - gtk_widget_destroy(dialog); - return; - } - - for (i=0;i<argv->argc;i++) { - CamelArg *arg = &argv->argv[i]; - - switch (arg->tag & CAMEL_ARG_TYPE) { - case CAMEL_ARG_BOO: - arg->ca_int = gtk_toggle_button_get_active ((GtkToggleButton *) prop_data->widgets[i]); - break; - case CAMEL_ARG_STR: - g_free(arg->ca_str); - arg->ca_str = gtk_entry_get_text ((GtkEntry *) prop_data->widgets[i]); - break; - default: - printf("unknown property type set\n"); - } - } - - camel_object_setv(prop_data->object, NULL, argv); - gtk_widget_destroy(dialog); -} - -static void -emc_popup_properties_free(void *data) -{ - struct _prop_data *prop_data = data; - int i; - - for (i=0; i<prop_data->argv->argc; i++) { - if ((prop_data->argv->argv[i].tag & CAMEL_ARG_TYPE) == CAMEL_ARG_STR) - g_free(prop_data->argv->argv[i].ca_str); - } - camel_object_unref(prop_data->object); - g_free(prop_data->argv); - g_free(prop_data); -} - -static void -emc_popup_properties_got_folder (char *uri, CamelFolder *folder, void *data) -{ - if (folder) { - GtkWidget *dialog, *w, *table, *label; - GSList *list, *l; - char *name; - int row = 1; - gint32 count, i; - struct _prop_data *prop_data; - CamelArgV *argv; - CamelArgGetV *arggetv; - - camel_object_get(folder, NULL, CAMEL_FOLDER_PROPERTIES, &list, CAMEL_FOLDER_NAME, &name, NULL); - - dialog = gtk_dialog_new_with_buttons(_("Folder properties"), - NULL, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_OK, - GTK_RESPONSE_OK, - NULL); - - /* TODO: maybe we want some basic properties here, like message counts/approximate size/etc */ - w = gtk_frame_new(_("Properties")); - gtk_box_pack_start ((GtkBox *) ((GtkDialog *)dialog)->vbox, w, TRUE, TRUE, 6); - table = gtk_table_new(g_slist_length(list)+1, 2, FALSE); - gtk_container_add((GtkContainer *)w, table); - label = gtk_label_new(_("Folder Name")); - gtk_misc_set_alignment ((GtkMisc *) label, 1.0, 0.5); - gtk_table_attach ((GtkTable *) table, label, 0, 1, 0, 1, GTK_FILL|GTK_EXPAND, 0, 3, 0); - label = gtk_label_new(name); - gtk_misc_set_alignment ((GtkMisc *) label, 0.0, 0.5); - gtk_table_attach ((GtkTable *) table, label, 1, 2, 0, 1, GTK_FILL|GTK_EXPAND, 0, 3, 0); - - /* build an arggetv/argv to retrieve/store the results */ - count = g_slist_length(list); - arggetv = g_malloc0(sizeof(*arggetv) + (count - CAMEL_ARGV_MAX) * sizeof(arggetv->argv[0])); - arggetv->argc = count; - argv = g_malloc0(sizeof(*argv) + (count - CAMEL_ARGV_MAX) * sizeof(argv->argv[0])); - argv->argc = count; - i = 0; - l = list; - while (l) { - CamelProperty *prop = l->data; - - argv->argv[i].tag = prop->tag; - arggetv->argv[i].tag = prop->tag; - arggetv->argv[i].ca_ptr = &argv->argv[i].ca_ptr; - - l = l->next; - i++; - } - camel_object_getv(folder, NULL, arggetv); - g_free(arggetv); - - prop_data = g_malloc0(sizeof(*prop_data)); - prop_data->widgets = g_malloc0(sizeof(prop_data->widgets[0]) * count); - prop_data->argv = argv; - - /* setup the ui with the values retrieved */ - l = list; - i = 0; - while (l) { - CamelProperty *prop = l->data; - - switch (prop->tag & CAMEL_ARG_TYPE) { - case CAMEL_ARG_BOO: - w = gtk_check_button_new_with_label(prop->description); - gtk_toggle_button_set_active((GtkToggleButton *)w, argv->argv[i].ca_int != 0); - gtk_table_attach ((GtkTable *) table, w, 0, 2, row, row+1, 0, 0, 3, 3); - prop_data->widgets[i] = w; - break; - case CAMEL_ARG_STR: - label = gtk_label_new(prop->description); - gtk_misc_set_alignment ((GtkMisc *) label, 1.0, 0.5); - gtk_table_attach ((GtkTable *) table, label, 0, 1, row, row+1, GTK_FILL|GTK_EXPAND, 0, 3, 3); - - w = gtk_entry_new(); - if (argv->argv[i].ca_str) { - gtk_entry_set_text((GtkEntry *)w, argv->argv[i].ca_str); - camel_object_free(folder, argv->argv[i].tag, argv->argv[i].ca_str); - argv->argv[i].ca_str = NULL; - } - gtk_table_attach ((GtkTable *) table, w, 1, 2, row, row+1, GTK_FILL, 0, 3, 3); - prop_data->widgets[i] = w; - break; - default: - w = gtk_label_new("CamelFolder error: unsupported propery type"); - gtk_table_attach ((GtkTable *) table, w, 0, 2, row, row+1, 0, 0, 3, 3); - break; - } - - row++; - l = l->next; - } - - prop_data->object = folder; - camel_object_ref(folder); - - camel_object_free(folder, CAMEL_FOLDER_PROPERTIES, list); - camel_object_free(folder, CAMEL_FOLDER_NAME, name); - - /* we do 'apply on ok' ... since instant apply may apply some very long running tasks */ - - g_signal_connect(dialog, "response", G_CALLBACK(emc_popup_properties_response), prop_data); - g_object_set_data_full((GObject *)dialog, "e-prop-data", prop_data, emc_popup_properties_free); - gtk_widget_show_all(dialog); - } -} - -static void -emc_popup_properties(GtkWidget *w, MailComponent *mc) -{ - EFolder *efolder; - - /* TODO: Make sure we only have one dialog open for any given folder */ - - efolder = e_storage_set_get_folder(mc->priv->storage_set, mc->priv->context_path); - if (efolder == NULL) - return; - - mail_get_folder(e_folder_get_physical_uri(efolder), 0, emc_popup_properties_got_folder, mc, mail_thread_new); -} - -static EMPopupItem emc_popup_menu[] = { -#if 0 - { EM_POPUP_ITEM, "00.emc.00", N_("_View"), G_CALLBACK(emc_popup_view), NULL, NULL, 0 }, - { EM_POPUP_ITEM, "00.emc.01", N_("Open in _New Window"), G_CALLBACK(emc_popup_open_new), NULL, NULL, 0 }, - - { EM_POPUP_BAR, "10.emc" }, -#endif - { EM_POPUP_ITEM, "10.emc.00", N_("_Copy"), G_CALLBACK(emc_popup_copy), NULL, "folder-copy-16.png", 0 }, - { EM_POPUP_ITEM, "10.emc.01", N_("_Move"), G_CALLBACK(emc_popup_move), NULL, "folder-move-16.png", 0 }, - - { EM_POPUP_BAR, "20.emc" }, - { EM_POPUP_ITEM, "20.emc.00", N_("_New Folder..."), G_CALLBACK(emc_popup_new_folder), NULL, "folder-mini.png", 0 }, - { EM_POPUP_ITEM, "20.emc.01", N_("_Delete"), G_CALLBACK(emc_popup_delete_folder), NULL, "evolution-trash-mini.png", 0 }, - { EM_POPUP_ITEM, "20.emc.01", N_("_Rename"), G_CALLBACK(emc_popup_rename_folder), NULL, NULL, 0 }, - - { EM_POPUP_BAR, "80.emc" }, - { EM_POPUP_ITEM, "80.emc.00", N_("_Properties..."), G_CALLBACK(emc_popup_properties), NULL, "configure_16_folder.xpm", 0 }, -}; - - -static int -emc_tree_right_click(ETree *tree, gint row, ETreePath path, gint col, GdkEvent *event, MailComponent *component) -{ - char *name; - ETreeModel *model = e_tree_get_model(tree); - EMPopup *emp; - int i; - GSList *menus = NULL; - struct _GtkMenu *menu; - - name = e_tree_memory_node_get_data((ETreeMemory *)model, path); - g_free(component->priv->context_path); - component->priv->context_path = g_strdup(name); - printf("right click, path = '%s'\n", name); - - emp = em_popup_new("com.ximian.mail.storageset.popup.select"); - - for (i=0;i<sizeof(emc_popup_menu)/sizeof(emc_popup_menu[0]);i++) { - EMPopupItem *item = &emc_popup_menu[i]; - - item->activate_data = component; - menus = g_slist_prepend(menus, item); - } - - em_popup_add_items(emp, menus, (GDestroyNotify)g_slist_free); - - menu = em_popup_create_menu_once(emp, NULL, 0, 0); - - if (event == NULL || event->type == GDK_KEY_PRESS) { - /* FIXME: menu pos function */ - gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, event->key.time); - } else { - gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button.button, event->button.time); - } - - return TRUE; -} diff --git a/mail/mail-component.h b/mail/mail-component.h index 0a31fdc815..818b8d2ff9 100644 --- a/mail/mail-component.h +++ b/mail/mail-component.h @@ -30,7 +30,7 @@ #include <filter/rule-context.h> #include <bonobo/bonobo-object.h> -#include "shell/e-storage-set.h" +#include "em-folder-tree-model.h" #include "Evolution.h" @@ -48,13 +48,13 @@ typedef struct _MailComponentClass MailComponentClass; struct _MailComponent { BonoboObject parent; - + MailComponentPrivate *priv; }; struct _MailComponentClass { BonoboObjectClass parent_class; - + POA_GNOME_Evolution_Component__epv epv; }; @@ -76,15 +76,14 @@ void mail_component_remove_storage (MailComponent *component, CamelStore *store); void mail_component_remove_storage_by_uri (MailComponent *component, const char *uri); -EStorage *mail_component_lookup_storage (MailComponent *component, - CamelStore *store); int mail_component_get_storage_count (MailComponent *component); -EStorageSet *mail_component_peek_storage_set (MailComponent *component); void mail_component_storages_foreach (MailComponent *component, GHFunc func, void *data); +EMFolderTreeModel *mail_component_get_tree_model (MailComponent *component); + char *em_uri_from_camel (const char *curi); char *em_uri_to_camel (const char *euri); diff --git a/mail/mail-folder-cache.c b/mail/mail-folder-cache.c index 05b006b777..23f6221544 100644 --- a/mail/mail-folder-cache.c +++ b/mail/mail-folder-cache.c @@ -98,8 +98,6 @@ struct _store_info { CamelStore *store; /* the store for these folders */ - EStorage *storage; - /* Outstanding folderinfo requests */ EDList folderinfo_updates; }; @@ -186,20 +184,12 @@ real_flush_updates(void *o, void *event_data, void *data) { struct _folder_update *up; struct _store_info *si; - EStorage *storage; time_t now; LOCK(info_lock); while ((up = (struct _folder_update *)e_dlist_remhead(&updates))) { si = g_hash_table_lookup(stores, up->store); - if (si) { - storage = si->storage; - if (storage) - g_object_ref (storage); - } else { - storage = NULL; - } - + UNLOCK(info_lock); if (up->remove) { @@ -207,20 +197,10 @@ real_flush_updates(void *o, void *event_data, void *data) mail_vfolder_delete_uri(up->store, up->uri); mail_filter_delete_uri(up->store, up->uri); mail_config_uri_deleted(CAMEL_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(up->store))->compare_folder_name, up->uri); - if (up->unsub) - e_storage_removed_folder (storage, up->path); + } else mail_vfolder_add_uri(up->store, up->uri, TRUE); } else { - /* Its really a rename, but we have no way of telling the shell that, so remove it */ - if (up->oldpath) { - if (storage != NULL) { - d(printf("Removing old folder (rename?) '%s'\n", up->oldpath)); - e_storage_removed_folder(storage, up->oldpath); - } - /* ELSE? Shell supposed to handle the local snot case */ - } - /* We can tell the vfolder code though */ if (up->olduri && up->add) { d(printf("renaming folder '%s' to '%s'\n", up->olduri, up->uri)); @@ -229,40 +209,7 @@ real_flush_updates(void *o, void *event_data, void *data) mail_config_uri_renamed(CAMEL_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(up->store))->compare_folder_name, up->olduri, up->uri); } - - if (up->name == NULL) { - EFolder *folder = e_storage_get_folder (storage, up->path); - - if (folder != NULL) { - d(printf("updating unread count to '%s' to %d\n", up->path, up->unread)); - e_folder_set_unread_count (folder, up->unread); - } else { - g_warning ("No folder at %s ?!", up->path); - } - } else if (storage != NULL) { - char *type; - EFolder *new_folder; - - if (strncmp(up->uri, "vtrash:", 7)==0) { - type = "vtrash"; - } else if (strncmp(up->uri, "vjunk:", 6)==0) { - type = "vjunk"; - } else - type = "mail"; - - new_folder = e_folder_new (up->name, type, NULL); - d(printf("Adding new folder: %s\n", up->path)); - - e_folder_set_physical_uri (new_folder, up->uri); - e_folder_set_unread_count (new_folder, up->unread); - if (CAMEL_IS_DISCO_STORE(up->store) && camel_disco_store_can_work_offline((CamelDiscoStore *)up->store)) - e_folder_set_can_sync_offline (new_folder, TRUE); - else - e_folder_set_can_sync_offline (new_folder, FALSE); - - e_storage_new_folder(storage, up->path, new_folder); - } - + if (!up->olduri && up->add) mail_vfolder_add_uri(up->store, up->uri, FALSE); } @@ -285,9 +232,6 @@ real_flush_updates(void *o, void *event_data, void *data) notify_idle_id = g_idle_add_full (G_PRIORITY_LOW, notify_idle_cb, NULL, NULL); free_update(up); - - if (storage != NULL) - g_object_unref (storage); LOCK(info_lock); } @@ -429,9 +373,7 @@ setup_folder(CamelFolderInfo *fi, struct _store_info *si) up = g_malloc0(sizeof(*up)); up->path = g_strdup(mfi->path); - if (si->storage != NULL) { - up->name = g_strdup(fi->name); - } + up->name = g_strdup(fi->name); up->uri = g_strdup(fi->url); up->unread = (fi->unread_message_count==-1)?0:fi->unread_message_count; up->store = si->store; @@ -659,8 +601,7 @@ rename_folders(struct _store_info *si, const char *oldbase, const char *newbase, g_free(old); up->path = g_strdup(mfi->path); - if (si->storage) - up->name = g_strdup(fi->name); + up->name = g_strdup(fi->name); up->uri = g_strdup(mfi->uri); up->unread = fi->unread_message_count==-1?0:fi->unread_message_count; up->store = si->store; @@ -783,10 +724,7 @@ mail_note_store_remove(CamelStore *store) mail_msg_cancel(ud->id); ud = ud->next; } - - /* This is the only gtk object we need to unref */ - mail_async_event_emit(mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc)bonobo_object_unref, si->storage, 0, 0); - + camel_object_unref(si->store); g_hash_table_foreach(si->folders, (GHFunc)free_folder_info_hash, NULL); g_hash_table_destroy(si->folders); @@ -913,15 +851,13 @@ store_online_cb (CamelStore *store, void *data) } void -mail_note_store(CamelStore *store, CamelOperation *op, EStorage *storage, +mail_note_store(CamelStore *store, CamelOperation *op, void (*done)(CamelStore *store, CamelFolderInfo *info, void *data), void *data) { struct _store_info *si; struct _update_data *ud; const char *buf; guint timeout; - - g_return_if_fail (storage == NULL || E_IS_STORAGE (storage)); g_assert(CAMEL_IS_STORE(store)); g_assert(pthread_self() == mail_gui_thread); @@ -941,15 +877,10 @@ mail_note_store(CamelStore *store, CamelOperation *op, EStorage *storage, if (si == NULL) { d(printf("Noting a new store: %p: %s\n", store, camel_url_to_string(((CamelService *)store)->url, 0))); - /* FIXME: Need to ref the storages & store or something?? */ - si = g_malloc0(sizeof(*si)); si->folders = g_hash_table_new(g_str_hash, g_str_equal); si->folders_uri = g_hash_table_new(CAMEL_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->hash_folder_name, CAMEL_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->compare_folder_name); - si->storage = storage; - if (storage != NULL) - g_object_ref (storage); si->store = store; camel_object_ref((CamelObject *)store); g_hash_table_insert(stores, store, si); diff --git a/mail/mail-folder-cache.h b/mail/mail-folder-cache.h index b9f8f44dfb..875579ad67 100644 --- a/mail/mail-folder-cache.h +++ b/mail/mail-folder-cache.h @@ -25,27 +25,27 @@ #ifndef _MAIL_FOLDER_CACHE_H #define _MAIL_FOLDER_CACHE_H -#include "e-storage.h" +#include <camel/camel-store.h> /* Add a store whose folders should appear in the shell The folders are scanned from the store, and/or added at runtime via the folder_created event */ void -mail_note_store(CamelStore *store, CamelOperation *op, EStorage *storage, - void (*done) (CamelStore *store, CamelFolderInfo *info, void *data), - void *data); +mail_note_store (CamelStore *store, CamelOperation *op, + void (*done) (CamelStore *store, CamelFolderInfo *info, void *data), + void *data); /* de-note a store */ -void mail_note_store_remove(CamelStore *store); +void mail_note_store_remove (CamelStore *store); /* When a folder has been opened, notify it for watching. The folder must have already been created on the store (which has already been noted) before the folder can be opened */ -void mail_note_folder(CamelFolder *folder); +void mail_note_folder (CamelFolder *folder); /* Returns true if a folder is available (yet), and also sets *folderp (if supplied) to a (referenced) copy of the folder if it has already been opened */ -int mail_note_get_folder_from_uri(const char *uri, CamelFolder **folderp); +int mail_note_get_folder_from_uri (const char *uri, CamelFolder **folderp); #endif diff --git a/mail/mail-offline-handler.c b/mail/mail-offline-handler.c index ce0bcf729f..5a39249765 100644 --- a/mail/mail-offline-handler.c +++ b/mail/mail-offline-handler.c @@ -271,7 +271,7 @@ storage_go_online (gpointer key, gpointer value, gpointer data) if (service_is_relevant (CAMEL_SERVICE (store), FALSE)) { mail_store_set_offline (store, FALSE, NULL, NULL); - mail_note_store (store, NULL, NULL, NULL, NULL); + mail_note_store (store, NULL, NULL, NULL); } } diff --git a/mail/mail-send-recv.c b/mail/mail-send-recv.c index 6d70fe5047..193f7a0af4 100644 --- a/mail/mail-send-recv.c +++ b/mail/mail-send-recv.c @@ -42,8 +42,6 @@ #include "camel/camel-folder.h" #include "camel/camel-operation.h" -#include "evolution-storage.h" - #include "mail.h" #include "mail-mt.h" #include "mail-component.h" @@ -664,19 +662,7 @@ receive_update_got_store (char *uri, CamelStore *store, void *data) struct _send_info *info = data; if (store) { - EStorage *storage = mail_component_lookup_storage (mail_component_peek (), store); - - if (storage) { - mail_note_store(store, info->cancel, storage, receive_update_done, info); - /*bonobo_object_unref (BONOBO_OBJECT (storage));*/ - } else { - /* If we get here, store must be an external - * storage other than /local. (Eg, Exchange). - * Do a get_folder_info just to force it to - * update itself. - */ - mail_get_folderinfo(store, info->cancel, receive_update_got_folderinfo, info); - } + mail_get_folderinfo (store, info->cancel, receive_update_got_folderinfo, info); } else { receive_done ("", info); } |