diff options
author | Milan Crha <mcrha@redhat.com> | 2007-12-17 13:40:53 +0800 |
---|---|---|
committer | Srinivasa Ragavan <sragavan@src.gnome.org> | 2007-12-17 13:40:53 +0800 |
commit | 2093e3100243fb209ceb2c3a26d917124903dd8a (patch) | |
tree | 7974536b2cc4f091d51cfffdf67cc1b862134a06 /mail | |
parent | aec1cc466636e8630eccbf4cf5a593dca84dde95 (diff) | |
download | gsoc2013-evolution-2093e3100243fb209ceb2c3a26d917124903dd8a.tar gsoc2013-evolution-2093e3100243fb209ceb2c3a26d917124903dd8a.tar.gz gsoc2013-evolution-2093e3100243fb209ceb2c3a26d917124903dd8a.tar.bz2 gsoc2013-evolution-2093e3100243fb209ceb2c3a26d917124903dd8a.tar.lz gsoc2013-evolution-2093e3100243fb209ceb2c3a26d917124903dd8a.tar.xz gsoc2013-evolution-2093e3100243fb209ceb2c3a26d917124903dd8a.tar.zst gsoc2013-evolution-2093e3100243fb209ceb2c3a26d917124903dd8a.zip |
** Fix for bug #211353
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-14 Milan Crha <mcrha@redhat.com>
** Part of fix for bug #211353
* filter-label.c: Use global label's setup, not its own copy.
2007-12-14 Milan Crha <mcrha@redhat.com>
** Part of fix for bug #211353
* e-popup.h:
* e-popup.c: (ep_build_tree):
Toggles can be in inconsistent state now, and can also contain
an image, which is a pointer to GtkImage widget.
2007-12-14 Milan Crha <mcrha@redhat.com>
** Part of fix for bug #211353
* e-search-bar.c: (e_search_bar_get_viewitem_id):
Return -1 if no viewmenu is setup yet.
svn path=/trunk/; revision=34715
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> |