[evolution] Bug 203955 - Custom icon/text color for Mail folders



commit 4e123e6f513094f3224528f312d1308c6622f8a5
Author: Milan Crha <mcrha redhat com>
Date:   Mon Mar 11 12:10:04 2019 +0100

    Bug 203955 - Custom icon/text color for Mail folders
    
    Closes https://bugzilla.gnome.org/show_bug.cgi?id=203955

 src/mail/CMakeLists.txt         |   2 +
 src/mail/e-mail-folder-tweaks.c | 292 ++++++++++++++++++++++++++++++++++++
 src/mail/e-mail-folder-tweaks.h |  86 +++++++++++
 src/mail/em-folder-properties.c | 324 +++++++++++++++++++++++++++++++++++++---
 src/mail/em-folder-tree-model.c | 116 ++++++++++++++
 src/mail/em-folder-tree-model.h |  14 +-
 src/mail/em-folder-tree.c       |  39 +++--
 7 files changed, 837 insertions(+), 36 deletions(-)
---
diff --git a/src/mail/CMakeLists.txt b/src/mail/CMakeLists.txt
index 32cb8a7923..fa60d1091d 100644
--- a/src/mail/CMakeLists.txt
+++ b/src/mail/CMakeLists.txt
@@ -66,6 +66,7 @@ set(SOURCES
        e-mail-display-popup-extension.c
        e-mail-folder-create-dialog.c
        e-mail-folder-pane.c
+       e-mail-folder-tweaks.c
        e-mail-free-form-exp.c
        e-mail-junk-options.c
        e-mail-label-action.c
@@ -154,6 +155,7 @@ set(HEADERS
        e-mail-enums.h
        e-mail-folder-create-dialog.h
        e-mail-folder-pane.h
+       e-mail-folder-tweaks.h
        e-mail-free-form-exp.h
        e-mail-junk-options.h
        e-mail-label-action.h
diff --git a/src/mail/e-mail-folder-tweaks.c b/src/mail/e-mail-folder-tweaks.c
new file mode 100644
index 0000000000..2b4f754106
--- /dev/null
+++ b/src/mail/e-mail-folder-tweaks.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2019 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "evolution-config.h"
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "libemail-engine/libemail-engine.h"
+
+#include "e-mail-folder-tweaks.h"
+
+#define KEY_TEXT_COLOR         "Color"
+#define KEY_ICON_FILENAME      "Icon"
+
+struct _EMailFolderTweaksPrivate {
+       gchar *config_filename;
+       GKeyFile *config;
+       gboolean saving;
+};
+
+enum {
+       CHANGED,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (EMailFolderTweaks, e_mail_folder_tweaks, G_TYPE_OBJECT)
+
+static gboolean
+mail_folder_tweaks_save_idle_cb (gpointer user_data)
+{
+       EMailFolderTweaks *tweaks = user_data;
+       GError *error = NULL;
+
+       g_return_val_if_fail (E_IS_MAIL_FOLDER_TWEAKS (tweaks), FALSE);
+
+       if (!g_key_file_save_to_file (tweaks->priv->config, tweaks->priv->config_filename, &error)) {
+               g_warning ("%s: Failed to save tweaks to '%s': %s", G_STRFUNC,
+                       tweaks->priv->config_filename, error ? error->message : "Unknown error");
+               g_clear_error (&error);
+       }
+
+       tweaks->priv->saving = FALSE;
+
+       return FALSE;
+}
+
+static void
+mail_folder_tweaks_schedule_save (EMailFolderTweaks *tweaks)
+{
+       g_return_if_fail (E_IS_MAIL_FOLDER_TWEAKS (tweaks));
+
+       if (!tweaks->priv->saving) {
+               tweaks->priv->saving = TRUE;
+
+               g_idle_add_full (G_PRIORITY_LOW, mail_folder_tweaks_save_idle_cb, g_object_ref (tweaks), 
g_object_unref);
+       }
+}
+
+static gchar *
+mail_folder_tweaks_dup_string (EMailFolderTweaks *tweaks,
+                              const gchar *folder_uri,
+                              const gchar *key)
+{
+       g_return_val_if_fail (E_IS_MAIL_FOLDER_TWEAKS (tweaks), NULL);
+       g_return_val_if_fail (folder_uri != NULL, NULL);
+       g_return_val_if_fail (key != NULL, NULL);
+
+       return g_key_file_get_string (tweaks->priv->config, folder_uri, key, NULL);
+}
+
+static void
+mail_folder_tweaks_set_string (EMailFolderTweaks *tweaks,
+                              const gchar *folder_uri,
+                              const gchar *key,
+                              const gchar *value)
+{
+       gboolean changed;
+
+       g_return_if_fail (E_IS_MAIL_FOLDER_TWEAKS (tweaks));
+       g_return_if_fail (folder_uri != NULL);
+       g_return_if_fail (key != NULL);
+
+       if (!value || !*value) {
+               changed = g_key_file_remove_key (tweaks->priv->config, folder_uri, key, NULL);
+               if (changed) {
+                       gchar **keys;
+
+                       keys = g_key_file_get_keys (tweaks->priv->config, folder_uri, NULL, NULL);
+
+                       /* Remove the whole group, if it's the last key in it */
+                       if (!keys || !keys[0]) {
+                               g_key_file_remove_group (tweaks->priv->config, folder_uri, NULL);
+                       }
+
+                       g_strfreev (keys);
+               }
+       } else {
+               gchar *stored;
+
+               stored = mail_folder_tweaks_dup_string (tweaks, folder_uri, key);
+               changed = g_strcmp0 (stored, value) != 0;
+               g_free (stored);
+
+               if (changed)
+                       g_key_file_set_string (tweaks->priv->config, folder_uri, key, value);
+       }
+
+       if (changed) {
+               mail_folder_tweaks_schedule_save (tweaks);
+
+               g_signal_emit (tweaks, signals[CHANGED], 0, folder_uri, NULL);
+       }
+}
+
+static GObject *
+e_mail_folder_tweaks_constructor (GType type,
+                                 guint n_construct_properties,
+                                 GObjectConstructParam *construct_properties)
+{
+       static GWeakRef singleton;
+       GObject *result;
+
+       result = g_weak_ref_get (&singleton);
+       if (!result) {
+               result = G_OBJECT_CLASS (e_mail_folder_tweaks_parent_class)->constructor (type, 
n_construct_properties, construct_properties);
+
+               if (result)
+                       g_weak_ref_set (&singleton, result);
+       }
+
+       return result;
+}
+
+static void
+e_mail_folder_tweaks_finalize (GObject *object)
+{
+       EMailFolderTweaks *tweaks = E_MAIL_FOLDER_TWEAKS (object);
+
+       g_free (tweaks->priv->config_filename);
+       g_key_file_free (tweaks->priv->config);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_mail_folder_tweaks_parent_class)->finalize (object);
+}
+
+static void
+e_mail_folder_tweaks_class_init (EMailFolderTweaksClass *klass)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (klass, sizeof (EMailFolderTweaksPrivate));
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->constructor = e_mail_folder_tweaks_constructor;
+       object_class->finalize = e_mail_folder_tweaks_finalize;
+
+       signals[CHANGED] = g_signal_new (
+               "changed",
+               G_OBJECT_CLASS_TYPE (object_class),
+               G_SIGNAL_ACTION,
+               G_STRUCT_OFFSET (EMailFolderTweaksClass, changed),
+               NULL, NULL,
+               g_cclosure_marshal_VOID__STRING,
+               G_TYPE_NONE, 1,
+               G_TYPE_STRING);
+}
+
+static void
+e_mail_folder_tweaks_init (EMailFolderTweaks *tweaks)
+{
+       tweaks->priv = G_TYPE_INSTANCE_GET_PRIVATE (tweaks, E_TYPE_MAIL_FOLDER_TWEAKS, 
EMailFolderTweaksPrivate);
+       tweaks->priv->config_filename = g_build_filename (mail_session_get_config_dir (), 
"folder-tweaks.ini", NULL);
+       tweaks->priv->config = g_key_file_new ();
+
+       /* Ignore errors */
+       g_key_file_load_from_file (tweaks->priv->config, tweaks->priv->config_filename, G_KEY_FILE_NONE, 
NULL);
+}
+
+EMailFolderTweaks *
+e_mail_folder_tweaks_new (void)
+{
+       return g_object_new (E_TYPE_MAIL_FOLDER_TWEAKS, NULL);
+}
+
+void
+e_mail_folder_tweaks_remove_for_folders (EMailFolderTweaks *tweaks,
+                                        const gchar *top_folder_uri)
+{
+       gboolean changed = FALSE;
+       gchar **groups;
+       gint ii;
+
+       g_return_if_fail (E_IS_MAIL_FOLDER_TWEAKS (tweaks));
+       g_return_if_fail (top_folder_uri != NULL);
+
+       groups = g_key_file_get_groups (tweaks->priv->config, NULL);
+
+       if (!groups)
+               return;
+
+       for (ii = 0; groups[ii]; ii++) {
+               if (g_str_has_prefix (groups[ii], top_folder_uri)) {
+                       changed = g_key_file_remove_group (tweaks->priv->config, groups[ii], NULL);
+               }
+       }
+
+       g_strfreev (groups);
+
+       if (changed)
+               mail_folder_tweaks_schedule_save (tweaks);
+}
+
+gboolean
+e_mail_folder_tweaks_get_color (EMailFolderTweaks *tweaks,
+                               const gchar *folder_uri,
+                               GdkRGBA *out_rgba)
+{
+       gchar *stored;
+       gboolean success;
+
+       g_return_val_if_fail (E_IS_MAIL_FOLDER_TWEAKS (tweaks), FALSE);
+       g_return_val_if_fail (folder_uri != NULL, FALSE);
+       g_return_val_if_fail (out_rgba != NULL, FALSE);
+
+       stored = mail_folder_tweaks_dup_string (tweaks, folder_uri, KEY_TEXT_COLOR);
+       if (!stored)
+               return FALSE;
+
+       success = gdk_rgba_parse (out_rgba, stored);
+
+       g_free (stored);
+
+       return success;
+}
+
+void
+e_mail_folder_tweaks_set_color (EMailFolderTweaks *tweaks,
+                               const gchar *folder_uri,
+                               const GdkRGBA *rgba)
+{
+       gchar *value;
+
+       g_return_if_fail (E_IS_MAIL_FOLDER_TWEAKS (tweaks));
+       g_return_if_fail (folder_uri != NULL);
+
+       if (rgba)
+               value = gdk_rgba_to_string (rgba);
+       else
+               value = NULL;
+
+       mail_folder_tweaks_set_string (tweaks, folder_uri, KEY_TEXT_COLOR, value);
+
+       g_free (value);
+}
+
+gchar *
+e_mail_folder_tweaks_dup_icon_filename (EMailFolderTweaks *tweaks,
+                                       const gchar *folder_uri)
+{
+       g_return_val_if_fail (E_IS_MAIL_FOLDER_TWEAKS (tweaks), FALSE);
+       g_return_val_if_fail (folder_uri != NULL, FALSE);
+
+       return mail_folder_tweaks_dup_string (tweaks, folder_uri, KEY_ICON_FILENAME);
+}
+
+void
+e_mail_folder_tweaks_set_icon_filename (EMailFolderTweaks *tweaks,
+                                       const gchar *folder_uri,
+                                       const gchar *icon_filename)
+{
+       g_return_if_fail (E_IS_MAIL_FOLDER_TWEAKS (tweaks));
+       g_return_if_fail (folder_uri != NULL);
+
+       mail_folder_tweaks_set_string (tweaks, folder_uri, KEY_ICON_FILENAME, icon_filename);
+}
diff --git a/src/mail/e-mail-folder-tweaks.h b/src/mail/e-mail-folder-tweaks.h
new file mode 100644
index 0000000000..23fc379cbf
--- /dev/null
+++ b/src/mail/e-mail-folder-tweaks.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef E_MAIL_FOLDER_TWEAKS_H
+#define E_MAIL_FOLDER_TWEAKS_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_FOLDER_TWEAKS \
+       (e_mail_folder_tweaks_get_type ())
+#define E_MAIL_FOLDER_TWEAKS(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_MAIL_FOLDER_TWEAKS, EMailFolderTweaks))
+#define E_MAIL_FOLDER_TWEAKS_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_MAIL_FOLDER_TWEAKS, EMailFolderTweaksClass))
+#define E_IS_MAIL_FOLDER_TWEAKS(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_MAIL_FOLDER_TWEAKS))
+#define E_IS_MAIL_FOLDER_TWEAKS_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_MAIL_FOLDER_TWEAKS))
+#define E_MAIL_FOLDER_TWEAKS_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_MAIL_FOLDER_TWEAKS, EMailFolderTweaksClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailFolderTweaks EMailFolderTweaks;
+typedef struct _EMailFolderTweaksClass EMailFolderTweaksClass;
+typedef struct _EMailFolderTweaksPrivate EMailFolderTweaksPrivate;
+
+struct _EMailFolderTweaks {
+       /*< private >*/
+       GObject parent;
+       EMailFolderTweaksPrivate *priv;
+};
+
+struct _EMailFolderTweaksClass {
+       /*< private >*/
+       GObjectClass parent_class;
+
+       void    (* changed)     (EMailFolderTweaks *tweaks,
+                                const gchar *folder_uri);
+};
+
+GType          e_mail_folder_tweaks_get_type   (void);
+
+EMailFolderTweaks *
+               e_mail_folder_tweaks_new        (void);
+void           e_mail_folder_tweaks_remove_for_folders
+                                               (EMailFolderTweaks *tweaks,
+                                                const gchar *top_folder_uri);
+gboolean       e_mail_folder_tweaks_get_color  (EMailFolderTweaks *tweaks,
+                                                const gchar *folder_uri,
+                                                GdkRGBA *out_rgba);
+void           e_mail_folder_tweaks_set_color  (EMailFolderTweaks *tweaks,
+                                                const gchar *folder_uri,
+                                                const GdkRGBA *rgba);
+gchar *                e_mail_folder_tweaks_dup_icon_filename
+                                               (EMailFolderTweaks *tweaks,
+                                                const gchar *folder_uri);
+void           e_mail_folder_tweaks_set_icon_filename
+                                               (EMailFolderTweaks *tweaks,
+                                                const gchar *folder_uri,
+                                                const gchar *icon_filename);
+
+G_END_DECLS
+
+#endif /* E_MAIL_FOLDER_TWEAKS_H */
diff --git a/src/mail/em-folder-properties.c b/src/mail/em-folder-properties.c
index 1be107ba46..a1a77c6cce 100644
--- a/src/mail/em-folder-properties.c
+++ b/src/mail/em-folder-properties.c
@@ -35,6 +35,7 @@
 #include <e-util/e-util.h>
 
 #include "e-mail-backend.h"
+#include "e-mail-folder-tweaks.h"
 #include "e-mail-label-dialog.h"
 #include "e-mail-notes.h"
 #include "e-mail-ui-session.h"
@@ -85,6 +86,258 @@ emfp_free (EConfig *ec,
        g_slist_free (items);
 }
 
+typedef struct _FolderTweaksData {
+       gchar *folder_uri;
+       EMailFolderTweaks *tweaks; /* referenced */
+       GtkWidget *widget; /* not referenced */
+} FolderTweaksData;
+
+static FolderTweaksData *
+folder_tweaks_data_new (const gchar *folder_uri,
+                       EMailFolderTweaks *tweaks,
+                       GtkWidget *widget)
+{
+       FolderTweaksData *ftd;
+
+       ftd = g_new0 (FolderTweaksData, 1);
+       ftd->folder_uri = g_strdup (folder_uri);
+       ftd->tweaks = g_object_ref (tweaks);
+       ftd->widget = widget;
+
+       return ftd;
+}
+
+static void
+folder_tweaks_data_free (gpointer ptr,
+                        GClosure *closure)
+{
+       FolderTweaksData *ftd = ptr;
+
+       if (ftd) {
+               g_free (ftd->folder_uri);
+               g_object_unref (ftd->tweaks);
+               g_free (ftd);
+       }
+}
+
+static void
+tweaks_custom_icon_check_toggled_cb (GtkToggleButton *toggle_button,
+                                    FolderTweaksData *ftd)
+{
+       GtkWidget *image;
+
+       g_return_if_fail (ftd != NULL);
+
+       if (!gtk_toggle_button_get_active (toggle_button)) {
+               e_mail_folder_tweaks_set_icon_filename (ftd->tweaks, ftd->folder_uri, NULL);
+               return;
+       }
+
+       image = gtk_button_get_image (GTK_BUTTON (ftd->widget));
+
+       if (image && gtk_image_get_storage_type (GTK_IMAGE (image))) {
+               GIcon *icon = NULL;
+
+               gtk_image_get_gicon (GTK_IMAGE (image), &icon, NULL);
+
+               if (G_IS_FILE_ICON (icon)) {
+                       GFile *file;
+
+                       file = g_file_icon_get_file (G_FILE_ICON (icon));
+                       if (file) {
+                               gchar *filename;
+
+                               filename = g_file_get_path (file);
+                               if (filename) {
+                                       e_mail_folder_tweaks_set_icon_filename (ftd->tweaks, ftd->folder_uri, 
filename);
+
+                                       g_free (filename);
+                               }
+                       }
+               }
+       }
+}
+
+static void
+tweaks_custom_icon_button_clicked_cb (GtkWidget *button,
+                                     FolderTweaksData *ftd)
+{
+       GtkWidget *dialog;
+       GtkWidget *toplevel;
+       GFile *file;
+
+       toplevel = gtk_widget_get_toplevel (button);
+       dialog = e_image_chooser_dialog_new (_("Select Custom Icon"),
+               GTK_IS_WINDOW (toplevel) ? GTK_WINDOW (toplevel) : NULL);
+
+       file = e_image_chooser_dialog_run (E_IMAGE_CHOOSER_DIALOG (dialog));
+
+       gtk_widget_destroy (dialog);
+
+       if (file) {
+               gchar *filename;
+
+               filename = g_file_get_path (file);
+               if (filename) {
+                       GtkWidget *image;
+                       GIcon *custom_icon;
+
+                       image = gtk_button_get_image (GTK_BUTTON (button));
+                       custom_icon = g_file_icon_new (file);
+
+                       gtk_image_set_from_gicon (GTK_IMAGE (image), custom_icon, GTK_ICON_SIZE_BUTTON);
+
+                       g_clear_object (&custom_icon);
+
+                       e_mail_folder_tweaks_set_icon_filename (ftd->tweaks, ftd->folder_uri, filename);
+
+                       g_free (filename);
+               }
+
+               g_object_unref (file);
+       }
+}
+
+static void
+emfp_add_tweaks_custom_icon_row (GtkBox *vbox,
+                                const gchar *folder_uri,
+                                EMailFolderTweaks *tweaks)
+{
+       GtkWidget *checkbox;
+       GtkWidget *button;
+       GtkWidget *image;
+       GtkWidget *hbox;
+       gchar *icon_filename;
+
+       g_return_if_fail (GTK_IS_BOX (vbox));
+       g_return_if_fail (folder_uri != NULL);
+       g_return_if_fail (E_IS_MAIL_FOLDER_TWEAKS (tweaks));
+
+       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
+       gtk_box_pack_start (vbox, hbox, FALSE, FALSE, 0);
+
+       checkbox = gtk_check_button_new_with_mnemonic (_("_Use custom icon"));
+       gtk_box_pack_start (GTK_BOX (hbox), checkbox, FALSE, FALSE, 0);
+
+       button = gtk_button_new ();
+       image = gtk_image_new_from_icon_name (NULL, GTK_ICON_SIZE_BUTTON);
+       gtk_button_set_image (GTK_BUTTON (button), image);
+       gtk_button_set_always_show_image (GTK_BUTTON (button), TRUE);
+
+       icon_filename = e_mail_folder_tweaks_dup_icon_filename (tweaks, folder_uri);
+       if (icon_filename &&
+           g_file_test (icon_filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+               GFile *file;
+               GIcon *custom_icon;
+
+               file = g_file_new_for_path (icon_filename);
+               custom_icon = g_file_icon_new (file);
+
+               g_clear_object (&file);
+
+               gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), TRUE);
+               gtk_image_set_from_gicon (GTK_IMAGE (image), custom_icon, GTK_ICON_SIZE_BUTTON);
+
+               g_clear_object (&custom_icon);
+       }
+
+       g_free (icon_filename);
+
+       gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+       e_binding_bind_property (
+               checkbox, "active",
+               button, "sensitive",
+               G_BINDING_DEFAULT |
+               G_BINDING_SYNC_CREATE);
+
+       g_signal_connect_data (checkbox, "toggled",
+               G_CALLBACK (tweaks_custom_icon_check_toggled_cb),
+               folder_tweaks_data_new (folder_uri, tweaks, button), folder_tweaks_data_free, 0);
+
+       g_signal_connect_data (button, "clicked",
+               G_CALLBACK (tweaks_custom_icon_button_clicked_cb),
+               folder_tweaks_data_new (folder_uri, tweaks, NULL), folder_tweaks_data_free, 0);
+
+       gtk_widget_show_all (hbox);
+}
+
+static void
+tweaks_text_color_check_toggled_cb (GtkToggleButton *toggle_button,
+                                   FolderTweaksData *ftd)
+{
+       g_return_if_fail (ftd != NULL);
+
+       if (gtk_toggle_button_get_active (toggle_button)) {
+               GdkRGBA rgba;
+
+               gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (ftd->widget), &rgba);
+
+               e_mail_folder_tweaks_set_color (ftd->tweaks, ftd->folder_uri, &rgba);
+       } else {
+               e_mail_folder_tweaks_set_color (ftd->tweaks, ftd->folder_uri, NULL);
+       }
+}
+
+static void
+tweaks_text_color_button_color_set_cb (GtkColorButton *col_button,
+                                      FolderTweaksData *ftd)
+{
+       GdkRGBA rgba;
+
+       g_return_if_fail (ftd != NULL);
+
+       gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (col_button), &rgba);
+
+       e_mail_folder_tweaks_set_color (ftd->tweaks, ftd->folder_uri, &rgba);
+}
+
+static void
+emfp_add_tweaks_text_color_row (GtkBox *vbox,
+                               const gchar *folder_uri,
+                               EMailFolderTweaks *tweaks)
+{
+       GtkWidget *checkbox;
+       GtkWidget *button;
+       GtkWidget *hbox;
+       GdkRGBA rgba;
+
+       g_return_if_fail (GTK_IS_BOX (vbox));
+       g_return_if_fail (folder_uri != NULL);
+       g_return_if_fail (E_IS_MAIL_FOLDER_TWEAKS (tweaks));
+
+       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
+       gtk_box_pack_start (vbox, hbox, FALSE, FALSE, 0);
+
+       checkbox = gtk_check_button_new_with_mnemonic (_("Use te_xt color"));
+       gtk_box_pack_start (GTK_BOX (hbox), checkbox, FALSE, FALSE, 0);
+
+       button = gtk_color_button_new ();
+
+       gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+       if (e_mail_folder_tweaks_get_color (tweaks, folder_uri, &rgba)) {
+               gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), TRUE);
+               gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (button), &rgba);
+       }
+
+       e_binding_bind_property (
+               checkbox, "active",
+               button, "sensitive",
+               G_BINDING_DEFAULT |
+               G_BINDING_SYNC_CREATE);
+
+       g_signal_connect_data (checkbox, "toggled",
+               G_CALLBACK (tweaks_text_color_check_toggled_cb),
+               folder_tweaks_data_new (folder_uri, tweaks, button), folder_tweaks_data_free, 0);
+
+       g_signal_connect_data (button, "color-set",
+               G_CALLBACK (tweaks_text_color_button_color_set_cb),
+               folder_tweaks_data_new (folder_uri, tweaks, NULL), folder_tweaks_data_free, 0);
+
+       gtk_widget_show_all (hbox);
+}
+
 static void
 mail_identity_combo_box_changed_cb (GtkComboBox *combo_box,
                                     EMailSendAccountOverride *account_override)
