diff options
Diffstat (limited to 'plugins/templates/templates.c')
-rw-r--r-- | plugins/templates/templates.c | 387 |
1 files changed, 234 insertions, 153 deletions
diff --git a/plugins/templates/templates.c b/plugins/templates/templates.c index 78a0cf40a1..89496b57eb 100644 --- a/plugins/templates/templates.c +++ b/plugins/templates/templates.c @@ -27,6 +27,7 @@ #include <glib/gi18n.h> #include <string.h> +#include <glade/glade.h> #include <gconf/gconf-client.h> #include <e-util/e-config.h> @@ -35,13 +36,15 @@ #include <camel/camel-stream-mem.h> #include <mail/e-mail-local.h> +#include <mail/e-mail-reader.h> #include <mail/em-composer-utils.h> -#include <mail/em-popup.h> #include <mail/mail-session.h> #include <mail/mail-ops.h> +#include <mail/message-list.h> #include <e-util/e-error.h> #include <e-util/e-plugin.h> -#include <glade/glade.h> +#include <e-util/e-util.h> +#include <shell/e-shell-view.h> #include <composer/e-msg-composer.h> @@ -63,32 +66,10 @@ enum { CLUE_N_COLUMNS }; -typedef struct { - CamelMimeMessage *msg; - EMPopupTargetSelect *t; -} UserData; - -static gchar * get_content (CamelMimeMessage *message); - -static void reply_with_template (EPopup *ep, EPopupItem *item, gpointer data); - -static void popup_free (EPopup *ep, GSList *l, gpointer data); - -static GSList *fill_submenu (CamelStore *store, - CamelFolderInfo *info, - GSList *list, - EMPopupTargetSelect *t); - -static GSList *append_to_menu (CamelFolder *folder, - GPtrArray *uids, - GSList *list, - EMPopupTargetSelect *t); - -void org_gnome_templates_popup (EPlugin *ep, EMPopupTargetSelect *t); - GtkWidget *e_plugin_lib_get_configure_widget (EPlugin *epl); -gboolean e_plugin_ui_init (GtkUIManager *ui_manager, EMsgComposer *composer); +gboolean e_plugin_ui_init (GtkUIManager *ui_manager, GObject *object); +gint e_plugin_lib_enable (EPlugin *plugin, gboolean enabled); /* Thanks to attachment reminder plugin for this*/ static void commit_changes (UIData *ui); @@ -102,6 +83,8 @@ static void value_cell_edited_callback (GtkCellRendererText *cell, gchar *path_ static gboolean clue_foreach_check_isempty (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, UIData *ui); +static gboolean plugin_enabled; + static void selection_changed (GtkTreeSelection *selection, UIData *ui) { @@ -496,32 +479,23 @@ get_content (CamelMimeMessage *message) } static void -reply_with_template (EPopup *ep, EPopupItem *item, gpointer data) +action_reply_with_template_cb (GtkAction *action, + CamelMimeMessage *message) { - CamelMimeMessage *new, *template, *reply_to; - CamelFolder *templates_folder; + CamelMimeMessage *new, *template; + CamelFolder *folder; struct _camel_header_raw *header; - UserData *userdata = item->user_data; gchar *cont; - /* We get the templates folder and all the uids of the messages in there */ - templates_folder = e_mail_local_get_folder (E_MAIL_FOLDER_TEMPLATES); - - /* Get from the currently selected folder, the currently selected message */ - reply_to = camel_folder_get_message (userdata->t->folder, - g_ptr_array_index (userdata->t->uids, 0), - NULL); - - /* The message we'll be using has been stored when building the menu */ - template = userdata->msg; + folder = e_mail_local_get_folder (E_MAIL_FOLDER_TEMPLATES); + template = g_object_get_data (G_OBJECT (action), "template"); /* The new message we are creating */ new = camel_mime_message_new(); /* Add the headers from the message we are replying to, so CC and that - * stuff is preserved. - */ - header = ((CamelMimePart *)reply_to)->headers; + * stuff is preserved. */ + header = ((CamelMimePart *)message)->headers; while (header) { if (g_ascii_strncasecmp (header->name, "content-", 8) != 0) { camel_medium_add_header((CamelMedium *) new, @@ -538,7 +512,7 @@ reply_with_template (EPopup *ep, EPopupItem *item, gpointer data) /* Set the To: field to the same To: field of the message we are replying to. */ camel_mime_message_set_recipients (new, CAMEL_RECIPIENT_TYPE_TO, - camel_mime_message_get_from (reply_to)); + camel_mime_message_get_from (message)); /* Copy the CC and BCC from the template.*/ camel_mime_message_set_recipients (new, CAMEL_RECIPIENT_TYPE_CC, @@ -551,160 +525,148 @@ reply_with_template (EPopup *ep, EPopupItem *item, gpointer data) cont, (gint) g_utf8_strlen(cont, -1), "text"); /* Create the composer */ - em_utils_edit_message (new, templates_folder); + em_utils_edit_message (new, folder); camel_object_unref(new); } static void -popup_free (EPopup *ep, GSList *l, gpointer data) +build_template_menus_recurse (GtkUIManager *ui_manager, + GtkActionGroup *action_group, + const gchar *menu_path, + guint *action_count, + guint merge_id, + CamelFolderInfo *folder_info, + CamelMimeMessage *message) { - g_slist_free (l); -} + CamelStore *store; -static GSList -*append_to_menu (CamelFolder *folder, GPtrArray *uids, GSList *list, EMPopupTargetSelect *t) -{ - gint i; + store = e_mail_local_get_store (); - for (i = 0; i < uids->len; i++) { - const gchar *subject; + while (folder_info != NULL) { + CamelFolder *folder; + GPtrArray *uids; + GtkAction *action; + const gchar *action_label; + gchar *action_name; gchar *path; - EPopupItem *item; - CamelMimeMessage *message; - UserData *user_data; - const gchar *uid; - - uid = g_strdup (g_ptr_array_index (uids, i)); - - /* Same as in fill_submenu */ - if (!g_str_has_suffix (folder->name, "Templates")) - path = g_strdup_printf ("80.%s", folder->full_name); - else - path = g_strdup ("80.Templates"); - - /* If this uid is trashed, ignore it */ - if (camel_folder_get_message_flags (folder, uid) & CAMEL_MESSAGE_DELETED) - continue; + guint ii; - /* Get the message for this uid */ - message = camel_folder_get_message (folder, - uid, - NULL); + folder = camel_store_get_folder ( + store, folder_info->full_name, 0, NULL); - subject = camel_mime_message_get_subject (message); + action_name = g_strdup_printf ( + "templates-menu-%d", *action_count); + *action_count = *action_count + 1; - /* Create the menu item for it */ - item = g_slice_alloc0(sizeof(*item)); - item->type = E_POPUP_ITEM; - item->path = g_strdup_printf ("%s/%02d", path, i); - item->label = g_strdup ((strlen(subject) > 0) ? subject : _("No title")); - item->visible = EM_POPUP_SELECT_MANY | EM_POPUP_SELECT_ONE; + /* To avoid having a Templates dir, we ignore the top level */ + if (g_str_has_suffix (folder->name, "Templates")) + action_label = _("Templates"); + else + action_label = folder->name; - /* Make some info available to the callback */ - user_data = g_slice_new(UserData); - user_data->msg = message; - user_data->t = t; + action = gtk_action_new ( + action_name, action_label, NULL, NULL); - item->user_data = user_data; - item->activate = reply_with_template; + gtk_action_group_add_action (action_group, action); - list = g_slist_prepend (list, item); - } + g_debug ("Adding %s/%s", menu_path, action_name); - return list; -} + gtk_ui_manager_add_ui ( + ui_manager, merge_id, menu_path, action_name, + action_name, GTK_UI_MANAGER_MENU, FALSE); -static GSList -*fill_submenu (CamelStore *store, CamelFolderInfo *info, GSList *list, EMPopupTargetSelect *t) -{ - while (info) { - CamelFolder *folder; - GPtrArray *uids; - EPopupItem *item; + path = g_strdup_printf ("%s/%s", menu_path, action_name); - folder = camel_store_get_folder (store, info->full_name, 0, NULL); + g_object_unref (action); + g_free (action_name); - item = g_slice_alloc0(sizeof(*item)); - item->type = E_POPUP_SUBMENU; - item->label = folder->name; - item->visible = EM_POPUP_SELECT_MANY | EM_POPUP_SELECT_ONE; + /* Add submenus, if any. */ + if (folder_info->child != NULL) + build_template_menus_recurse ( + ui_manager, action_group, + path, action_count, merge_id, + folder_info->child, message); - /* To avoid having a Templates dir, we ignore the top level */ - if (!g_str_has_suffix (folder->name, "Templates")) - item->path = g_strdup_printf ("80.%s", folder->full_name); - else - item->path = g_strdup ("80.Templates"); + /* Get the UIDs for this folder and add them to the menu. */ + uids = camel_folder_get_uids (folder); + for (ii = 0; ii < uids->len; ii++) { + CamelMimeMessage *template; + const gchar *uid = uids->pdata[ii]; + guint32 flags; - list = g_slist_prepend (list, item); + /* If the UIDs is marked for deletion, skip it. */ + flags = camel_folder_get_message_flags (folder, uid); + if (flags & CAMEL_MESSAGE_DELETED) + continue; - /* Get the uids for this folder and fill them in the menu */ - uids = camel_folder_get_uids (folder); - list = append_to_menu (folder, uids, list, t); - camel_folder_free_uids (folder, uids); + template = camel_folder_get_message (folder, uid, NULL); + camel_object_ref (template); - /* If the folder has a child, call this function again */ - if (info->child) { - list = fill_submenu (store, info->child, list, t); - } + action_label = + camel_mime_message_get_subject (template); + if (action_label == NULL || *action_label == '\0') + action_label = _("No Title"); - info = info->next; - } + action_name = g_strdup_printf ( + "templates-item-%d", *action_count); + *action_count = *action_count + 1; - return list; -} + action = gtk_action_new ( + action_name, action_label, NULL, NULL); -void -org_gnome_templates_popup (EPlugin *ep, EMPopupTargetSelect *t) -{ - CamelFolder *templates_folder; - CamelFolderInfo *templates_info; - CamelStore *store; + g_object_set_data_full ( + G_OBJECT (action), "template", template, + (GDestroyNotify) camel_object_unref); - GSList *list = NULL; + g_signal_connect ( + action, "activate", + G_CALLBACK (action_reply_with_template_cb), + message); - /* We get the templates folder and all the uids of the messages in there */ - store = e_mail_local_get_store (); + gtk_action_group_add_action (action_group, action); - templates_folder = e_mail_local_get_folder (E_MAIL_FOLDER_TEMPLATES); + g_debug ("Adding %s/%s", path, action_name); - templates_info = camel_store_get_folder_info ( - store, templates_folder->full_name, - CAMEL_STORE_FOLDER_INFO_RECURSIVE | - CAMEL_STORE_FOLDER_INFO_FAST, NULL); + gtk_ui_manager_add_ui ( + ui_manager, merge_id, path, action_name, + action_name, GTK_UI_MANAGER_MENUITEM, FALSE); - /* Get subfolders and fill it */ - list = fill_submenu (store, templates_info, list, t); + g_object_unref (action); + g_free (action_name); + } + camel_folder_free_uids (folder, uids); - e_popup_add_items (t->target.popup, list, NULL, popup_free, NULL); + g_free (path); - return; + folder_info = folder_info->next; + } } static void action_template_cb (GtkAction *action, - EMsgComposer *composer) + EMsgComposer *composer) { CamelMessageInfo *info; CamelMimeMessage *msg; - CamelFolder *templates_folder; + CamelFolder *folder; + + /* Get the templates folder and all UIDs of the messages there. */ + folder = e_mail_local_get_folder (E_MAIL_FOLDER_TEMPLATES); - /* We get the templates folder and all the uids of the messages in there */ - templates_folder = e_mail_local_get_folder (E_MAIL_FOLDER_TEMPLATES); msg = e_msg_composer_get_message_draft (composer); info = camel_message_info_new (NULL); /* FIXME: what's the ~0 for? :) */ - camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DRAFT, ~0); + camel_message_info_set_flags ( + info, CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DRAFT, ~0); - mail_append_mail (templates_folder, msg, info, NULL, composer); - - return; + mail_append_mail (folder, msg, info, NULL, composer); } -static GtkActionEntry entries[] = { +static GtkActionEntry composer_entries[] = { - { "Template", + { "template", GTK_STOCK_SAVE, N_("Save as _Template"), "<Shift><Control>t", @@ -712,9 +674,73 @@ static GtkActionEntry entries[] = { G_CALLBACK (action_template_cb) } }; -gboolean -e_plugin_ui_init (GtkUIManager *ui_manager, - EMsgComposer *composer) +static void +update_actions_cb (EShellView *shell_view) +{ + EShellContent *shell_content; + EShellWindow *shell_window; + GtkActionGroup *action_group; + GtkUIManager *ui_manager; + MessageList *message_list; + CamelMimeMessage *message; + CamelFolderInfo *folder_info; + CamelFolder *folder; + CamelStore *store; + EMailReader *reader; + GPtrArray *uids; + guint action_count = 0; + guint merge_id; + gpointer data; + + shell_content = e_shell_view_get_shell_content (shell_view); + shell_window = e_shell_view_get_shell_window (shell_view); + + ui_manager = e_shell_window_get_ui_manager (shell_window); + action_group = e_lookup_action_group (ui_manager, "templates"); + data = g_object_get_data (G_OBJECT (action_group), "merge-id"); + merge_id = GPOINTER_TO_UINT (data); + g_return_if_fail (merge_id > 0); + + gtk_ui_manager_remove_ui (ui_manager, merge_id); + e_action_group_remove_all_actions (action_group); + + if (!plugin_enabled) + return; + + reader = E_MAIL_READER (shell_content); + message_list = e_mail_reader_get_message_list (reader); + + folder = message_list->folder; + uids = message_list_get_selected (message_list); + + if (uids->len != 1) + goto exit; + + /* This is the source message to use in replying with a template. */ + message = camel_folder_get_message (folder, uids->pdata[0], NULL); + + /* Now recursively build template submenus in the pop-up menu. */ + + store = e_mail_local_get_store (); + folder = e_mail_local_get_folder (E_MAIL_FOLDER_TEMPLATES); + + folder_info = camel_store_get_folder_info ( + store, folder->full_name, + CAMEL_STORE_FOLDER_INFO_RECURSIVE | + CAMEL_STORE_FOLDER_INFO_FAST, NULL); + + build_template_menus_recurse ( + ui_manager, action_group, + "/mail-message-popup/mail-message-templates", + &action_count, merge_id, folder_info, message); + +exit: + em_utils_uids_free (uids); +} + +static gboolean +init_composer_actions (GtkUIManager *ui_manager, + EMsgComposer *composer) { GtkhtmlEditor *editor; @@ -723,7 +749,62 @@ e_plugin_ui_init (GtkUIManager *ui_manager, /* Add actions to the "composer" action group. */ gtk_action_group_add_actions ( gtkhtml_editor_get_action_group (editor, "composer"), - entries, G_N_ELEMENTS (entries), composer); + composer_entries, G_N_ELEMENTS (composer_entries), composer); return TRUE; } + +static gboolean +init_shell_actions (GtkUIManager *ui_manager, + EShellWindow *shell_window) +{ + EShellView *shell_view; + GtkActionGroup *action_group; + guint merge_id; + + shell_view = e_shell_window_get_shell_view (shell_window, "mail"); + + /* This is where we keep dynamically-built menu items. */ + e_shell_window_add_action_group (shell_window, "templates"); + action_group = e_lookup_action_group (ui_manager, "templates"); + + merge_id = gtk_ui_manager_new_merge_id (ui_manager); + + g_object_set_data ( + G_OBJECT (action_group), "merge-id", + GUINT_TO_POINTER (merge_id)); + + g_signal_connect ( + shell_view, "update-actions", + G_CALLBACK (update_actions_cb), NULL); +} + +gboolean +e_plugin_ui_init (GtkUIManager *ui_manager, + GObject *object) +{ + /* XXX This is a scenario I hadn't considered when designing + * EPluginUI: two different UI manager IDs with different + * closures sharing the same plugin entry point. We know + * the closures are both GObjects so we query the type. + * Awkward, but it should work for now. */ + + if (E_IS_MSG_COMPOSER (object)) + return init_composer_actions ( + ui_manager, E_MSG_COMPOSER (object)); + + if (E_IS_SHELL_WINDOW (object)) + return init_shell_actions ( + ui_manager, E_SHELL_WINDOW (object)); + + return FALSE; +} + +gint +e_plugin_lib_enable (EPlugin *plugin, + gboolean enabled) +{ + plugin_enabled = enabled; + + return 0; +} |