diff options
Diffstat (limited to 'mail')
-rw-r--r-- | mail/ChangeLog | 25 | ||||
-rw-r--r-- | mail/em-folder-browser.c | 80 | ||||
-rw-r--r-- | mail/em-folder-view.c | 77 | ||||
-rw-r--r-- | mail/em-mailer-prefs.c | 308 | ||||
-rw-r--r-- | mail/em-mailer-prefs.h | 10 | ||||
-rw-r--r-- | mail/filtertypes.xml | 4 | ||||
-rw-r--r-- | mail/mail-config.c | 410 | ||||
-rw-r--r-- | mail/mail-config.glade | 375 | ||||
-rw-r--r-- | mail/mail-config.h | 17 | ||||
-rw-r--r-- | mail/message-list.c | 93 | ||||
-rw-r--r-- | mail/message-list.etspec | 1 | ||||
-rw-r--r-- | mail/message-list.h | 1 | ||||
-rw-r--r-- | mail/vfoldertypes.xml | 4 |
13 files changed, 1020 insertions, 385 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index dbbd71dce4..fdf87579b3 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,28 @@ +2007-12-14 Milan Crha <mcrha@redhat.com> + + ** Fix for bug #211353 + + * message-list.etspec: + * message-list.h: + * message-list.c: Added new column to show labels. + * filtertypes.xml: + * vfoldertypes.xml: + Code for label filters/search folders has been changed. + * mail-config.glade: + * em-folder-view.c: (emfv_set_label), (emfv_unset_label), + (emfv_popup_label_clear), (emfv_popup_label_set), + (emfv_popup_labels_get_state_for_tag), (emfv_popup): + Labels popup submenu is now shown with checkboxes so one can set + more than one label to the message and unset only one label from + message. There has been added new function, because of this. + * mail-config.h: + * mail-config.c: New "interface" functions to work with labels. + * em-mailer-prefs.h: + * em-mailer-prefs.c: Editing labels in tree. + * em-folder-browser.c: + Labels in show menu reflect changes in preferences. + + 2007-12-17 Srinivasa Ragavan <sragavan@novell.com> ** Fix for bug #430369 diff --git a/mail/em-folder-browser.c b/mail/em-folder-browser.c index e3e35ab3c0..de3067babf 100644 --- a/mail/em-folder-browser.c +++ b/mail/em-folder-browser.c @@ -126,6 +126,8 @@ struct _EMFolderBrowserPrivate { gboolean scope_restricted; EMMenu *menu; /* toplevel menu manager */ + + guint labels_change_notify_id; /* mail_config's notify id */ }; typedef struct EMFBSearchBarItem { @@ -202,6 +204,9 @@ enum { VIEW_CUSTOMIZE }; +/* label IDs are set above this number */ +#define VIEW_ITEMS_MASK 63 + /* Options for View */ static EMFBSearchBarItem emfb_view_items[] = { {{ N_("All Messages"), VIEW_ALL_MESSAGES, 0 }, NULL}, @@ -304,7 +309,7 @@ generate_viewoption_menu (GtkWidget *emfv) } /* Add the labels */ - for (l = mail_config_get_labels(); l; l = l->next) { + for (l = mail_config_get_labels(), i = 0; l; l = l->next, i++) { MailConfigLabel *label = l->data; if (label->name && *(label->name)) { char *str; @@ -328,10 +333,11 @@ generate_viewoption_menu (GtkWidget *emfv) g_free (str); gtk_image_menu_item_set_image ((GtkImageMenuItem *)menu_item, image); g_object_set_data (G_OBJECT (menu_item), "EsbItemId", - GINT_TO_POINTER (VIEW_LABEL)); + GINT_TO_POINTER (VIEW_LABEL + (VIEW_ITEMS_MASK + 1) * i)); + /* label->tag starts with "$Label" so it's safe to do */ g_object_set_data (G_OBJECT (menu_item), "LabelTag", - g_strdup(label->tag)); + g_strdup (label->tag + 6)); } gtk_widget_show (menu_item); @@ -396,9 +402,16 @@ emfb_realize (GtkWidget *widget) { GtkWidget *menu; EMFolderBrowser *emfb = (EMFolderBrowser *)widget; + int id; - menu = generate_viewoption_menu(widget); - e_search_bar_set_viewoption_menu ((ESearchBar *)emfb->search, menu); + menu = generate_viewoption_menu (widget); + id = e_search_bar_get_viewitem_id (E_SEARCH_BAR (emfb->search)); + + e_search_bar_set_viewoption_menu (E_SEARCH_BAR (emfb->search), menu); + + /* restore last selected ID, if any */ + if (id != -1) + e_search_bar_set_viewitem_id (E_SEARCH_BAR (emfb->search), id); } static void @@ -420,6 +433,16 @@ html_scroll (GtkHTML *html, message_list_select(((EMFolderView *) emfb)->list, MESSAGE_LIST_SELECT_NEXT, 0, CAMEL_MESSAGE_SEEN); } } + +static void +gconf_labels_changed (GConfClient *client, guint cnxn_id, + GConfEntry *entry, gpointer user_data) +{ + /* regenerate menu option whenever something changed in labels */ + if (user_data) + emfb_realize (user_data); +} + static void emfb_init(GObject *o) { @@ -456,6 +479,7 @@ emfb_init(GObject *o) const char *systemrules = g_object_get_data (G_OBJECT (search_context), "system"); const char *userrules = g_object_get_data (G_OBJECT (search_context), "user"); EFilterBar *efb; + GConfClient *gconf; emfb->search = e_filter_bar_new(search_context, systemrules, userrules, emfb_search_config_search, emfb); efb = (EFilterBar *)emfb->search; @@ -473,6 +497,9 @@ emfb_init(GObject *o) g_signal_connect(emfb->search, "search_cleared", G_CALLBACK(emfb_search_search_cleared), NULL); gtk_box_pack_start((GtkBox *)emfb, (GtkWidget *)emfb->search, FALSE, TRUE, 0); + + gconf = mail_config_get_gconf_client (); + emfb->priv->labels_change_notify_id = gconf_client_notify_add (gconf, "/apps/evolution/mail/labels", gconf_labels_changed, emfb, NULL, NULL); } emfb->priv->show_wide = gconf_client_get_bool(mail_config_get_gconf_client(), "/apps/evolution/mail/display/show_wide", NULL); @@ -541,6 +568,15 @@ emfb_destroy(GtkObject *o) if (emfb->view.folder && emfb->priv->folder_changed_id) camel_object_remove_event(emfb->view.folder, emfb->priv->folder_changed_id); + if (emfb->priv->labels_change_notify_id) { + GConfClient *gconf = mail_config_get_gconf_client (); + + if (gconf) + gconf_client_notify_remove (gconf, emfb->priv->labels_change_notify_id); + + emfb->priv->labels_change_notify_id = 0; + } + ((GtkObjectClass *)emfb_parent)->destroy(o); } @@ -796,12 +832,13 @@ get_view_query (ESearchBar *esb, CamelFolder *folder, const char *folder_uri) gint id; GtkWidget *menu_item; char *tag; + gboolean duplicate = TRUE; /* Get the current selected view */ id = e_search_bar_get_viewitem_id (esb); menu_item = e_search_bar_get_selected_viewitem (esb); - switch (id) { + switch (id & VIEW_ITEMS_MASK) { case VIEW_ALL_MESSAGES: view_sexp = " "; break; @@ -830,15 +867,27 @@ get_view_query (ESearchBar *esb, CamelFolder *folder, const char *folder_uri) case VIEW_NOT_JUNK: view_sexp = "(match-all (not (system-flag \"junk\")))"; break; - case VIEW_NO_LABEL: - /* FIXME : cannot hard code this query */ - view_sexp = "(and (match-all (not (= (user-tag \"label\") \"important\")))" - "(match-all (not (= (user-tag \"label\") \"work\"))) (match-all (not (= (user-tag \"label\") \"personal\")))" - "(match-all (not (= (user-tag \"label\") \"todo\"))) (match-all (not (= (user-tag \"label\") \"later\"))) ))"; - break; + case VIEW_NO_LABEL: { + GSList *l; + GString *s = g_string_new ("(and"); + + for (l = mail_config_get_labels (); l; l = l->next) { + MailConfigLabel *label = (MailConfigLabel *)l->data; + + /* tag is always with "$Label" prefix */ + if (label && label->tag) + g_string_append_printf (s, " (match-all (not (or (= (user-tag \"label\") \"%s\") (user-flag \"$Label%s\"))))", label->tag + 6, label->tag + 6); + } + + g_string_append (s, ")"); + + duplicate = FALSE; + view_sexp = g_string_free (s, FALSE); + } break; case VIEW_LABEL: tag = (char *)g_object_get_data (G_OBJECT (menu_item), "LabelTag"); - view_sexp = g_strdup_printf ("(match-all (= (user-tag \"label\") \"%s\"))",tag); + view_sexp = g_strdup_printf ("(match-all (or (= (user-tag \"label\") \"%s\") (user-flag \"$Label%s\" )))", tag, tag); + duplicate = FALSE; break; case VIEW_MESSAGES_MARKED_AS_IMPORTANT: view_sexp = "(match-all (system-flag \"Flagged\"))"; @@ -850,6 +899,10 @@ get_view_query (ESearchBar *esb, CamelFolder *folder, const char *folder_uri) view_sexp = " "; break; } + + if (duplicate) + view_sexp = g_strdup (view_sexp); + return view_sexp; } @@ -1147,6 +1200,7 @@ emfb_search_search_activated(ESearchBar *esb, EMFolderBrowser *emfb) message_list_set_search(emfb->view.list, search_word); g_free (search_word); + g_free (view_sexp); camel_exception_free (ex); } diff --git a/mail/em-folder-view.c b/mail/em-folder-view.c index 61942175ae..2f77d96919 100644 --- a/mail/em-folder-view.c +++ b/mail/em-folder-view.c @@ -1200,22 +1200,42 @@ emfv_popup_copy(EPopup *ep, EPopupItem *pitem, void *data) } static void -emfv_set_label(EMFolderView *emfv, const char *label) +emfv_set_label (EMFolderView *emfv, const char *label) { - GPtrArray *uids = message_list_get_selected(emfv->list); + GPtrArray *uids = message_list_get_selected (emfv->list); int i; - for (i=0;i<uids->len;i++) - camel_folder_set_message_user_tag(emfv->folder, uids->pdata[i], "label", label); + for (i = 0; i < uids->len; i++) + camel_folder_set_message_user_flag (emfv->folder, uids->pdata[i], label, TRUE); - message_list_free_uids(emfv->list, uids); + message_list_free_uids (emfv->list, uids); +} + +static void +emfv_unset_label (EMFolderView *emfv, const char *label) +{ + GPtrArray *uids = message_list_get_selected (emfv->list); + int i; + + for (i = 0; i < uids->len; i++) { + camel_folder_set_message_user_flag (emfv->folder, uids->pdata[i], label, FALSE); + camel_folder_set_message_user_tag (emfv->folder, uids->pdata[i], "label", NULL); + } + + message_list_free_uids (emfv->list, uids); } static void emfv_popup_label_clear(EPopup *ep, EPopupItem *pitem, void *data) { EMFolderView *emfv = data; - emfv_set_label(emfv, NULL); + GSList *l; + MailConfigLabel *label; + + for (l = mail_config_get_labels(); l; l = l->next) { + label = l->data; + emfv_unset_label(emfv, label->tag); + } } static void @@ -1223,7 +1243,10 @@ emfv_popup_label_set(EPopup *ep, EPopupItem *pitem, void *data) { EMFolderView *emfv = data; - emfv_set_label(emfv, pitem->user_data); + if (pitem->type & E_POPUP_ACTIVE) + emfv_set_label (emfv, pitem->user_data); + else + emfv_unset_label (emfv, pitem->user_data); } static void @@ -1341,6 +1364,38 @@ static EPopupItem emfv_popup_items[] = { emfv_popup_filter_mlist, NULL, NULL, EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST|EM_FOLDER_VIEW_SELECT_LISTONLY }, }; +static enum _e_popup_t +emfv_popup_labels_get_state_for_tag (EMFolderView *emfv, GPtrArray *uids, const char *label_tag) +{ + enum _e_popup_t state = 0; + int i; + gboolean exists = FALSE, not_exists = FALSE; + + g_return_val_if_fail (emfv != 0, state); + g_return_val_if_fail (label_tag != NULL, state); + + for (i = 0; i < uids->len && (!exists || !not_exists); i++) { + if (camel_folder_get_message_user_flag (emfv->folder, uids->pdata[i], label_tag)) + exists = TRUE; + else { + const char *label = mail_config_get_new_label_tag (camel_folder_get_message_user_tag (emfv->folder, uids->pdata[i], "label")); + + /* backward compatibility... */ + if (label && !strcmp (label, label_tag)) + exists = TRUE; + else + not_exists = TRUE; + } + } + + if (exists && not_exists) + state = E_POPUP_INCONSISTENT; + else if (exists) + state = E_POPUP_ACTIVE; + + return state; +} + static void emfv_popup_labels_free(EPopup *ep, GSList *l, void *data) { @@ -1388,6 +1443,8 @@ emfv_popup(EMFolderView *emfv, GdkEvent *event, int on_display) i = 1; if (!on_display) { + GPtrArray *uids = message_list_get_selected (emfv->list); + for (l = mail_config_get_labels(); l; l = l->next) { EPopupItem *item; MailConfigLabel *label = l->data; @@ -1396,7 +1453,7 @@ emfv_popup(EMFolderView *emfv, GdkEvent *event, int on_display) GdkGC *gc; item = g_malloc0(sizeof(*item)); - item->type = E_POPUP_IMAGE; + item->type = E_POPUP_TOGGLE | emfv_popup_labels_get_state_for_tag (emfv, uids, label->tag); item->path = g_strdup_printf("60.label.00/00.label.%02d", i++); item->label = label->name; item->activate = emfv_popup_label_set; @@ -1404,7 +1461,7 @@ emfv_popup(EMFolderView *emfv, GdkEvent *event, int on_display) item->visible = EM_POPUP_SELECT_MANY|EM_FOLDER_VIEW_SELECT_LISTONLY; - gdk_color_parse(label->colour, &colour); + gdk_color_parse (label->colour, &colour); gdk_colormap_alloc_color(gdk_colormap_get_system(), &colour, FALSE, TRUE); pixmap = gdk_pixmap_new(((GtkWidget *)emfv)->window, 16, 16, -1); @@ -1418,6 +1475,8 @@ emfv_popup(EMFolderView *emfv, GdkEvent *event, int on_display) label_list = g_slist_prepend(label_list, item); } + + message_list_free_uids (emfv->list, uids); } e_popup_add_items((EPopup *)emp, label_list, NULL, emfv_popup_labels_free, emfv); diff --git a/mail/em-mailer-prefs.c b/mail/em-mailer-prefs.c index b8c3d7fb59..991c684d10 100644 --- a/mail/em-mailer-prefs.c +++ b/mail/em-mailer-prefs.c @@ -54,6 +54,8 @@ #include <gtk/gtkoptionmenu.h> #include <gtk/gtkmenuitem.h> +#include "libedataserverui/e-cell-renderer-color.h" + #include "e-util/e-util-private.h" #include "mail-config.h" @@ -182,57 +184,254 @@ citation_color_set (GtkColorButton *color_button, EMMailerPrefs *prefs) spec, NULL); } +enum { + LABEL_LIST_COLUMN_COLOR, + LABEL_LIST_COLUMN_TAG, + LABEL_LIST_COLUMN_NAME +}; + static void -labels_changed (EMMailerPrefs *prefs) +label_name_edited_cb (GtkCellRendererText *cell, gchar *path_string, gchar *new_text, EMMailerPrefs *prefs) { - GSList *l, *n, *list = NULL; - const char *cstring; - char *string; - int i; + GtkTreeModel *model; + GtkTreeIter iter; - for (i = 4; i >= 0; i--) { - GdkColor color; + model = gtk_tree_view_get_model (GTK_TREE_VIEW (prefs->label_tree)); + + gtk_tree_model_get_iter_from_string (model, &iter, path_string); + + g_strstrip (new_text); + + /* allow only nonempty texts and always strip spaces there */ + if (new_text && *new_text) { + gchar *tag = NULL; + + gtk_tree_model_get (model, &iter, LABEL_LIST_COLUMN_TAG, &tag, -1); + + gtk_list_store_set (GTK_LIST_STORE (model), &iter, LABEL_LIST_COLUMN_NAME, new_text, -1); + mail_config_set_label_name (tag, new_text); - cstring = gtk_entry_get_text (prefs->labels[i].name); - gtk_color_button_get_color (prefs->labels[i].color, &color); - string = g_strdup_printf ("%s:#%04x%04x%04x", cstring, - color.red, color.green, color.blue); - list = g_slist_prepend (list, string); + g_free (tag); } +} + +static void +label_sensitive_buttons (EMMailerPrefs *prefs) +{ + gboolean can_remove = FALSE, have_selected = FALSE, locked; + + g_return_if_fail (prefs); + + /* it's not sensitive if it's locked for updates */ + locked = !GTK_WIDGET_IS_SENSITIVE (prefs->label_tree); - gconf_client_set_list (prefs->gconf, "/apps/evolution/mail/labels", GCONF_VALUE_STRING, list, NULL); + if (!locked) { + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; - l = list; - while (l != NULL) { - n = l->next; - g_free (l->data); - g_slist_free_1 (l); - l = n; + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (prefs->label_tree)); + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + gchar *tag = NULL; + + gtk_tree_model_get (model, &iter, LABEL_LIST_COLUMN_TAG, &tag, -1); + + can_remove = tag && !mail_config_is_system_label (tag); + have_selected = TRUE; + + g_free (tag); + } } + + gtk_widget_set_sensitive (prefs->label_remove, !locked && can_remove); + gtk_widget_set_sensitive (prefs->label_color, !locked && have_selected); } static void -label_color_set (GtkWidget *widget, EMMailerPrefs *prefs) +label_tree_cursor_changed (GtkWidget *widget, gpointer user_data) { - labels_changed (prefs); + label_sensitive_buttons (user_data); +} + +static GtkListStore * +init_label_tree (GtkWidget *label_tree, EMMailerPrefs *prefs, gboolean locked) +{ + GtkListStore *store; + GSList *labels; + GtkCellRenderer *renderer; + gint col; + + g_return_val_if_fail (label_tree != NULL, NULL); + g_return_val_if_fail (prefs != NULL, NULL); + + store = gtk_list_store_new (3, GDK_TYPE_COLOR, G_TYPE_STRING, G_TYPE_STRING); + gtk_tree_view_set_model (GTK_TREE_VIEW (label_tree), GTK_TREE_MODEL (store)); + + renderer = e_cell_renderer_color_new (); + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (label_tree), -1, _("Color"), renderer, "color", LABEL_LIST_COLUMN_COLOR, NULL); + + renderer = gtk_cell_renderer_text_new (); + col = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (label_tree), -1, _("Tag"), renderer, "text", LABEL_LIST_COLUMN_TAG, NULL); + g_object_set (G_OBJECT (renderer), "editable", FALSE, NULL); + gtk_tree_view_column_set_visible (gtk_tree_view_get_column (GTK_TREE_VIEW (label_tree), col - 1), FALSE); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (label_tree), -1, _("Name"), renderer, "text", LABEL_LIST_COLUMN_NAME, NULL); + g_object_set (G_OBJECT (renderer), "editable", !locked, NULL); + + if (!locked) { + g_signal_connect (renderer, "edited", G_CALLBACK (label_name_edited_cb), prefs); + g_signal_connect (label_tree, "cursor-changed", G_CALLBACK (label_tree_cursor_changed), prefs); + } + + for (labels = mail_config_get_labels (); labels; labels = labels->next) { + GdkColor color; + GtkTreeIter iter; + MailConfigLabel *label = labels->data; + + if (label->colour) + gdk_color_parse (label->colour, &color); + + gtk_list_store_append (store, &iter); + gtk_list_store_set ( + store, &iter, + LABEL_LIST_COLUMN_COLOR, label->colour ? &color : NULL, + LABEL_LIST_COLUMN_NAME, label->name, + LABEL_LIST_COLUMN_TAG, label->tag, + -1); + } + + label_sensitive_buttons (prefs); + + return store; } static void -label_entry_changed (GtkEntry *entry, EMMailerPrefs *prefs) +label_add_cb (GtkWidget *widget, gpointer user_data) { - labels_changed (prefs); + EMMailerPrefs *prefs = user_data; + GtkTreeModel *model; + GtkTreeIter iter; + char *tag, *name; + int tagid; + GtkTreePath *path; + GdkColor gray; + + g_return_if_fail (prefs != NULL); + + tag = mail_config_get_next_label_tag (&tagid); + + if (!tag) + return; + + memset (&gray, 0xCD, sizeof (GdkColor)); + name = g_strdup_printf ("%s %d", _("Label"), tagid); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (prefs->label_tree)); + + if (mail_config_add_label (tag, name, &gray)) { + gtk_list_store_append (GTK_LIST_STORE (model), &iter); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + LABEL_LIST_COLUMN_COLOR, &gray, + LABEL_LIST_COLUMN_NAME, name, + LABEL_LIST_COLUMN_TAG, tag, + -1); + + path = gtk_tree_model_get_path (model, &iter); + if (path) { + GtkTreeViewColumn *focus_col = gtk_tree_view_get_column (GTK_TREE_VIEW (prefs->label_tree), LABEL_LIST_COLUMN_NAME); + + gtk_tree_view_set_cursor (GTK_TREE_VIEW (prefs->label_tree), path, focus_col, TRUE); + gtk_tree_view_row_activated (GTK_TREE_VIEW (prefs->label_tree), path, focus_col); + gtk_tree_path_free (path); + } + } + + g_free (tag); + g_free (name); } static void -restore_labels_clicked (GtkWidget *widget, gpointer user_data) +label_remove_cb (GtkWidget *widget, gpointer user_data) { - EMMailerPrefs *prefs = (EMMailerPrefs *) user_data; - int i; + EMMailerPrefs *prefs = user_data; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + + g_return_if_fail (prefs != NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (prefs->label_tree)); + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + gchar *tag = NULL; + + gtk_tree_model_get (model, &iter, LABEL_LIST_COLUMN_TAG, &tag, -1); + + if (tag && !mail_config_is_system_label (tag)) { + gint children; + + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + mail_config_remove_label (tag); + + children = gtk_tree_model_iter_n_children (model, NULL); + if (children > 0) { + GtkTreePath *path; + + if (!gtk_list_store_iter_is_valid (GTK_LIST_STORE (model), &iter)) + gtk_tree_model_iter_nth_child (model, &iter, NULL, children - 1); + + path = gtk_tree_model_get_path (model, &iter); + if (path) { + GtkTreeViewColumn *focus_col = gtk_tree_view_get_column (GTK_TREE_VIEW (prefs->label_tree), LABEL_LIST_COLUMN_NAME); + + gtk_tree_view_set_cursor (GTK_TREE_VIEW (prefs->label_tree), path, focus_col, FALSE); + gtk_tree_view_row_activated (GTK_TREE_VIEW (prefs->label_tree), path, focus_col); + gtk_tree_path_free (path); + } + } + } + + g_free (tag); + } +} - for (i = 0; i < 5; i++) { - gtk_entry_set_text (prefs->labels[i].name, _(label_defaults[i].name)); - color_button_set_color (prefs->labels[i].color, label_defaults[i].colour); - atk_object_set_name(gtk_widget_get_accessible((GtkWidget *)prefs->labels[i].color), _(label_defaults[i].name)); +static void +label_color_cb (GtkWidget *widget, gpointer user_data) +{ + EMMailerPrefs *prefs = user_data; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + + g_return_if_fail (prefs != NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (prefs->label_tree)); + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + GtkWidget *dialog; + GdkColor *color = NULL, color2; + + gtk_tree_model_get (model, &iter, LABEL_LIST_COLUMN_COLOR, &color, -1); + + dialog = gtk_color_selection_dialog_new (_("Select color for label...")); + gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dialog)->colorsel), color); + + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { + gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dialog)->colorsel), &color2); + + if (!color || memcmp (color, &color2, sizeof(GdkColor)) != 0) { + gchar *tag = NULL; + + gtk_tree_model_get (model, &iter, LABEL_LIST_COLUMN_TAG, &tag, -1); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, LABEL_LIST_COLUMN_COLOR, &color2, -1); + + mail_config_set_label_color (tag, &color2); + + g_free (tag); + } + } + + gtk_widget_destroy (dialog); + if (color) + gdk_color_free (color); } } @@ -842,7 +1041,7 @@ create_combo_text_widget (void) { static void em_mailer_prefs_construct (EMMailerPrefs *prefs) { - GSList *list, *header_config_list, *header_add_list, *p; + GSList *header_config_list, *header_add_list, *p; GHashTable *default_header_hash; GtkWidget *toplevel; GtkTreeSelection *selection; @@ -1005,39 +1204,24 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs) /* Labels... */ locked = !gconf_client_key_is_writable (prefs->gconf, "/apps/evolution/mail/labels", NULL); - i = 0; - list = mail_config_get_labels (); - while (list != NULL && i < 5) { - MailConfigLabel *label; - char *widget_name; - label = list->data; - - widget_name = g_strdup_printf ("txtLabel%d", i); - prefs->labels[i].name = GTK_ENTRY (glade_xml_get_widget (gui, widget_name)); - gtk_widget_set_sensitive ((GtkWidget *) prefs->labels[i].name, !locked); - g_free (widget_name); - - widget_name = g_strdup_printf ("colorLabel%d", i); - prefs->labels[i].color = GTK_COLOR_BUTTON (glade_xml_get_widget (gui, widget_name)); - gtk_widget_set_sensitive ((GtkWidget *) prefs->labels[i].color, !locked); - g_free (widget_name); - - gtk_entry_set_text (prefs->labels[i].name, label->name); - g_signal_connect (prefs->labels[i].name, "changed", G_CALLBACK (label_entry_changed), prefs); - - color_button_set_color (prefs->labels[i].color, label->colour); - g_signal_connect (prefs->labels[i].color, "color-set", G_CALLBACK (label_color_set), prefs); - - atk_object_set_name(gtk_widget_get_accessible((GtkWidget *)prefs->labels[i].color), label->name); - - i++; - list = list->next; + prefs->label_add = glade_xml_get_widget (gui, "labelAdd"); + prefs->label_remove = glade_xml_get_widget (gui, "labelRemove"); + prefs->label_color = glade_xml_get_widget (gui, "labelColor"); + prefs->label_tree = glade_xml_get_widget (gui, "labelTree"); + + gtk_widget_set_sensitive (prefs->label_add, !locked); + gtk_widget_set_sensitive (prefs->label_remove, !locked); + gtk_widget_set_sensitive (prefs->label_color, !locked); + gtk_widget_set_sensitive (prefs->label_tree, !locked); + + prefs->label_list_store = init_label_tree (prefs->label_tree, prefs, locked); + + if (!locked) { + g_signal_connect (G_OBJECT (prefs->label_add), "clicked", G_CALLBACK (label_add_cb), prefs); + g_signal_connect (G_OBJECT (prefs->label_remove), "clicked", G_CALLBACK (label_remove_cb), prefs); + g_signal_connect (G_OBJECT (prefs->label_color), "clicked", G_CALLBACK (label_color_cb), prefs); } - prefs->restore_labels = GTK_BUTTON (glade_xml_get_widget (gui, "cmdRestoreLabels")); - gtk_widget_set_sensitive ((GtkWidget *) prefs->restore_labels, !locked); - g_signal_connect (prefs->restore_labels, "clicked", G_CALLBACK (restore_labels_clicked), prefs); - /* headers */ locked = !gconf_client_key_is_writable (prefs->gconf, "/apps/evolution/mail/display/headers", NULL); diff --git a/mail/em-mailer-prefs.h b/mail/em-mailer-prefs.h index 846ce151bd..8c25be69f0 100644 --- a/mail/em-mailer-prefs.h +++ b/mail/em-mailer-prefs.h @@ -102,11 +102,11 @@ struct _EMMailerPrefs { struct _GtkToggleButton *prompt_unwanted_html; /* Labels and Colours tab */ - struct { - struct _GtkEntry *name; - struct _GtkColorButton *color; - } labels[5]; - struct _GtkButton *restore_labels; + struct _GtkWidget *label_add; + struct _GtkWidget *label_remove; + struct _GtkWidget *label_color; + struct _GtkWidget *label_tree; + struct _GtkListStore *label_list_store; /* Headers tab */ struct _GtkButton *add_header; diff --git a/mail/filtertypes.xml b/mail/filtertypes.xml index 3132fce6b7..1f8d39b34c 100644 --- a/mail/filtertypes.xml +++ b/mail/filtertypes.xml @@ -523,13 +523,13 @@ <option value="is"> <title>is</title> <code> - (match-all (= (user-tag "label") ${versus})) + (match-all (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus})))) </code> </option> <option value="is-not"> <title>is not</title> <code> - (match-all (not (= (user-tag "label") ${versus}))) + (match-all (not (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus}))))) </code> </option> </input> diff --git a/mail/mail-config.c b/mail/mail-config.c index a59128b9f1..ef9185ecbd 100644 --- a/mail/mail-config.c +++ b/mail/mail-config.c @@ -77,12 +77,14 @@ #include "mail-tools.h" /* Note, the first element of each MailConfigLabel must NOT be translated */ -MailConfigLabel label_defaults[5] = { - { "important", N_("I_mportant"), "#EF2929" }, /* red */ - { "work", N_("_Work"), "#F57900" }, /* orange */ - { "personal", N_("_Personal"), "#4E9A06" }, /* green */ - { "todo", N_("_To Do"), "#3465A4" }, /* blue */ - { "later", N_("_Later"), "#75507B" } /* purple */ +/* Note, the label tag should Always starts with prefix "$Label"! + It's also because filters and search folders, so beware people. */ +MailConfigLabel label_defaults[LABEL_DEFAULTS_NUM] = { + { "$Labelimportant", N_("I_mportant"), "#EF2929" }, /* red */ + { "$Labelwork", N_("_Work"), "#F57900" }, /* orange */ + { "$Labelpersonal", N_("_Personal"), "#4E9A06" }, /* green */ + { "$Labeltodo", N_("_To Do"), "#3465A4" }, /* blue */ + { "$Labellater", N_("_Later"), "#75507B" } /* purple */ }; typedef struct { @@ -163,75 +165,95 @@ config_clear_labels (void) static void config_cache_labels (void) { - GSList *labels, *list, *tail, *n; + GSList *labels, *list, *head; MailConfigLabel *label; - char *buf, *colour; + char *buf; int num = 0; - tail = labels = NULL; + labels = NULL; - list = gconf_client_get_list (config->gconf, "/apps/evolution/mail/labels", GCONF_VALUE_STRING, NULL); + head = gconf_client_get_list (config->gconf, "/apps/evolution/mail/labels", GCONF_VALUE_STRING, NULL); - while (list != NULL) { - buf = list->data; - - if (num < 5 && (colour = strrchr (buf, ':'))) { - label = g_new (MailConfigLabel, 1); - - *colour++ = '\0'; - label->tag = g_strdup(label_defaults[num].tag); - - /* Don't translate an empty string */ - if (buf == NULL || buf[0] == '\0') - label->name = g_strdup (_("Unnamed")); - else - label->name = g_strdup (_(buf)); - - label->colour = g_strdup (colour); + for (list = head; list; list = list->next) { + char *color, *name, *tag; + name = buf = list->data; + color = strrchr (buf, ':'); - n = g_slist_alloc (); - n->next = NULL; - n->data = label; + *color++ = '\0'; + tag = strchr (color, '|'); + if (tag) + *tag++ = '\0'; - if (tail == NULL) - labels = n; - else - tail->next = n; - - tail = n; + label = g_new (MailConfigLabel, 1); + /* Needed for Backward Compatibility */ + if (num < LABEL_DEFAULTS_NUM) { + label->name = g_strdup (_(buf)); + label->tag = g_strdup (label_defaults[num].tag); num++; + } else if (!tag) { + g_free (buf); + g_free (label); + continue; + } else { + label->name = g_strdup (name); + label->tag = g_strdup (tag); } - g_free (buf); + label->colour = g_strdup (color); + labels = g_slist_prepend (labels, label); - n = list->next; - g_slist_free_1 (list); - list = n; + g_free (buf); } - while (num < 5) { + if (head) + g_slist_free (head); + + while (num < LABEL_DEFAULTS_NUM) { /* complete the list with defaults */ label = g_new (MailConfigLabel, 1); label->tag = g_strdup (label_defaults[num].tag); label->name = g_strdup (_(label_defaults[num].name)); label->colour = g_strdup (label_defaults[num].colour); - n = g_slist_alloc (); - n->next = NULL; - n->data = label; + labels = g_slist_prepend (labels, label); - if (tail == NULL) - labels = n; - else - tail->next = n; + num++; + } - tail = n; + config->labels = g_slist_reverse (labels); +} - num++; +/* stores the actual cache to gconf */ +static gboolean +config_cache_labels_flush (void) +{ + GSList *l, *text_labels; + + if (!config || !config->labels) + return FALSE; + + text_labels = NULL; + + for (l = config->labels; l; l = l->next) { + MailConfigLabel *label = l->data; + + if (label && label->tag && label->name && label->colour) + text_labels = g_slist_prepend (text_labels, g_strdup_printf ("%s:%s|%s", label->name, label->colour, label->tag)); } - config->labels = labels; + if (!text_labels) + return FALSE; + + text_labels = g_slist_reverse (text_labels); + + gconf_client_set_list (config->gconf, "/apps/evolution/mail/labels", GCONF_VALUE_STRING, text_labels, NULL); + + g_slist_foreach (text_labels, (GFunc)g_free, NULL); + g_slist_free (text_labels); + + /* not true if gconf failed to write; who cares */ + return TRUE; } static void @@ -587,12 +609,6 @@ mail_config_is_corrupt (void) return config->corrupt; } -GSList * -mail_config_get_labels (void) -{ - return config->labels; -} - int mail_config_get_address_count (void) { @@ -635,36 +651,288 @@ mail_config_get_enable_magic_spacebar () return config->magic_spacebar; } -const char * -mail_config_get_label_color_by_name (const char *name) +/* public Label functions */ + +/** + * config_get_label + * + * Looks for label in labels cache by tag and returns actual pointer to cache. + * @param tag Tag of label you are looking for. + * @return Pointer to cache data if label with such tag exists or NULL. Do not free it! + **/ +static MailConfigLabel * +config_get_label (const char *tag) { - MailConfigLabel *label; - GSList *node; - - node = config->labels; - while (node != NULL) { - label = node->data; - if (!strcmp (label->tag, name)) - return label->colour; - node = node->next; + GSList *l; + + g_return_val_if_fail (tag != NULL, NULL); + + for (l = config->labels; l; l = l->next) { + MailConfigLabel *label = l->data; + + if (label && label->tag && !strcmp (tag, label->tag)) + return label; } return NULL; } +/** + * mail_config_get_labels + * + * @return list of known labels, each member data is MailConfigLabel structure. + * Returned list should not be freed, neither data inside it. + **/ +GSList * +mail_config_get_labels (void) +{ + return config->labels; +} + +/** + * mail_config_get_next_label_tag + * + * @param id [out] if not NULL, then assigned used number of the next free tag. + * @return Next free tag, which can be used for new label. + * Returned pointer should be freed with g_free. + * + * @note All labels should always start with "$Label" string, it's very important + * for filters and search folders! + **/ +char * +mail_config_get_next_label_tag (int *id) +{ + char *tag = NULL; + int count = LABEL_DEFAULTS_NUM; + + /* who wants more than 100 labels? */ + while (!tag && count <= 100) { + count++; + tag = g_strdup_printf ("$Label%d", count); + + if (config_get_label (tag)) { + g_free (tag); + tag = NULL; + } + } + + if (id) + *id = count; + + return tag; +} + +/** + * mail_config_is_system_label + * + * @return Whether the tag is one of default/system labels or not. + **/ +gboolean +mail_config_is_system_label (const char *tag) +{ + int i; + + if (!tag) + return FALSE; + + for (i = 0; i < LABEL_DEFAULTS_NUM; i++) { + if (strcmp (tag, label_defaults[i].tag) == 0) + return TRUE; + } + + return FALSE; +} + +/** + * mail_config_add_label + * Creates new label at the end of actual list of labels. + * + * @param tag Unique identifier of this new label. + * @param name User readable name of this label. Should not be NULL. + * @param color Color assigned to this label. Should not be NULL. + * @return Whether was added. + **/ +gboolean +mail_config_add_label (const char *tag, const char *name, const GdkColor *color) +{ + MailConfigLabel *label; + + g_return_val_if_fail (tag != NULL, FALSE); + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + if (config_get_label (tag) != NULL) + return FALSE; + + label = g_new0 (MailConfigLabel, 1); + label->tag = g_strdup (tag); + label->name = g_strdup (name); + label->colour = gdk_color_to_string (color); + + config->labels = g_slist_append (config->labels, label); + + return config_cache_labels_flush (); +} + +/** + * mail_config_remove_label + * + * @param tag Tag of the label to remove. + * @return Whether was removed. + **/ +gboolean +mail_config_remove_label (const char *tag) +{ + MailConfigLabel *label; + + g_return_val_if_fail (tag != NULL, FALSE); + + label = config_get_label (tag); + if (!label) + return FALSE; + + config->labels = g_slist_remove (config->labels, label); + + g_free (label); + + return config_cache_labels_flush (); +} + +/** + * mail_config_get_label_name + * + * @param tag Tag of the label of our interest. + * @return Name of the label with that tag or NULL, if no such label exists. + **/ const char * -mail_config_get_label_color_by_index (int index) +mail_config_get_label_name (const char *tag) +{ + MailConfigLabel *label; + + g_return_val_if_fail (tag != NULL, NULL); + + label = config_get_label (tag); + if (!label) + return NULL; + + return label->name; +} + +/** + * mail_config_get_label_color + * + * @param tag Tag of the label of our interest. + * @param color [out] Actual color of the label with that tag, or unchanged if failed. + * @return Whether found such label and color has been set. + **/ +gboolean +mail_config_get_label_color (const char *tag, GdkColor *color) { MailConfigLabel *label; - label = g_slist_nth_data (config->labels, index); + g_return_val_if_fail (tag != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); - if (label) - return label->colour; + label = config_get_label (tag); + if (!label) + return FALSE; + + return gdk_color_parse (label->colour, color); +} + +/** + * mail_config_get_label_color_str + * + * @param tag Tag of the label of our interest. + * @return String representation of that label, or NULL, is no such label exists. + **/ +const char * +mail_config_get_label_color_str (const char *tag) +{ + MailConfigLabel *label; + + g_return_val_if_fail (tag != NULL, FALSE); + + label = config_get_label (tag); + if (!label) + return FALSE; + + return label->colour; +} + +/** + * mail_config_get_new_label_tag + * + * @param old_tag Tag of the label from old version of Evolution. + * @return New tag name equivalent with the old tag, or NULL if no such name existed before. + **/ +const char * +mail_config_get_new_label_tag (const char *old_tag) +{ + int i; + + if (!old_tag) + return NULL; + + for (i = 0; i < LABEL_DEFAULTS_NUM; i++) { + /* default labels have same name as those old, only with prefix "$Label" */ + if (!strcmp (old_tag, label_defaults[i].tag + 6)) + return label_defaults[i].tag; + } return NULL; } +/** + * mail_config_set_label_name + * + * @param tag Tag of the label of our interest. + * @param name New name for the label. + * @return Whether successfully saved. + **/ +gboolean +mail_config_set_label_name (const char *tag, const char *name) +{ + MailConfigLabel *label; + + g_return_val_if_fail (tag != NULL, FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + label = config_get_label (tag); + if (!label) + return FALSE; + + g_free (label->name); + label->name = g_strdup (name); + + return config_cache_labels_flush (); +} + +/** + * mail_config_set_label_color + * + * @param tag Tag of the label of our interest. + * @param color New color for the label. + * @return Whether successfully saved. + **/ +gboolean +mail_config_set_label_color (const char *tag, const GdkColor *color) +{ + MailConfigLabel *label; + + g_return_val_if_fail (tag != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + label = config_get_label (tag); + if (!label) + return FALSE; + + g_free (label->colour); + label->colour = gdk_color_to_string (color); + + return config_cache_labels_flush (); +} + const char ** mail_config_get_allowable_mime_types (void) { diff --git a/mail/mail-config.glade b/mail/mail-config.glade index 316934df1a..b6e08a7163 100644 --- a/mail/mail-config.glade +++ b/mail/mail-config.glade @@ -1422,6 +1422,7 @@ For example: "Work" or "Personal"</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> + <property name="mnemonic_widget">source_auth_dropdown</property> <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> <property name="width_chars">-1</property> <property name="single_line_mode">False</property> @@ -2803,7 +2804,7 @@ For example: "Work" or "Personal"</property> <widget class="Custom" id="sent_button"> <property name="visible">True</property> <property name="creation_function">em_account_editor_folder_selector_button_new</property> - <property name="string1">Select Sent Folder</property> + <property name="string1" translatable="yes">Select Sent Folder</property> <property name="int1">0</property> <property name="int2">0</property> <property name="last_modification_time">Tue, 14 Dec 2004 17:07:09 GMT</property> @@ -2822,7 +2823,7 @@ For example: "Work" or "Personal"</property> <widget class="Custom" id="drafts_button"> <property name="visible">True</property> <property name="creation_function">em_account_editor_folder_selector_button_new</property> - <property name="string1">Select Drafts Folder</property> + <property name="string1" translatable="yes">Select Drafts Folder</property> <property name="int1">0</property> <property name="int2">0</property> <property name="last_modification_time">Tue, 14 Dec 2004 17:07:02 GMT</property> @@ -5858,225 +5859,106 @@ For example: "Work" or "Personal"</property> </child> <child> - <widget class="GtkTable" id="tableColours"> + <widget class="GtkHBox" id="hbox242"> <property name="visible">True</property> - <property name="n_rows">6</property> - <property name="n_columns">2</property> <property name="homogeneous">False</property> - <property name="row_spacing">6</property> - <property name="column_spacing">6</property> - - <child> - <widget class="GtkColorButton" id="colorLabel0"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="use_alpha">False</property> - <property name="title" translatable="yes">Pick a color</property> - <property name="focus_on_click">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">0</property> - <property name="bottom_attach">1</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> - - <child> - <widget class="GtkColorButton" id="colorLabel1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="use_alpha">False</property> - <property name="title" translatable="yes">Pick a color</property> - <property name="focus_on_click">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> - - <child> - <widget class="GtkColorButton" id="colorLabel2"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="use_alpha">False</property> - <property name="title" translatable="yes">Pick a color</property> - <property name="focus_on_click">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> - - <child> - <widget class="GtkColorButton" id="colorLabel3"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="use_alpha">False</property> - <property name="title" translatable="yes">Pick a color</property> - <property name="focus_on_click">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> - - <child> - <widget class="GtkColorButton" id="colorLabel4"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="use_alpha">False</property> - <property name="title" translatable="yes">Pick a color</property> - <property name="focus_on_click">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> - - <child> - <widget class="GtkEntry" id="txtLabel0"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="editable">True</property> - <property name="visibility">True</property> - <property name="max_length">0</property> - <property name="text" translatable="yes">Important</property> - <property name="has_frame">True</property> - <property name="invisible_char">*</property> - <property name="activates_default">False</property> - </widget> - <packing> - <property name="left_attach">0</property> - <property name="right_attach">1</property> - <property name="top_attach">0</property> - <property name="bottom_attach">1</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> + <property name="spacing">0</property> <child> - <widget class="GtkEntry" id="txtLabel1"> + <widget class="GtkVBox" id="vbox209"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="editable">True</property> - <property name="visibility">True</property> - <property name="max_length">0</property> - <property name="text" translatable="yes">Work</property> - <property name="has_frame">True</property> - <property name="invisible_char">*</property> - <property name="activates_default">False</property> - </widget> - <packing> - <property name="left_attach">0</property> - <property name="right_attach">1</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> + <property name="homogeneous">False</property> + <property name="spacing">0</property> - <child> - <widget class="GtkEntry" id="txtLabel2"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="editable">True</property> - <property name="visibility">True</property> - <property name="max_length">0</property> - <property name="text" translatable="yes">Personal</property> - <property name="has_frame">True</property> - <property name="invisible_char">*</property> - <property name="activates_default">False</property> - </widget> - <packing> - <property name="left_attach">0</property> - <property name="right_attach">1</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow50"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> - <child> - <widget class="GtkEntry" id="txtLabel3"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="editable">True</property> - <property name="visibility">True</property> - <property name="max_length">0</property> - <property name="text" translatable="yes">To Do</property> - <property name="has_frame">True</property> - <property name="invisible_char">*</property> - <property name="activates_default">False</property> - </widget> - <packing> - <property name="left_attach">0</property> - <property name="right_attach">1</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> + <child> + <widget class="GtkTreeView" id="labelTree"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + <property name="fixed_height_mode">False</property> + <property name="hover_selection">False</property> + <property name="hover_expand">False</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> - <child> - <widget class="GtkEntry" id="txtLabel4"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="editable">True</property> - <property name="visibility">True</property> - <property name="max_length">0</property> - <property name="text" translatable="yes">Later</property> - <property name="has_frame">True</property> - <property name="invisible_char">*</property> - <property name="activates_default">False</property> + <child> + <widget class="GtkLabel" id="label589"> + <property name="visible">True</property> + <property name="label" translatable="yes">Note: Underscore in the label name is used as mnemonic identifier in menu.</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">10</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> </widget> <packing> - <property name="left_attach">0</property> - <property name="right_attach">1</property> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="x_options">fill</property> - <property name="y_options"></property> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> </packing> </child> <child> - <widget class="GtkHBox" id="hbox188"> + <widget class="GtkVBox" id="vbox208"> <property name="visible">True</property> <property name="homogeneous">False</property> - <property name="spacing">6</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkButton" id="labelAdd"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-add</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> <child> - <widget class="GtkButton" id="cmdRestoreLabels"> + <widget class="GtkButton" id="labelRemove"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="label">gtk-revert-to-saved</property> + <property name="label">gtk-remove</property> <property name="use_stock">True</property> <property name="relief">GTK_RELIEF_NORMAL</property> <property name="focus_on_click">True</property> @@ -6087,14 +5969,93 @@ For example: "Work" or "Personal"</property> <property name="fill">False</property> </packing> </child> + + <child> + <widget class="GtkButton" id="labelColor"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment36"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox243"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image11"> + <property name="visible">True</property> + <property name="stock">gtk-select-color</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label590"> + <property name="visible">True</property> + <property name="label" translatable="yes">C_olor</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">10</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <placeholder/> + </child> </widget> <packing> - <property name="left_attach">0</property> - <property name="right_attach">2</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - <property name="x_options">fill</property> - <property name="y_options">fill</property> + <property name="padding">6</property> + <property name="expand">False</property> + <property name="fill">False</property> </packing> </child> </widget> diff --git a/mail/mail-config.h b/mail/mail-config.h index 3d159fe7e1..454a44f2bf 100644 --- a/mail/mail-config.h +++ b/mail/mail-config.h @@ -25,6 +25,7 @@ #include <glib.h> #include <glib-object.h> +#include <gdk/gdkcolor.h> #include "camel/camel-provider.h" /* can't forward-declare enums, bah */ @@ -94,7 +95,7 @@ typedef struct { } MailConfigLabel; #define LABEL_DEFAULTS_NUM 5 -extern MailConfigLabel label_defaults[5]; +extern MailConfigLabel label_defaults[LABEL_DEFAULTS_NUM]; /* Configuration */ void mail_config_init (void); @@ -108,9 +109,17 @@ struct _GConfClient *mail_config_get_gconf_client (void); gboolean mail_config_is_configured (void); gboolean mail_config_is_corrupt (void); -GSList *mail_config_get_labels (void); -const char *mail_config_get_label_color_by_name (const char *name); -const char *mail_config_get_label_color_by_index (int index); +GSList * mail_config_get_labels (void); +char * mail_config_get_next_label_tag (int *id); +gboolean mail_config_is_system_label (const char *tag); +gboolean mail_config_add_label (const char *tag, const char *name, const GdkColor *color); +gboolean mail_config_remove_label (const char *tag); +const char *mail_config_get_label_name (const char *tag); +gboolean mail_config_get_label_color (const char *tag, GdkColor *color); +const char *mail_config_get_label_color_str (const char *tag); +const char *mail_config_get_new_label_tag (const char *old_tag); +gboolean mail_config_set_label_name (const char *tag, const char *name); +gboolean mail_config_set_label_color (const char *tag, const GdkColor *color); const char **mail_config_get_allowable_mime_types (void); diff --git a/mail/message-list.c b/mail/message-list.c index e008301cee..9b76441418 100644 --- a/mail/message-list.c +++ b/mail/message-list.c @@ -934,6 +934,7 @@ ml_duplicate_value (ETreeModel *etm, int col, const void *value, void *data) case COL_MIXED_RECIPIENTS: case COL_FOLLOWUP_FLAG: case COL_LOCATION: + case COL_LABELS: return g_strdup (value); default: g_warning ("This shouldn't be reached\n"); @@ -967,6 +968,7 @@ ml_free_value (ETreeModel *etm, int col, void *value, void *data) case COL_RECIPIENTS: case COL_MIXED_SENDER: case COL_MIXED_RECIPIENTS: + case COL_LABELS: g_free (value); break; default: @@ -1000,6 +1002,7 @@ ml_initialize_value (ETreeModel *etm, int col, void *data) case COL_RECIPIENTS: case COL_MIXED_SENDER: case COL_MIXED_RECIPIENTS: + case COL_LABELS: return g_strdup (""); default: g_warning ("This shouldn't be reached\n"); @@ -1034,6 +1037,7 @@ ml_value_is_empty (ETreeModel *etm, int col, const void *value, void *data) case COL_RECIPIENTS: case COL_MIXED_SENDER: case COL_MIXED_RECIPIENTS: + case COL_LABELS: return !(value && *(char *)value); default: g_warning ("This shouldn't be reached\n"); @@ -1102,6 +1106,7 @@ ml_value_to_string (ETreeModel *etm, int col, const void *value, void *data) case COL_RECIPIENTS: case COL_MIXED_SENDER: case COL_MIXED_RECIPIENTS: + case COL_LABELS: return g_strdup (value); default: g_warning ("This shouldn't be reached\n"); @@ -1232,6 +1237,55 @@ sanitize_recipients (const gchar *string) return g_string_free (recipients, FALSE); } +static int +get_all_labels (CamelMessageInfo *msg_info, char **label_str, gboolean get_tags) +{ + GString *str; + const char *old_label; + int count = 0; + const CamelFlag *flag; + + str = g_string_new (""); + + for (flag = camel_message_info_user_flags (msg_info); flag; flag = flag->next) { + /* We will be able to show in the column even unknown labels from + other Evolution, because every label starts with "$Label". + This doesn't apply for filters and search folders, but here + we can see that we should add new labels to this Evolution too. */ + if (strncmp (flag->name, "$Label", 6) == 0) { + const char *name = NULL; + + if (str->len) + g_string_append (str, ", "); + + if (!get_tags) + name = mail_config_get_label_name (flag->name); + + g_string_append (str, get_tags || !name ? flag->name : name); + count++; + } + } + + old_label = mail_config_get_new_label_tag (camel_message_info_user_tag (msg_info, "label")); + + if (old_label != NULL) { + const char *name = NULL; + + if (str->len) + g_string_append (str, ", "); + + if (!get_tags) + name = mail_config_get_label_name (old_label); + + g_string_append (str, get_tags || !name ? old_label : name); + ++count; + } + + *label_str = g_string_free (str, FALSE); + + return count; +} + static void * ml_tree_value_at (ETreeModel *etm, ETreePath path, int col, void *model_data) { @@ -1355,25 +1409,24 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, int col, void *model_data) return GINT_TO_POINTER (!(flags & CAMEL_MESSAGE_SEEN)); } case COL_COLOUR: { - const char *colour, *due_by, *completed, *label; + const char *colour, *due_by, *completed; + char *labels_string = NULL; + int n; /* Priority: colour tag; label tag; important flag; due-by tag */ /* This is astonisngly poorly written code */ + /* To add to the woes, what color to show when the user choose multiple labels ? + Don't say that I need to have the new labels [with subject] column visible always */ + colour = camel_message_info_user_tag(msg_info, "colour"); due_by = camel_message_info_user_tag(msg_info, "due-by"); completed = camel_message_info_user_tag(msg_info, "completed-on"); - label = camel_message_info_user_tag(msg_info, "label"); if (colour == NULL) { - find_colour: - if (label != NULL) { - colour = mail_config_get_label_color_by_name (label); - if (colour == NULL) { - /* dead label? */ - label = NULL; - goto find_colour; - } + if ((n = get_all_labels (msg_info, &labels_string, TRUE)) == 1) { + + colour = mail_config_get_label_color_str (labels_string); } else if (camel_message_info_flags(msg_info) & CAMEL_MESSAGE_FLAGGED) { /* FIXME: extract from the important.xpm somehow. */ colour = "#A7453E"; @@ -1386,6 +1439,9 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, int col, void *model_data) colour = "#A7453E"; } } + + g_free (labels_string); + return (void *) colour; } case COL_LOCATION: { @@ -1441,6 +1497,23 @@ ml_tree_value_at (ETreeModel *etm, ETreePath path, int col, void *model_data) else return (void *)(""); } + case COL_LABELS:{ + char *str = NULL; + GString *cleansed_str; + + cleansed_str = g_string_new (""); + + if (get_all_labels (msg_info, &str, FALSE)) { + int i; + for (i = 0; str[i] != '\0'; ++i) { + if (str[i] != '_') { + g_string_append_c (cleansed_str, str[i]); + } + } + return (void *) (g_string_free (cleansed_str, FALSE)); + } else + return (void *) (""); + } default: g_warning ("This shouldn't be reached\n"); return NULL; diff --git a/mail/message-list.etspec b/mail/message-list.etspec index 80edd4a9cd..4581bc354f 100644 --- a/mail/message-list.etspec +++ b/mail/message-list.etspec @@ -31,6 +31,7 @@ <ETableColumn model_col="15" _title="Recipients" expansion="1.0" minimum_width="32" resizable="true" cell="render_text" compare="address_compare" search="string" priority="10"/> <ETableColumn model_col="16" _title="Messages" expansion="1.0" minimum_width="32" resizable="true" cell="render_composite_from" compare="address_compare" search="string" priority="10" sortable="false"/> <ETableColumn model_col="17" _title="Sent Messages" expansion="1.0" minimum_width="32" resizable="true" cell="render_composite_to" compare="address_compare" search="string" priority="10" sortable="false"/> + <ETableColumn model_col="18" _title="Labels" expansion="1.0" minimum_width="32" resizable="true" cell="render_text" compare="string" search="string" priority="10"/> <ETableState> <column source="0"/> <column source="3"/> <column source="1"/> diff --git a/mail/message-list.h b/mail/message-list.h index 5bec274ad6..147d76955d 100644 --- a/mail/message-list.h +++ b/mail/message-list.h @@ -60,6 +60,7 @@ enum { COL_RECIPIENTS, COL_MIXED_SENDER, COL_MIXED_RECIPIENTS, + COL_LABELS, /* normalised strings */ COL_FROM_NORM, diff --git a/mail/vfoldertypes.xml b/mail/vfoldertypes.xml index c1b60d40e8..a0ef98a717 100644 --- a/mail/vfoldertypes.xml +++ b/mail/vfoldertypes.xml @@ -260,13 +260,13 @@ <option value="is"> <title>is</title> <code> - (match-all (= (user-tag "label") ${versus})) + (match-all (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus})))) </code> </option> <option value="is-not"> <title>is not</title> <code> - (match-all (not (= (user-tag "label") ${versus}))) + (match-all (not (or (= (user-tag "label") ${versus}) (user-flag (+ "$Label" ${versus}))))) </code> </option> </input> |