@@ -462,6 +715,39 @@ emfp_get_folder_item (EConfig *ec,
        return table;
 }
 
+static GtkWidget *
+emfp_get_appearance_item (EConfig *ec,
+                         EConfigItem *item,
+                         GtkWidget *parent,
+                         GtkWidget *old,
+                         gint position,
+                         gpointer user_data)
+{
+       AsyncContext *context = user_data;
+       GtkBox *vbox;
+       EMailFolderTweaks *tweaks;
+       gchar *folder_uri;
+
+       if (old)
+               return old;
+
+       vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 6));
+       gtk_widget_show (GTK_WIDGET (vbox));
+
+       gtk_box_pack_start (GTK_BOX (parent), GTK_WIDGET (vbox), TRUE, TRUE, 0);
+
+       tweaks = e_mail_folder_tweaks_new ();
+       folder_uri = e_mail_folder_uri_from_folder (context->folder);
+
+       emfp_add_tweaks_custom_icon_row (vbox, folder_uri, tweaks);
+       emfp_add_tweaks_text_color_row (vbox, folder_uri, tweaks);
+
+       g_clear_object (&tweaks);
+       g_free (folder_uri);
+
+       return GTK_WIDGET (vbox);
+}
+
 static const gchar *
 emfp_autoarchive_config_to_string (EAutoArchiveConfig config)
 {
@@ -1076,22 +1362,22 @@ emfp_get_labels_item (EConfig *ec,
        return GTK_WIDGET (grid);
 }
 
-#define EMFP_FOLDER_SECTION (2)
-
 static EMConfigItem emfp_items[] = {
        { E_CONFIG_BOOK, (gchar *) "", NULL },
        { E_CONFIG_PAGE, (gchar *) "00.general", (gchar *) N_("General") },
        { E_CONFIG_SECTION, (gchar *) "00.general/00.folder", NULL /* set by code */ },
        { E_CONFIG_ITEM, (gchar *) "00.general/00.folder/00.info", NULL, emfp_get_folder_item },
+       { E_CONFIG_PAGE, (gchar *) "10.appearance", (gchar *) N_("Appearance") },
+       { E_CONFIG_SECTION, (gchar *) "10.appearance/00.folder", NULL },
+       { E_CONFIG_ITEM, (gchar *) "10.appearance/00.folder/00.appearance", NULL, emfp_get_appearance_item },
        /* Translators: "Archive" is a noun (This is a tab heading in the mail folder properties) */
-       { E_CONFIG_PAGE, (gchar *) "10.autoarchive", (gchar *) N_("Archive") },
-       { E_CONFIG_SECTION, (gchar *) "10.autoarchive/00.folder", NULL },
-       { E_CONFIG_ITEM, (gchar *) "10.autoarchive/00.folder/00.info", NULL, emfp_get_autoarchive_item },
-       { E_CONFIG_PAGE, (gchar *) "20.labels", (gchar *) N_("Labels") },
-       { E_CONFIG_SECTION, (gchar *) "20.labels/00.folder", NULL },
-       { E_CONFIG_ITEM, (gchar *) "20.labels/00.folder/00.labels", NULL, emfp_get_labels_item }
+       { E_CONFIG_PAGE, (gchar *) "20.autoarchive", (gchar *) N_("Archive") },
+       { E_CONFIG_SECTION, (gchar *) "20.autoarchive/00.folder", NULL },
+       { E_CONFIG_ITEM, (gchar *) "20.autoarchive/00.folder/00.info", NULL, emfp_get_autoarchive_item },
+       { E_CONFIG_PAGE, (gchar *) "30.labels", (gchar *) N_("Labels") },
+       { E_CONFIG_SECTION, (gchar *) "30.labels/00.folder", NULL },
+       { E_CONFIG_ITEM, (gchar *) "30.labels/00.folder/00.labels", NULL, emfp_get_labels_item }
 };
-static gboolean emfp_items_translated = FALSE;
 
 static void
 emfp_dialog_run (AsyncContext *context)
@@ -1107,6 +1393,7 @@ emfp_dialog_run (AsyncContext *context)
        gboolean store_is_local;
        gboolean hide_deleted;
        GSettings *settings;
+       const gchar *folder_label;
        const gchar *name;
        const gchar *uid;
 
@@ -1152,18 +1439,17 @@ emfp_dialog_run (AsyncContext *context)
                || !strcmp (name, "Inbox")
                || !strcmp (name, "Outbox")
                || !strcmp (name, "Sent"))) {
-               emfp_items[EMFP_FOLDER_SECTION].label = gettext (name);
-               if (!emfp_items_translated) {
-                       for (i = 0; i < G_N_ELEMENTS (emfp_items); i++) {
-                               if (emfp_items[i].label)
-                                       emfp_items[i].label = _(emfp_items[i].label);
-                       }
-                       emfp_items_translated = TRUE;
-               }
+               folder_label = _(name);
        } else if (!strcmp (name, "INBOX"))
