aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-util-labels.c
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2008-01-10 19:19:37 +0800
committerMilan Crha <mcrha@src.gnome.org>2008-01-10 19:19:37 +0800
commitdd7bad07415b4b2a46d3bae6236838d52334f6fb (patch)
tree9a64bb9cd03b79fafe14ef7f8eee2399675fdd51 /e-util/e-util-labels.c
parent510eb1f01695c5d92df90bb3a2d2fbbc2bec8f40 (diff)
downloadgsoc2013-evolution-dd7bad07415b4b2a46d3bae6236838d52334f6fb.tar.gz
gsoc2013-evolution-dd7bad07415b4b2a46d3bae6236838d52334f6fb.tar.zst
gsoc2013-evolution-dd7bad07415b4b2a46d3bae6236838d52334f6fb.zip
** Fix for bug #211353
2008-01-10 Milan Crha <mcrha@redhat.com> ** Fix for bug #211353 * po/POTFILES.in: Added new file e-util/e-util-labels.c * mail/filtertypes.xml: * mail/vfoldertypes.xml: * mail/em-folder-view.c: * mail/em-folder-browser.c: * mail/em-mailer-prefs.h: * mail/em-mailer-prefs.c: * mail/mail-config.h: * mail/mail-config.c: * mail/mail-config.glade: * mail/message-list.c: Label tags are now generated based on label name when creating, except of first 5 labels. New menu option "New Label" in popup menu over message list and editing of labels has been changed in Preferences. Also renaming tab in Preferences for "Labels", not "Colors", and the tab label too. mail-config-label... functions was moved to e-util/e-util-labels.c/.h. * mail/message-list.etspec: Normalized columns has been moved by one when label column has been added. * filter/filter-option.h: * filter/filter-option.c: (filter_option_get_current), (filter_option_remove_all): New functions to be able to refill options even after initialization of the filter element. * filter/filter-label.c: Added support to notify changes on labels in runtime and use actual labels. * e-util/Makefile.am: * e-util/e-util-labels.h: * e-util/e-util-labels.c: New files to work with labels. svn path=/trunk/; revision=34788
Diffstat (limited to 'e-util/e-util-labels.c')
-rw-r--r--e-util/e-util-labels.c551
1 files changed, 551 insertions, 0 deletions
diff --git a/e-util/e-util-labels.c b/e-util/e-util-labels.c
new file mode 100644
index 0000000000..85225a93a5
--- /dev/null
+++ b/e-util/e-util-labels.c
@@ -0,0 +1,551 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-util-labels.c
+ *
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <gconf/gconf-client.h>
+
+#include <gtk/gtkbox.h>
+#include <gtk/gtkcolorbutton.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtktable.h>
+
+#include <camel/camel-utf8.h>
+
+#include "e-util-labels.h"
+#include "e-dialog-utils.h"
+
+/* Note, the first element of each EUtilLabel must NOT be translated */
+EUtilLabel 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 */
+};
+
+/**
+ * e_util_labels_parse
+ * Reads the setup from client and parses it to list of EUtilLabel objects.
+ *
+ * @param client The config client to be used for reading setup.
+ * Can be NULL, in that case it will use the default client.
+ * @return Newly allocated list of labels, should be freed with @ref e_util_labels_free.
+ **/
+GSList *
+e_util_labels_parse (GConfClient *client)
+{
+ GSList *labels, *list, *head;
+ EUtilLabel *label;
+ char *buf;
+ int num = 0;
+ gboolean unref_client = client == NULL;
+
+ labels = NULL;
+
+ if (!client)
+ client = gconf_client_get_default ();
+
+ head = gconf_client_get_list (client, E_UTIL_LABELS_GCONF_KEY, GCONF_VALUE_STRING, NULL);
+
+ for (list = head; list; list = list->next) {
+ char *color, *name, *tag;
+ name = buf = list->data;
+ color = strrchr (buf, ':');
+
+ *color++ = '\0';
+ tag = strchr (color, '|');
+ if (tag)
+ *tag++ = '\0';
+
+ label = g_new (EUtilLabel, 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);
+ }
+
+ label->colour = g_strdup (color);
+ labels = g_slist_prepend (labels, label);
+
+ g_free (buf);
+ }
+
+ if (head)
+ g_slist_free (head);
+
+ while (num < LABEL_DEFAULTS_NUM) {
+ /* complete the list with defaults */
+ label = g_new (EUtilLabel, 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);
+
+ labels = g_slist_prepend (labels, label);
+
+ num++;
+ }
+
+ if (unref_client)
+ g_object_unref (client);
+
+ return g_slist_reverse (labels);
+}
+
+static void
+free_label_struct (EUtilLabel *label)
+{
+ if (!label)
+ return;
+
+ g_free (label->tag);
+ g_free (label->name);
+ g_free (label->colour);
+ g_free (label);
+}
+
+/**
+ * e_util_labels_free
+ * Frees memory previously allocated by @ref e_util_labels_parse
+ *
+ * @param labels Labels list, previously allocated by @ref e_util_labels_parse
+ * It is safe to call with NULL.
+ **/
+void
+e_util_labels_free (GSList *labels)
+{
+ if (!labels)
+ return;
+
+ g_slist_foreach (labels, (GFunc)free_label_struct, NULL);
+ g_slist_free (labels);
+}
+
+/* stores the actual cache to gconf */
+static gboolean
+flush_labels_cache (GSList *labels, gboolean free_labels)
+{
+ GSList *l, *text_labels;
+ GConfClient *client;
+
+ if (!labels)
+ return FALSE;
+
+ text_labels = NULL;
+
+ for (l = labels; l; l = l->next) {
+ EUtilLabel *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));
+ }
+
+ if (!text_labels) {
+ if (free_labels)
+ e_util_labels_free (labels);
+
+ return FALSE;
+ }
+
+ text_labels = g_slist_reverse (text_labels);
+
+ client = gconf_client_get_default ();
+ gconf_client_set_list (client, E_UTIL_LABELS_GCONF_KEY, GCONF_VALUE_STRING, text_labels, NULL);
+ g_object_unref (client);
+
+ g_slist_foreach (text_labels, (GFunc)g_free, NULL);
+ g_slist_free (text_labels);
+
+ if (free_labels)
+ e_util_labels_free (labels);
+
+ /* not true if gconf failed to write; who cares */
+ return TRUE;
+}
+
+/**
+ * find_label
+ *
+ * Looks for label in labels cache by tag and returns actual pointer to cache.
+ * @param labels The cache of labels; comes from @ref e_util_labels_parse
+ * @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 EUtilLabel *
+find_label (GSList *labels, const char *tag)
+{
+ GSList *l;
+
+ g_return_val_if_fail (tag != NULL, NULL);
+
+ for (l = labels; l; l = l->next) {
+ EUtilLabel *label = l->data;
+
+ if (label && label->tag && !strcmp (tag, label->tag))
+ return label;
+ }
+
+ return NULL;
+}
+
+
+static char *
+tag_from_name (const char *name)
+{
+ /* this does thunderbird, just do not ask */
+ char *s1, *s2, *p;
+ const char *bads = " ()/{%*<>\\\"";
+
+ if (!name || !*name)
+ return NULL;
+
+ s1 = g_strdup (name);
+ for (p = s1; p && *p; p++) {
+ if (strchr (bads, *p))
+ *p = '_';
+ }
+
+ s2 = camel_utf8_utf7 (s1);
+ g_free (s1);
+
+ s1 = g_ascii_strdown (s2, -1);
+ g_free (s2);
+
+ return s1;
+}
+
+/**
+ * e_util_labels_add
+ * Creates new label at the end of actual list of labels.
+ *
+ * @param name User readable name of this label. Should not be NULL.
+ * @param color Color assigned to this label. Should not be NULL.
+ * @return If succeeded then new label tag, NULL otherwise.
+ * Returned pointer should be freed with g_free.
+ * It will return NULL when the tag will be same as already existed.
+ * Tag name is generated in similar way as in Thunderbird.
+ **/
+char *
+e_util_labels_add (const char *name, const GdkColor *color)
+{
+ EUtilLabel *label;
+ GSList *labels;
+ char *tag;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (color != NULL, NULL);
+
+ labels = e_util_labels_parse (NULL);
+ tag = tag_from_name (name);
+
+ if (!tag || find_label (labels, tag) != NULL) {
+ g_free (tag);
+ e_util_labels_free (labels);
+ return NULL;
+ }
+
+ label = g_new0 (EUtilLabel, 1);
+ label->tag = g_strdup (tag);
+ label->name = g_strdup (name);
+ label->colour = gdk_color_to_string (color);
+
+ labels = g_slist_append (labels, label);
+
+ flush_labels_cache (labels, TRUE);
+
+ return tag;
+}
+
+/**
+ * e_util_labels_add_with_dlg
+ * This will open a dialog to add or edit label.
+ *
+ * @param parent Parent widget for the dialog.
+ * @param tag A tag for existing label to edit or NULL to add new label.
+ * @return Tag for newly added label or NULL, if something failed.
+ * Returned value should be freed with g_free.
+ **/
+char *
+e_util_labels_add_with_dlg (GtkWindow *parent, const char *tag)
+{
+ GtkWidget *table, *dialog, *l, *e, *c;
+ const char *name;
+ GdkColor color;
+ gboolean is_edit = FALSE;
+ char *new_tag = NULL;
+ GSList *labels;
+
+ table = gtk_table_new (2, 2, FALSE);
+
+ labels = e_util_labels_parse (NULL);
+ name = tag ? e_util_labels_get_name (labels, tag) : NULL;
+
+ l = gtk_label_new_with_mnemonic (_("Label _Name:"));
+ e = gtk_entry_new ();
+ c = gtk_color_button_new ();
+
+ if (!tag || !e_util_labels_get_color (labels, tag, &color))
+ memset (&color, 0xCD, sizeof (GdkColor));
+ else
+ is_edit = TRUE;
+
+ if (name)
+ gtk_entry_set_text (GTK_ENTRY (e), name);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (l), e);
+ gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.0);
+ gtk_color_button_set_color (GTK_COLOR_BUTTON (c), &color);
+
+ gtk_table_attach (GTK_TABLE (table), l, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
+ gtk_table_attach (GTK_TABLE (table), e, 0, 1, 1, 2, 0, 0, 0, 0);
+ gtk_table_attach (GTK_TABLE (table), c, 1, 2, 1, 2, 0, 0, 0, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (table), 10);
+ gtk_widget_show_all (table);
+
+ dialog = gtk_dialog_new_with_buttons (is_edit ? _("Edit Label") : _("Add Label"),
+ parent,
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+ GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), table, TRUE, TRUE, 0);
+
+ while (!new_tag) {
+ const char *error = NULL;
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
+ name = gtk_entry_get_text (GTK_ENTRY (e));
+ gtk_color_button_get_color (GTK_COLOR_BUTTON (c), &color);
+
+ if (!name || !*name)
+ error = _("Label name cannot be empty.");
+ else if (is_edit) {
+ e_util_labels_set_data (tag, name, &color);
+ break;
+ } else if (!(new_tag = e_util_labels_add (name, &color)))
+ error = _("Label with same tag already exists. Rename your label please.");
+ else
+ break;
+ } else
+ break;
+
+ if (error)
+ e_notice (parent, GTK_MESSAGE_ERROR, error);
+ }
+
+ gtk_widget_destroy (dialog);
+ e_util_labels_free (labels);
+
+ return new_tag;
+}
+
+/**
+ * e_util_labels_remove
+ *
+ * @param tag Tag of the label to remove.
+ * @return Whether was removed.
+ **/
+gboolean
+e_util_labels_remove (const char *tag)
+{
+ EUtilLabel *label;
+ GSList *labels;
+
+ g_return_val_if_fail (tag != NULL, FALSE);
+
+ labels = e_util_labels_parse (NULL);
+ label = find_label (labels, tag);
+
+ if (!label) {
+ e_util_labels_free (labels);
+ return FALSE;
+ }
+
+ labels = g_slist_remove (labels, label);
+
+ free_label_struct (label);
+
+ return flush_labels_cache (labels, TRUE);
+}
+
+/**
+ * e_util_labels_set_data
+ *
+ * @param tag Tag of the label of our interest.
+ * @param name New name for the label.
+ * @param color New color for the label.
+ * @return Whether successfully saved.
+ **/
+gboolean
+e_util_labels_set_data (const char *tag, const char *name, const GdkColor *color)
+{
+ EUtilLabel *label;
+ GSList *labels;
+
+ g_return_val_if_fail (tag != NULL, FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+ g_return_val_if_fail (color != NULL, FALSE);
+
+ labels = e_util_labels_parse (NULL);
+ label = find_label (labels, tag);
+
+ if (!label) {
+ e_util_labels_free (labels);
+ return FALSE;
+ }
+
+ g_free (label->name);
+ label->name = g_strdup (name);
+
+ g_free (label->colour);
+ label->colour = gdk_color_to_string (color);
+
+ return flush_labels_cache (labels, TRUE);
+}
+
+/**
+ * e_util_labels_is_system
+ *
+ * @return Whether the tag is one of default/system labels or not.
+ **/
+gboolean
+e_util_labels_is_system (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;
+}
+
+/**
+ * e_util_labels_get_new_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 *
+e_util_labels_get_new_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;
+}
+
+/**
+ * e_util_labels_get_name
+ *
+ * @param labels Cache of labels from call of @ref e_util_labels_parse.
+ * The returned pointer will be taken from this list, so it's alive as long as the list.
+ * @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 *
+e_util_labels_get_name (GSList *labels, const char *tag)
+{
+ EUtilLabel *label;
+
+ g_return_val_if_fail (tag != NULL, NULL);
+
+ label = find_label (labels, tag);
+ if (!label)
+ return NULL;
+
+ return label->name;
+}
+
+/**
+ * e_util_labels_get_color
+ *
+ * @param labels Cache of labels from call of @ref e_util_labels_parse.
+ * @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
+e_util_labels_get_color (GSList *labels, const char *tag, GdkColor *color)
+{
+ EUtilLabel *label;
+
+ g_return_val_if_fail (tag != NULL, FALSE);
+ g_return_val_if_fail (color != NULL, FALSE);
+
+ label = find_label (labels, tag);
+ if (!label)
+ return FALSE;
+
+ return gdk_color_parse (label->colour, color);
+}
+
+/**
+ * e_util_labels_get_color_str
+ *
+ * @param labels Cache of labels from call of @ref e_util_labels_parse.
+ * The returned pointer will be taken from this list, so it's alive as long as the list.
+ * @param tag Tag of the label of our interest.
+ * @return String representation of that label, or NULL, is no such label exists.
+ **/
+const char *
+e_util_labels_get_color_str (GSList *labels, const char *tag)
+{
+ EUtilLabel *label;
+
+ g_return_val_if_fail (tag != NULL, FALSE);
+
+ label = find_label (labels, tag);
+ if (!label)
+ return FALSE;
+
+ return label->colour;
+}