/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) version 3. * * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with the program; if not, see * * * Authors: * Ashish Shrivastava * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "mail/em-menu.h" #include "mail/em-utils.h" #include "mail/em-event.h" #include "composer/e-msg-composer.h" #include "libedataserver/e-account.h" #include "e-util/e-config.h" #include "e-util/e-util.h" #include "email-custom-header.h" #define d(x) #define GCONF_KEY_CUSTOM_HEADER "/apps/evolution/eplugin/email_custom_header/customHeader" typedef struct { GladeXML *xml; GConfClient *gconf; GtkWidget *treeview; GtkWidget *header_add; GtkWidget *header_edit; GtkWidget *header_remove; GtkListStore *store; } ConfigData; enum { HEADER_KEY_COLUMN, HEADER_VALUE_COLUMN, HEADER_N_COLUMNS }; struct _EmailCustomHeaderOptionsDialogPrivate { /* Glade XML data */ GladeXML *xml; /*Widgets*/ GtkWidget *main; GtkWidget *page; GtkWidget *header_table; GtkWidget *header_type_name_label; GArray *combo_box_header_value; GArray *email_custom_header_details; GArray *header_index_type; gint flag; char *help_section; }; /* epech - e-plugin email custom header*/ static void epech_dialog_class_init (GObjectClass *object_class); static void epech_dialog_finalize (GObject *object); static void epech_dialog_init (GObject *object); static void epech_dialog_dispose (GObject *object); static void epech_setup_widgets (CustomHeaderOptionsDialog *mch); static gint epech_check_existing_composer_window(gconstpointer a, gconstpointer b); static void commit_changes (ConfigData *cd); int e_plugin_lib_enable (EPluginLib *ep, int enable); GtkWidget *e_plugin_lib_get_configure_widget (EPlugin *epl); gboolean e_plugin_ui_init(GtkUIManager *ui_manager, EMsgComposer *composer); GtkWidget *org_gnome_email_custom_header_config_option (struct _EPlugin *epl, struct _EConfigHookItemFactoryData *data); int e_plugin_lib_enable (EPluginLib *ep, int enable) { return 0; } static void epech_get_widgets_data (CustomHeaderOptionsDialog *mch) { EmailCustomHeaderOptionsDialogPrivate *priv; HeaderValueComboBox *sub_combo_box_get; gint selected_item; gint index_row,index_column; priv = mch->priv; priv->header_index_type = g_array_new (FALSE, FALSE, sizeof (gint)); priv->flag++; for (index_row = 0,index_column = 0; index_column < priv->email_custom_header_details->len; index_column++) { sub_combo_box_get = &g_array_index(priv->combo_box_header_value, HeaderValueComboBox,index_column); selected_item = gtk_combo_box_get_active((GtkComboBox *)sub_combo_box_get->header_value_combo_box); g_array_append_val (priv->header_index_type, selected_item); } return; } static gboolean epech_get_widgets (CustomHeaderOptionsDialog *mch) { EmailCustomHeaderOptionsDialogPrivate *priv; priv = mch->priv; #define EMAIL_CUSTOM_HEADER(name) glade_xml_get_widget (priv->xml, name) priv->main = EMAIL_CUSTOM_HEADER ("email-custom-header-dialog"); if (!priv->main) return FALSE; priv->page = EMAIL_CUSTOM_HEADER ("email-custom-header-vbox"); priv->header_table = EMAIL_CUSTOM_HEADER ("email-custom-header-options"); #undef EMAIL_CUSTOM_HEADER return (priv->page &&priv->header_table); } static void epech_fill_widgets_with_data (CustomHeaderOptionsDialog *mch) { EmailCustomHeaderOptionsDialogPrivate *priv; HeaderValueComboBox *sub_combo_box_fill; gint set_index_row,set_index_column; priv = mch->priv; priv->help_section = g_strdup ("usage-mail"); for (set_index_row = 0,set_index_column = 0; set_index_column < priv->email_custom_header_details->len;set_index_column++) { sub_combo_box_fill = &g_array_index(priv->combo_box_header_value, HeaderValueComboBox,set_index_column); if (priv->flag == 0) { gtk_combo_box_set_active ((GtkComboBox *)sub_combo_box_fill->header_value_combo_box,0); } else { gtk_combo_box_set_active ((GtkComboBox *)sub_combo_box_fill->header_value_combo_box, g_array_index(priv->header_index_type, gint, set_index_column)); } } } CustomHeaderOptionsDialog * epech_dialog_new (void) { CustomHeaderOptionsDialog *mch; mch = g_object_new (EMAIL_CUSTOM_HEADER_OPTIONS_DIALOG, NULL); return mch; } GType epech_dialog_get_type (void) { static GType type = 0; if (type == 0) { static const GTypeInfo info = { sizeof (CustomHeaderOptionsDialogClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) epech_dialog_class_init, /* class_init */ NULL, /* class_finalize */ NULL, /* class_data */ sizeof (CustomHeaderOptionsDialog), 0, /* n_preallocs */ (GInstanceInitFunc) epech_dialog_init, NULL /* instance_init */ }; type = g_type_register_static (G_TYPE_OBJECT, "CustomHeaderOptionsDialogType", &info, 0); } return type; } static void epech_header_options_cb (GtkDialog *dialog, gint state, gpointer func_data) { EmailCustomHeaderOptionsDialogPrivate *priv; CustomHeaderOptionsDialog *mch; mch = func_data; priv = mch->priv; switch (state) { case GTK_RESPONSE_OK: epech_get_widgets_data (mch); case GTK_RESPONSE_CANCEL: gtk_widget_hide (priv->main); gtk_widget_destroy (priv->main); g_object_unref (priv->xml); break; case GTK_RESPONSE_HELP: e_display_help ( GTK_WINDOW (priv->main), priv->help_section); break; } g_signal_emit (G_OBJECT (func_data), signals[MCH_RESPONSE], 0, state); } static gboolean epech_dialog_run (CustomHeaderOptionsDialog *mch, GtkWidget *parent) { EmailCustomHeaderOptionsDialogPrivate *priv; GtkWidget *toplevel; gchar *filename; g_return_val_if_fail (mch != NULL || EMAIL_CUSTOM_HEADER_OPTIONS_IS_DIALOG (mch), FALSE); priv = mch->priv; epech_get_header_list (mch); filename = g_build_filename (EVOLUTION_GLADEDIR, "org-gnome-email-custom-header.glade", NULL); priv->xml = glade_xml_new (filename, NULL, NULL); g_free (filename); if (!priv->xml) { d (printf ("\n Could not load the Glade XML file\n")); } if (!epech_get_widgets(mch)) { g_object_unref (priv->xml); d (printf ("\n Could not get the Widgets\n")); } epech_setup_widgets (mch); toplevel = gtk_widget_get_toplevel (priv->main); if (parent) gtk_window_set_transient_for (GTK_WINDOW (toplevel),GTK_WINDOW (parent)); epech_fill_widgets_with_data (mch); g_signal_connect (GTK_DIALOG (priv->main), "response", G_CALLBACK(epech_header_options_cb), mch); gtk_widget_show (priv->main); return TRUE; } static void epech_get_header_list (CustomHeaderOptionsDialog *mch) { GConfClient *client; client = gconf_client_get_default (); g_return_if_fail (GCONF_IS_CLIENT (client)); gconf_client_add_dir (client, GCONF_KEY_CUSTOM_HEADER, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); epech_load_from_gconf (client, "/apps/evolution/eplugin/email_custom_header/customHeader", mch); return; } static void epech_load_from_gconf (GConfClient *client,const char *path,CustomHeaderOptionsDialog *mch) { EmailCustomHeaderOptionsDialogPrivate *priv; EmailCustomHeaderDetails temp_header_details= {-1, -1, NULL, NULL}; CustomSubHeader temp_header_value_details = {NULL}; GSList *header_list,*q; gchar *buffer; char *str_colon; gint index,pos; priv = mch->priv; priv->email_custom_header_details = g_array_new (TRUE, TRUE, sizeof (EmailCustomHeaderDetails)); header_list = gconf_client_get_list (client,path,GCONF_VALUE_STRING, NULL); for (q = header_list,pos = 0; q != NULL; q = q->next,pos++) { gchar **parse_header_list; memset(&temp_header_value_details,0,sizeof(CustomSubHeader)); temp_header_details.sub_header_type_value = g_array_new (TRUE, TRUE, sizeof (CustomSubHeader)); buffer = q->data; parse_header_list = g_strsplit_set (buffer, "=;,", -1); str_colon = g_strconcat (parse_header_list[0], ":", NULL); temp_header_details.header_type_value = g_string_new(""); if (temp_header_details.header_type_value) { g_string_assign(temp_header_details.header_type_value, str_colon); } g_free (str_colon); for (index = 0; parse_header_list[index+1] ; ++index) { temp_header_value_details.sub_header_string_value = g_string_new(""); if (temp_header_value_details.sub_header_string_value) { g_string_assign(temp_header_value_details.sub_header_string_value, parse_header_list[index+1]); } g_array_append_val(temp_header_details.sub_header_type_value, temp_header_value_details); } temp_header_details.number_of_subtype_header = index; g_array_append_val(priv->email_custom_header_details, temp_header_details); } temp_header_details.number_of_header = pos; } static void epech_setup_widgets (CustomHeaderOptionsDialog *mch) { EmailCustomHeaderOptionsDialogPrivate *priv; EmailCustomHeaderDetails *temp_header_ptr,*temp; CustomSubHeader *temp_header_value_ptr; HeaderValueComboBox sub_combo_box = {NULL}; HeaderValueComboBox *sub_combo_box_ptr; gint sub_index,row_combo,column_combo; gint header_section_id,sub_type_index,row,column,label_row; gint i; gchar *str; static const gchar *security_field = N_("Security:"); static struct _security_values { const gchar *value, *str; } security_values[] = { { "Personal", N_("Personal") } , { "Unclassified", N_("Unclassified") }, { "Protected", N_("Protected") }, { "InConfidence", N_("Confidential") }, { "Secret", N_("Secret") }, { "Topsecret", N_("Top secret") }, { NULL, NULL } }; priv = mch->priv; priv->combo_box_header_value = g_array_new (TRUE, FALSE, sizeof (HeaderValueComboBox)); for (header_section_id = 0,label_row = 0,row = 0,column = 1; header_section_id < priv->email_custom_header_details->len; header_section_id++,row++,column++) { /* To create an empty label widget. Text will be added dynamically. */ priv->header_type_name_label = gtk_label_new (""); temp_header_ptr = &g_array_index(priv->email_custom_header_details, EmailCustomHeaderDetails,header_section_id); str = (temp_header_ptr->header_type_value)->str; if (strcmp (str, security_field) == 0) { str = _(security_field); } gtk_label_set_markup (GTK_LABEL (priv->header_type_name_label), str); gtk_table_attach (GTK_TABLE (priv->header_table), priv->header_type_name_label, 0, 1, row, column, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment (GTK_MISC (priv->header_type_name_label), 0, 0.5); gtk_widget_show (priv->header_type_name_label); sub_combo_box.header_value_combo_box = gtk_combo_box_new_text (); g_array_append_val(priv->combo_box_header_value, sub_combo_box); } for (sub_index = 0,row_combo = 0,column_combo = 1; sub_index < priv->combo_box_header_value->len; sub_index++,row_combo++,column_combo++) { temp = &g_array_index(priv->email_custom_header_details, EmailCustomHeaderDetails,sub_index); sub_combo_box_ptr = &g_array_index(priv->combo_box_header_value, HeaderValueComboBox,sub_index); gtk_table_attach (GTK_TABLE (priv->header_table), sub_combo_box_ptr->header_value_combo_box, 1, 2, row_combo, column_combo, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0); for (sub_type_index = 0; sub_type_index < temp->number_of_subtype_header; sub_type_index++) { temp_header_value_ptr = &g_array_index(temp->sub_header_type_value, CustomSubHeader,sub_type_index); str = (temp_header_value_ptr->sub_header_string_value)->str; for (i = 0; security_values[i].value != NULL; i++) { if (strcmp (str, security_values[i].value) == 0) { str = _(security_values[i].str); break; } } gtk_combo_box_append_text (GTK_COMBO_BOX (sub_combo_box_ptr->header_value_combo_box), str); } gtk_combo_box_append_text (GTK_COMBO_BOX (sub_combo_box_ptr->header_value_combo_box), _("None")); gtk_widget_show (sub_combo_box_ptr->header_value_combo_box); } } static void epech_dialog_class_init (GObjectClass *object) { CustomHeaderOptionsDialogClass *klass; GObjectClass *object_class; klass = EMAIL_CUSTOM_HEADEROPTIONS_DIALOG_CLASS (object); parent_class = g_type_class_peek_parent (klass); object_class = G_OBJECT_CLASS (klass); object_class->finalize = epech_dialog_finalize; object_class->dispose = epech_dialog_dispose; signals[MCH_RESPONSE] = g_signal_new ("emch_response", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (CustomHeaderOptionsDialogClass, emch_response), NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); } static void epech_dialog_init (GObject *object) { CustomHeaderOptionsDialog *mch; EmailCustomHeaderOptionsDialogPrivate *priv; mch = EMAIL_CUSTOM_HEADEROPTIONS_DIALOG (object); priv = g_new0 (EmailCustomHeaderOptionsDialogPrivate, 1); mch->priv = priv; priv->xml = NULL; priv->main = NULL; priv->page = NULL; priv->header_table = NULL; } static void epech_dialog_finalize (GObject *object) { CustomHeaderOptionsDialog *mch = (CustomHeaderOptionsDialog *)object; EmailCustomHeaderOptionsDialogPrivate *priv; g_return_if_fail (EMAIL_CUSTOM_HEADER_OPTIONS_IS_DIALOG (mch)); priv = mch->priv; g_free (priv->help_section); if (mch->priv) { g_free (mch->priv); mch->priv = NULL; } if (parent_class->finalize) (* parent_class->finalize) (object); } static void epech_dialog_dispose (GObject *object) { CustomHeaderOptionsDialog *mch = (CustomHeaderOptionsDialog *) object; g_return_if_fail (EMAIL_CUSTOM_HEADER_OPTIONS_IS_DIALOG (mch)); if (parent_class->dispose) (* parent_class->dispose) (object); } static void epech_append_to_custom_header (CustomHeaderOptionsDialog *dialog, gint state, gpointer data) { EMsgComposer *composer; EmailCustomHeaderOptionsDialogPrivate *priv; EmailCustomHeaderDetails *temp_header_ptr; CustomSubHeader *temp_header_value_ptr; gint index, index_subtype,sub_type_index; composer = (EMsgComposer *)data; priv = dialog->priv; if (state == GTK_RESPONSE_OK) { for (index = 0,index_subtype = 0; index_subtype < priv->email_custom_header_details->len; index_subtype++) { temp_header_ptr = &g_array_index(priv->email_custom_header_details, EmailCustomHeaderDetails,index_subtype); for (sub_type_index = 0; sub_type_index < temp_header_ptr->number_of_subtype_header; sub_type_index++) { temp_header_value_ptr = &g_array_index(temp_header_ptr->sub_header_type_value, CustomSubHeader,sub_type_index); if (sub_type_index == g_array_index(priv->header_index_type, gint, index_subtype)){ e_msg_composer_modify_header (composer, (temp_header_ptr->header_type_value)->str, (temp_header_value_ptr->sub_header_string_value)->str); } } } } } static void epech_custom_header_options_commit (EMsgComposer *comp, gpointer user_data) { EMsgComposer *composer; EmailCustomHeaderWindow *new_email_custom_header_window = NULL; CustomHeaderOptionsDialog *current_dialog = NULL; composer = (EMsgComposer *) user_data; if (!user_data || !EMAIL_CUSTOM_HEADER_OPTIONS_IS_DIALOG (user_data)) return; new_email_custom_header_window = g_object_get_data ((GObject *) composer, "compowindow"); if (new_email_custom_header_window) { current_dialog = new_email_custom_header_window->epech_dialog; } if (current_dialog) { g_free (current_dialog); current_dialog = NULL; } if (new_email_custom_header_window) { g_free (new_email_custom_header_window); new_email_custom_header_window = NULL; } } static gint epech_check_existing_composer_window(gconstpointer compowindow, gconstpointer other_compowindow) { if ((compowindow) && (other_compowindow)){ if (((EmailCustomHeaderWindow *)compowindow)->epech_window == (GdkWindow *)other_compowindow) { return 0; } } return -1; } static void destroy_compo_data (gpointer data) { EmailCustomHeaderWindow *compo_data = (EmailCustomHeaderWindow *) data; if (!compo_data) return; g_free (compo_data); } static void action_email_custom_header_cb (GtkAction *action, EMsgComposer *composer) { GtkUIManager *manager; GtkWidget *menuitem; CustomHeaderOptionsDialog *dialog = NULL; EmailCustomHeaderWindow *new_email_custom_header_window = NULL; manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (composer)); menuitem = gtk_ui_manager_get_widget (manager, "/main-menu/insert-menu/insert-menu-top/Custom Header"); new_email_custom_header_window = g_object_get_data ((GObject *) composer, "compowindow"); if (epech_check_existing_composer_window(new_email_custom_header_window,menuitem->window) == 0) { dialog = new_email_custom_header_window->epech_dialog; } else { dialog = epech_dialog_new (); if (dialog) { EmailCustomHeaderWindow *new_email_custom_header_window; new_email_custom_header_window = g_new0(EmailCustomHeaderWindow, 1); new_email_custom_header_window->epech_window = menuitem->window; new_email_custom_header_window->epech_dialog = dialog; g_object_set_data_full ((GObject *) composer, "compowindow", new_email_custom_header_window, destroy_compo_data); } } epech_dialog_run (dialog, GTK_WIDGET (composer)); g_signal_connect (dialog, "emch_response", G_CALLBACK (epech_append_to_custom_header), GTK_WIDGET (composer)); g_signal_connect (GTK_WIDGET (composer), "destroy", G_CALLBACK (epech_custom_header_options_commit), composer); } static GtkActionEntry entries[] = { { "Custom Header", NULL, N_("_Custom Header"), NULL, NULL, G_CALLBACK (action_email_custom_header_cb) } }; gboolean e_plugin_ui_init (GtkUIManager *ui_manager, EMsgComposer *composer) { GtkhtmlEditor *editor; editor = GTKHTML_EDITOR (composer); /* 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); return TRUE; } static void commit_changes (ConfigData *cd) { GtkTreeModel *model = NULL; GSList *header_config_list = NULL; GtkTreeIter iter; gboolean valid; model = gtk_tree_view_get_model (GTK_TREE_VIEW (cd->treeview)); valid = gtk_tree_model_get_iter_first (model, &iter); while (valid) { gchar *keyword = NULL, *value = NULL; gtk_tree_model_get (model, &iter, HEADER_KEY_COLUMN, &keyword, -1); /* Check if the keyword is not empty */ gtk_tree_model_get (model, &iter, HEADER_VALUE_COLUMN, &value, -1); /* Check if the keyword is not empty */ if ((keyword) && (g_utf8_strlen(g_strstrip(keyword), -1) > 0)){ if ((value) && (g_utf8_strlen(g_strstrip(value), -1) > 0)){ keyword = g_strconcat (keyword, "=", value, NULL); } header_config_list = g_slist_append (header_config_list, g_strdup(keyword)); } g_free (keyword); valid = gtk_tree_model_iter_next (model, &iter); } gconf_client_set_list (cd->gconf, GCONF_KEY_CUSTOM_HEADER, GCONF_VALUE_STRING, header_config_list, NULL); g_slist_foreach (header_config_list, (GFunc) g_free, NULL); g_slist_free (header_config_list); } static void header_isempty (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, ConfigData *cd) { GtkTreeSelection *selection; char *keyword = NULL; char *value = NULL; gboolean valid; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cd->treeview)); /* move to the previous node */ valid = gtk_tree_path_prev (path); gtk_tree_model_get (model, iter, HEADER_KEY_COLUMN, &keyword, -1); if ((keyword) && !(g_utf8_strlen (g_strstrip (keyword), -1) > 0)) gtk_list_store_remove (cd->store, iter); /* Check if we have a valid row to select. If not, then select * the previous row */ if (gtk_list_store_iter_is_valid (GTK_LIST_STORE (model), iter)) { gtk_tree_selection_select_iter (selection, iter); } else { if (path && valid) { gtk_tree_model_get_iter (model, iter, path); gtk_tree_selection_select_iter (selection, iter); } } gtk_widget_grab_focus (cd->treeview); g_free (keyword); g_free (value); } static gboolean header_foreach_check_isempty (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, ConfigData *cd) { gboolean valid; valid = gtk_tree_model_get_iter_first (model, iter); while (valid && gtk_list_store_iter_is_valid (cd->store, iter)) { char *keyword = NULL; char *value = NULL; gtk_tree_model_get (model, iter, HEADER_KEY_COLUMN, &keyword, -1); /* Check if the keyword is not empty and then emit the row-changed signal (if we delete the row, then the iter gets corrupted) */ if ((keyword) && !(g_utf8_strlen (g_strstrip (keyword), -1) > 0)) gtk_tree_model_row_changed (model, path, iter); else { gtk_tree_model_get (model, iter, HEADER_VALUE_COLUMN, &value, -1); /* Check if the keyword is not empty and then emit the row-changed signal (if we delete the row, then the iter gets corrupted) */ if ((value) && !(g_utf8_strlen (g_strstrip (value), -1) > 0)) gtk_tree_model_row_changed (model, path, iter); } g_free (keyword); g_free (value); valid = gtk_tree_model_iter_next (model, iter); } return FALSE; } static void cell_edited_callback (GtkCellRendererText *cell, gchar *path_string, gchar *new_text, ConfigData *cd) { GtkTreeModel *model; GtkTreeIter iter; model = gtk_tree_view_get_model (GTK_TREE_VIEW (cd->treeview)); gtk_tree_model_get_iter_from_string (model, &iter, path_string); gtk_list_store_set (GTK_LIST_STORE (model), &iter, HEADER_KEY_COLUMN, new_text, -1); commit_changes (cd); } static void cell_value_edited_callback (GtkCellRendererText *cell, gchar *path_string, gchar *new_text, ConfigData *cd) { GtkTreeModel *model; GtkTreeIter iter; model = gtk_tree_view_get_model (GTK_TREE_VIEW (cd->treeview)); gtk_tree_model_get_iter_from_string (model, &iter, path_string); gtk_list_store_set (GTK_LIST_STORE (model), &iter, HEADER_VALUE_COLUMN, new_text, -1); commit_changes (cd); } static void header_add_clicked (GtkButton *button, ConfigData *cd) { GtkTreeModel *model; GtkTreeIter iter; gchar *new_header = NULL; GtkTreeViewColumn *focus_col; GtkTreePath *path; model = gtk_tree_view_get_model (GTK_TREE_VIEW (cd->treeview)); gtk_tree_model_foreach (model, (GtkTreeModelForeachFunc) header_foreach_check_isempty, cd); /* Disconnect from signal so that we can create an empty row */ g_signal_handlers_disconnect_matched(G_OBJECT(model), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, header_isempty, cd); new_header = g_strdup (""); gtk_list_store_append (GTK_LIST_STORE (model), &iter); gtk_list_store_set (GTK_LIST_STORE (model), &iter, HEADER_KEY_COLUMN, new_header, -1); gtk_list_store_set (GTK_LIST_STORE (model), &iter, HEADER_VALUE_COLUMN, new_header, -1); focus_col = gtk_tree_view_get_column (GTK_TREE_VIEW (cd->treeview), HEADER_KEY_COLUMN); path = gtk_tree_model_get_path (model, &iter); if (path) { gtk_tree_view_set_cursor (GTK_TREE_VIEW (cd->treeview), path, focus_col, TRUE); gtk_tree_view_row_activated(GTK_TREE_VIEW(cd->treeview), path, focus_col); gtk_tree_path_free (path); } /* We have done our job, connect back to the signal */ g_signal_connect(G_OBJECT(model), "row-changed", G_CALLBACK(header_isempty), cd); } static void header_remove_clicked (GtkButton *button, ConfigData *cd) { GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path; gboolean valid; gint len; valid = FALSE; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cd->treeview)); if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; /* Get the path and move to the previous node :) */ path = gtk_tree_model_get_path (model, &iter); if (path) valid = gtk_tree_path_prev(path); gtk_list_store_remove (GTK_LIST_STORE (model), &iter); len = gtk_tree_model_iter_n_children (model, NULL); if (len > 0) { if (gtk_list_store_iter_is_valid (GTK_LIST_STORE(model), &iter)) { gtk_tree_selection_select_iter (selection, &iter); } else { if (path && valid) { gtk_tree_model_get_iter(model, &iter, path); gtk_tree_selection_select_iter (selection, &iter); } } } else { gtk_widget_set_sensitive (cd->header_edit, FALSE); gtk_widget_set_sensitive (cd->header_remove, FALSE); } gtk_widget_grab_focus(cd->treeview); gtk_tree_path_free (path); commit_changes (cd); } static void header_edit_clicked (GtkButton *button, ConfigData *cd) { GtkTreeSelection *selection; GtkTreeModel *model; GtkTreePath *path; GtkTreeIter iter; GtkTreeViewColumn *focus_col; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cd->treeview)); if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; focus_col = gtk_tree_view_get_column (GTK_TREE_VIEW (cd->treeview), HEADER_KEY_COLUMN); path = gtk_tree_model_get_path (model, &iter); if (path) { gtk_tree_view_set_cursor (GTK_TREE_VIEW (cd->treeview), path, focus_col, TRUE); gtk_tree_path_free (path); } } static void selection_changed (GtkTreeSelection *selection, ConfigData *cd) { GtkTreeModel *model; GtkTreeIter iter; if (gtk_tree_selection_get_selected (selection, &model, &iter)) { gtk_widget_set_sensitive (cd->header_edit, TRUE); gtk_widget_set_sensitive (cd->header_remove, TRUE); } else { gtk_widget_set_sensitive (cd->header_edit, FALSE); gtk_widget_set_sensitive (cd->header_remove, FALSE); } } static void destroy_cd_data (gpointer data) { ConfigData *cd = (ConfigData *) data; if (!cd) return; g_object_unref (cd->xml); g_object_unref (cd->gconf); g_free (cd); } GtkWidget * e_plugin_lib_get_configure_widget (EPlugin *epl) { GtkCellRenderer *renderer; GtkTreeSelection *selection; GtkTreeIter iter; GtkWidget *hbox; GSList *list; GSList *header_list = NULL; GtkTreeModel *model; gint index; gchar *buffer; char *str_colon = NULL, *str1_colon = NULL; GtkTreeViewColumn *col; int col_pos; GConfClient *client = gconf_client_get_default(); ConfigData *cd = g_new0 (ConfigData, 1); char *gladefile; gladefile = g_build_filename (EVOLUTION_GLADEDIR, "email-custom-header.glade", NULL); cd->xml = glade_xml_new (gladefile, "ech_configuration_box", NULL); g_free (gladefile); cd->gconf = gconf_client_get_default (); cd->treeview = glade_xml_get_widget (cd->xml, "header_treeview"); cd->store = gtk_list_store_new (HEADER_N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING); gtk_tree_view_set_model (GTK_TREE_VIEW (cd->treeview), GTK_TREE_MODEL (cd->store)); renderer = gtk_cell_renderer_text_new (); col_pos = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (cd->treeview), -1, _("Key"), renderer, "text", HEADER_KEY_COLUMN, NULL); col = gtk_tree_view_get_column (GTK_TREE_VIEW (cd->treeview), col_pos -1); gtk_tree_view_column_set_resizable (col, TRUE); gtk_tree_view_column_set_reorderable(col, TRUE); g_object_set (col, "min-width", 50, NULL); g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL); g_signal_connect(renderer, "edited", (GCallback) cell_edited_callback, cd); renderer = gtk_cell_renderer_text_new (); col_pos = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (cd->treeview), -1, _("Values"), renderer, "text", HEADER_VALUE_COLUMN, NULL); col = gtk_tree_view_get_column (GTK_TREE_VIEW (cd->treeview), col_pos -1); gtk_tree_view_column_set_resizable (col, TRUE); gtk_tree_view_column_set_reorderable(col, TRUE); g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL); g_signal_connect(renderer, "edited", (GCallback) cell_value_edited_callback, cd); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cd->treeview)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (selection_changed), cd); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (cd->treeview), TRUE); cd->header_add = glade_xml_get_widget (cd->xml, "header_add"); g_signal_connect (G_OBJECT (cd->header_add), "clicked", G_CALLBACK (header_add_clicked), cd); cd->header_remove = glade_xml_get_widget (cd->xml, "header_remove"); g_signal_connect (G_OBJECT (cd->header_remove), "clicked", G_CALLBACK (header_remove_clicked), cd); gtk_widget_set_sensitive (cd->header_remove, FALSE); cd->header_edit = glade_xml_get_widget (cd->xml, "header_edit"); g_signal_connect (G_OBJECT (cd->header_edit), "clicked", G_CALLBACK (header_edit_clicked), cd); gtk_widget_set_sensitive (cd->header_edit, FALSE); model = gtk_tree_view_get_model (GTK_TREE_VIEW (cd->treeview)); g_signal_connect(G_OBJECT(model), "row-changed", G_CALLBACK(header_isempty), cd); /* Populate tree view with values from gconf */ header_list = gconf_client_get_list (client,GCONF_KEY_CUSTOM_HEADER,GCONF_VALUE_STRING, NULL); for (list = header_list; list; list = g_slist_next (list)) { gchar **parse_header_list; buffer = list->data; gtk_list_store_append (cd->store, &iter); parse_header_list = g_strsplit_set (buffer, "=,", -1); str_colon = g_strconcat (parse_header_list[0], "", NULL); gtk_list_store_set (cd->store, &iter, HEADER_KEY_COLUMN, str_colon, -1); for (index = 0; parse_header_list[index+1] ; ++index) { str1_colon = g_strconcat (parse_header_list[index+1], "", NULL); gtk_list_store_set (cd->store, &iter, HEADER_VALUE_COLUMN, str1_colon, -1); } } g_free (str_colon); g_free (str1_colon); if (header_list) { g_slist_foreach (header_list, (GFunc) g_free, NULL); g_slist_free (header_list); } /* Add the list here */ hbox = gtk_vbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), glade_xml_get_widget (cd->xml, "ech_configuration_box"), TRUE, TRUE, 0); /* to let free data properly on destroy of configuration widget */ g_object_set_data_full (G_OBJECT (hbox), "mycd-data", cd, destroy_cd_data); return hbox; } /* Configuration in Mail Prefs Page goes here */ GtkWidget * org_gnome_email_custom_header_config_option (struct _EPlugin *epl, struct _EConfigHookItemFactoryData *data) { /* This function and the hook needs to be removed, once the configure code is thoroughly tested */ return NULL; }