-               emfp_items[EMFP_FOLDER_SECTION].label = _("Inbox");
+               folder_label = _("Inbox");
        else
-               emfp_items[EMFP_FOLDER_SECTION].label = (gchar *) name;
+               folder_label = name;
+
+       for (i = 0; i < G_N_ELEMENTS (emfp_items); i++) {
+               if (emfp_items[i].type == E_CONFIG_SECTION &&
+                   g_str_has_suffix (emfp_items[i].path, "/00.folder"))
+                       emfp_items[i].label = (gchar *) folder_label;
+       }
 
        dialog = gtk_dialog_new_with_buttons (
                _("Folder Properties"),
diff --git a/src/mail/em-folder-tree-model.c b/src/mail/em-folder-tree-model.c
index a1d2b74c00..cc56965ed9 100644
--- a/src/mail/em-folder-tree-model.c
+++ b/src/mail/em-folder-tree-model.c
@@ -64,6 +64,8 @@ struct _EMFolderTreeModelPrivate {
        /* CamelStore -> StoreInfo */
        GHashTable *store_index;
        GMutex store_index_lock;
+
+       EMailFolderTweaks *folder_tweaks;
 };
 
 typedef struct _FolderUnreadInfo {
@@ -523,8 +525,18 @@ folder_tree_model_service_removed (EMailAccountStore *account_store,
                                    CamelService *service,
                                    EMFolderTreeModel *folder_tree_model)
 {
+       EMailFolderTweaks *tweaks;
+       gchar *top_folder_uri;
+
        em_folder_tree_model_remove_store (
                folder_tree_model, CAMEL_STORE (service));
+
+       top_folder_uri = e_mail_folder_uri_build (CAMEL_STORE (service), "");
+       tweaks = em_folder_tree_model_get_folder_tweaks (folder_tree_model);
+
+       e_mail_folder_tweaks_remove_for_folders (tweaks, top_folder_uri);
+
+       g_free (top_folder_uri);
 }
 
 static void
@@ -586,6 +598,44 @@ folder_tree_model_spinner_pulse_cb (gpointer user_data)
        return G_SOURCE_CONTINUE;
 }
 
+static gboolean
+em_folder_tree_model_update_tweaks_foreach_cb (GtkTreeModel *model,
+                                              GtkTreePath *path,
+                                              GtkTreeIter *iter,
+                                              gpointer user_data)
+{
+       const gchar *given_folder_uri = user_data;
+       gchar *stored_folder_uri = NULL;
+
+       gtk_tree_model_get (model, iter, COL_STRING_FOLDER_URI, &stored_folder_uri, -1);
+
+       if (!stored_folder_uri ||
+           g_strcmp0 (stored_folder_uri, given_folder_uri) != 0) {
+               g_free (stored_folder_uri);
+               return FALSE;
+       }
+
+       g_free (stored_folder_uri);
+
+       em_folder_tree_model_update_row_tweaks (EM_FOLDER_TREE_MODEL (model), iter);
+
+       return TRUE;
+}
+
+static void
+em_folder_tree_model_folder_tweaks_changed_cb (EMailFolderTweaks *tweaks,
+                                              const gchar *folder_uri,
+                                              gpointer user_data)
+{
+       EMFolderTreeModel *model = user_data;
+
+       g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model));
+       g_return_if_fail (folder_uri != NULL);
+
+       gtk_tree_model_foreach (GTK_TREE_MODEL (model),
+               em_folder_tree_model_update_tweaks_foreach_cb, (gpointer) folder_uri);
+}
+
 static void
 folder_tree_model_selection_finalized_cb (EMFolderTreeModel *model)
 {
@@ -676,6 +726,9 @@ folder_tree_model_dispose (GObject *object)
                priv->account_store = NULL;
        }
 
