aboutsummaryrefslogtreecommitdiffstats
path: root/mail
diff options
context:
space:
mode:
Diffstat (limited to 'mail')
-rw-r--r--mail/ChangeLog25
-rw-r--r--mail/em-folder-browser.c80
-rw-r--r--mail/em-folder-view.c77
-rw-r--r--mail/em-mailer-prefs.c308
-rw-r--r--mail/em-mailer-prefs.h10
-rw-r--r--mail/filtertypes.xml4
-rw-r--r--mail/mail-config.c410
-rw-r--r--mail/mail-config.glade375
-rw-r--r--mail/mail-config.h17
-rw-r--r--mail/message-list.c93
-rw-r--r--mail/message-list.etspec1
-rw-r--r--mail/message-list.h1
-rw-r--r--mail/vfoldertypes.xml4
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: &quot;Work&quot; or &quot;Personal&quot;</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: &quot;Work&quot; or &quot;Personal&quot;</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: &quot;Work&quot; or &quot;Personal&quot;</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: &quot;Work&quot; or &quot;Personal&quot;</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: &quot;Work&quot; or &quot;Personal&quot;</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>