+       g_signal_handlers_disconnect_by_func (priv->folder_tweaks,
+               em_folder_tree_model_folder_tweaks_changed_cb, object);
+
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (em_folder_tree_model_parent_class)->dispose (object);
 }
@@ -689,6 +742,7 @@ folder_tree_model_finalize (GObject *object)
 
        g_hash_table_destroy (priv->store_index);
        g_mutex_clear (&priv->store_index_lock);
+       g_clear_object (&priv->folder_tweaks);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (em_folder_tree_model_parent_class)->finalize (object);
@@ -713,8 +767,13 @@ folder_tree_model_constructed (GObject *object)
                G_TYPE_BOOLEAN,   /* status icon visible */
                G_TYPE_UINT,      /* status spinner pulse */
                G_TYPE_BOOLEAN,   /* status spinner visible */
+               G_TYPE_STRING,    /* COL_STRING_FOLDER_URI */
+               G_TYPE_ICON,      /* COL_GICON_CUSTOM_ICON */
+               GDK_TYPE_RGBA     /* COL_RGBA_FOREGROUND_RGBA */
        };
 
+       g_warn_if_fail (G_N_ELEMENTS (col_types) == NUM_COLUMNS);
+
        gtk_tree_store_set_column_types (
                GTK_TREE_STORE (object), NUM_COLUMNS, col_types);
        gtk_tree_sortable_set_default_sort_func (
@@ -917,8 +976,12 @@ em_folder_tree_model_init (EMFolderTreeModel *model)
 
        model->priv = EM_FOLDER_TREE_MODEL_GET_PRIVATE (model);
        model->priv->store_index = store_index;
+       model->priv->folder_tweaks = e_mail_folder_tweaks_new ();
 
        g_mutex_init (&model->priv->store_index_lock);
+
+       g_signal_connect (model->priv->folder_tweaks, "changed",
+               G_CALLBACK (em_folder_tree_model_folder_tweaks_changed_cb), model);
 }
 
 EMFolderTreeModel *
@@ -960,6 +1023,14 @@ em_folder_tree_model_free_default (void)
        em_folder_tree_manage_default (FALSE);
 }
 
+EMailFolderTweaks *
+em_folder_tree_model_get_folder_tweaks (EMFolderTreeModel *model)
+{
+       g_return_val_if_fail (EM_IS_FOLDER_TREE_MODEL (model), NULL);
+
+       return model->priv->folder_tweaks;
+}
+
 GtkTreeSelection *
 em_folder_tree_model_get_selection (EMFolderTreeModel *model)
 {
@@ -1301,8 +1372,11 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model,
                COL_BOOL_LOAD_SUBDIRS, load,
                COL_UINT_UNREAD_LAST_SEL, 0,
                COL_BOOL_IS_DRAFT, folder_is_drafts,
+               COL_STRING_FOLDER_URI, uri,
                -1);
 
+       em_folder_tree_model_update_row_tweaks (model, iter);
+
        g_free (uri);
        uri = NULL;
 
@@ -1948,3 +2022,45 @@ em_folder_tree_model_user_marked_unread (EMFolderTreeModel *model,
                COL_UINT_UNREAD_LAST_SEL, unread,
                COL_UINT_UNREAD, unread, -1);
 }
+
+void
+em_folder_tree_model_update_row_tweaks (EMFolderTreeModel *model,
+                                       GtkTreeIter *iter)
+{
+       GIcon *custom_icon = NULL;
+       GdkRGBA *foreground = NULL, rgba;
+       gchar *folder_uri = NULL, *icon_filename;
+
+       g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model));
+       g_return_if_fail (iter != NULL);
+
+       gtk_tree_model_get (GTK_TREE_MODEL (model), iter,
+               COL_STRING_FOLDER_URI, &folder_uri,
+               -1);
+
+       if (!folder_uri)
+               return;
+
+       if (e_mail_folder_tweaks_get_color (model->priv->folder_tweaks, folder_uri, &rgba))
+               foreground = &rgba;
+
+       icon_filename = e_mail_folder_tweaks_dup_icon_filename (model->priv->folder_tweaks, folder_uri);
+       if (icon_filename &&
+           g_file_test (icon_filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+               GFile *file;
+
+               file = g_file_new_for_path (icon_filename);
+               custom_icon = g_file_icon_new (file);
+
+               g_clear_object (&file);
+       }
+
+       gtk_tree_store_set (GTK_TREE_STORE (model), iter,
+               COL_GICON_CUSTOM_ICON, custom_icon,
+               COL_RGBA_FOREGROUND_RGBA, foreground,
+               -1);
+
+       g_clear_object (&custom_icon);
+       g_free (icon_filename);
+       g_free (folder_uri);
+}
diff --git a/src/mail/em-folder-tree-model.h b/src/mail/em-folder-tree-model.h
index 325e3a5ad8..0d9c5b99cf 100644
--- a/src/mail/em-folder-tree-model.h
+++ b/src/mail/em-folder-tree-model.h
@@ -27,6 +27,8 @@
 
 #include <libemail-engine/libemail-engine.h>
 
+#include <mail/e-mail-folder-tweaks.h>
+
 /* Standard GObject macros */
 #define EM_TYPE_FOLDER_TREE_MODEL \
        (em_folder_tree_model_get_type ())
@@ -57,7 +59,7 @@ enum {
        COL_OBJECT_CAMEL_STORE,         /* CamelStore object */
        COL_STRING_FULL_NAME,           /* if node is a folder, the full path
                                         * name of the folder, no leading / */
-       COL_STRING_ICON_NAME,           /* icon name for the folder */
+       COL_STRING_ICON_NAME,           /* icon name for the folder, see COL_GICON_CUSTOM_ICON */
        COL_UINT_UNREAD,                /* unread count */
        COL_UINT_FLAGS,                 /* FolderInfo.flags */
 
@@ -75,6 +77,10 @@ enum {
        COL_STATUS_SPINNER_PULSE,
        COL_STATUS_SPINNER_VISIBLE,
 
+       COL_STRING_FOLDER_URI,          /* folder URI */
+       COL_GICON_CUSTOM_ICON,          /* a custom icon to use for the folder; NULL to use 
COL_STRING_ICON_NAME */
+       COL_RGBA_FOREGROUND_RGBA,       /* GdkRGBA for the foreground color; can be NULL */
+
        NUM_COLUMNS
 };
 
@@ -102,6 +108,9 @@ EMFolderTreeModel *
 EMFolderTreeModel *
                em_folder_tree_model_get_default (void);
 void           em_folder_tree_model_free_default (void);
+EMailFolderTweaks *
+               em_folder_tree_model_get_folder_tweaks
+                                               (EMFolderTreeModel *model);
 GtkTreeSelection *
                em_folder_tree_model_get_selection
                                        (EMFolderTreeModel *model);
@@ -146,6 +155,9 @@ void                em_folder_tree_model_user_marked_unread
                                        (EMFolderTreeModel *model,
                                         CamelFolder *folder,
                                         guint n_marked);
+void           em_folder_tree_model_update_row_tweaks
+                                       (EMFolderTreeModel *model,
+                                        GtkTreeIter *iter);
 
 G_END_DECLS
 
diff --git a/src/mail/em-folder-tree.c b/src/mail/em-folder-tree.c
index 3a9dd2eacf..9dc305c700 100644
--- a/src/mail/em-folder-tree.c
+++ b/src/mail/em-folder-tree.c
@@ -893,15 +893,13 @@ folder_tree_render_icon (GtkTreeViewColumn *column,
                          GtkTreeIter *iter)
 {
        GtkTreeSelection *selection;
-       GtkTreePath *drag_dest_row;
        GtkWidget *tree_view;
-       GIcon *icon;
+       GIcon *icon, *custom_icon = NULL;
        guint unread;
        guint old_unread;
        gchar *icon_name;
        gboolean is_selected;
        gboolean is_drafts = FALSE;
-       gboolean is_drag_dest = FALSE;
        gboolean show_new_mail_emblem;
        guint32 fi_flags = 0;
 
@@ -912,29 +910,32 @@ folder_tree_render_icon (GtkTreeViewColumn *column,
                COL_UINT_UNREAD, &unread,
                COL_BOOL_IS_DRAFT, &is_drafts,
                COL_UINT_FLAGS, &fi_flags,
+               COL_GICON_CUSTOM_ICON, &custom_icon,
                -1);
 
-       if (icon_name == NULL)
+       if (!icon_name && !custom_icon)
                return;
 
        tree_view = gtk_tree_view_column_get_tree_view (column);
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
        is_selected = gtk_tree_selection_iter_is_selected (selection, iter);
 
-       gtk_tree_view_get_drag_dest_row (
-               GTK_TREE_VIEW (tree_view), &drag_dest_row, NULL);
-       if (drag_dest_row != NULL) {
-               GtkTreePath *path;
+       if (!custom_icon && g_strcmp0 (icon_name, "folder") == 0) {
+               GtkTreePath *drag_dest_row;
+               gboolean is_drag_dest = FALSE;
 
-               path = gtk_tree_model_get_path (model, iter);
-               if (gtk_tree_path_compare (path, drag_dest_row) == 0)
-                       is_drag_dest = TRUE;
-               gtk_tree_path_free (path);
+               gtk_tree_view_get_drag_dest_row (GTK_TREE_VIEW (tree_view), &drag_dest_row, NULL);
+               if (drag_dest_row != NULL) {
+                       GtkTreePath *path;
 
-               gtk_tree_path_free (drag_dest_row);
-       }
+                       path = gtk_tree_model_get_path (model, iter);
+                       if (gtk_tree_path_compare (path, drag_dest_row) == 0)
+                               is_drag_dest = TRUE;
+                       gtk_tree_path_free (path);
+
+                       gtk_tree_path_free (drag_dest_row);
+               }
 
-       if (g_strcmp0 (icon_name, "folder") == 0) {
                if (is_selected) {
                        g_free (icon_name);
                        icon_name = g_strdup ("folder-open");
@@ -944,7 +945,10 @@ folder_tree_render_icon (GtkTreeViewColumn *column,
                }
        }
 
-       icon = g_themed_icon_new (icon_name);
+       if (custom_icon)
+               icon = g_object_ref (custom_icon);
+       else
+               icon = g_themed_icon_new (icon_name);
 
        show_new_mail_emblem =
                (unread > old_unread) &&
@@ -969,6 +973,7 @@ folder_tree_render_icon (GtkTreeViewColumn *column,
 
        g_object_set (renderer, "gicon", icon, NULL);
 
+       g_clear_object (&custom_icon);
        g_object_unref (icon);
        g_free (icon_name);
 }
@@ -1333,6 +1338,8 @@ folder_tree_constructed (GObject *object)
        renderer = priv->text_renderer;
        g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
        gtk_tree_view_column_pack_start (column, renderer, TRUE);
+       gtk_tree_view_column_add_attribute (
+               column, renderer, "foreground-rgba", COL_RGBA_FOREGROUND_RGBA);
        gtk_tree_view_column_set_cell_data_func (
                column, renderer, (GtkTreeCellDataFunc)
                folder_tree_render_display_name, NULL, NULL);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]