aboutsummaryrefslogblamecommitdiffstats
path: root/mail/e-mail-display.c
blob: aa3c4bd3d22d24798765d711727624944f6706d0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14













                                                                    
                                                                             





                                                        



                    

                           


                          


                                   
 





                                
                      


                             
 


                          

                                                
                                       






                                                      


            



                                          
                                        

                                         
                                                














                                                






                                                       









                                      





                                                            
                           
                        
 
                                                            





































                                                            
















                                                                       














                                                                       
                                             
























                                                                       
                                             




                                                                            
                                                             

 
           




                                              
                                               









                                                                        


                                                  
 

                                                          

 
               

                                                     








                                                                   









                                                                      

                                                          
                                                   






                            





                                            
                                           















                                                                   
                                                                   



                                                                   
                                                                    
                                                              






                                                                              
                            



                                                                               


                                                           
                                                                     
 

                                                                            









                                                                    

                                                                        



           



                                                  
                                      












                                                                       
 

                                                               
                                                                     
 
                                            
                                                               
                                                             









                                            




                                         
                           

                                     

                             
                                        
 

                                                                   
 



                                                                        
 

                                                             






                                                                     
                                                          


                                                                       





















                                                                 
                                                                        




                    





















                                                                 
/*
 * e-mail-display.c
 *
 * This program 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; either
 * version 2 of the License, or (at your option) version 3.
 *
 * This program 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 the program; if not, see <http://www.gnu.org/licenses/>
 *
 *
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "e-mail-display.h"

#include <glib/gi18n.h>

#include "e-util/e-util.h"
#include "e-util/e-plugin-ui.h"
#include "mail/em-composer-utils.h"
#include "mail/em-utils.h"

struct _EMailDisplayPrivate {
    EMFormatHTML *formatter;
};

enum {
    PROP_0,
    PROP_FORMATTER
};

static gpointer parent_class;

static const gchar *ui =
"<ui>"
"  <popup name='context'>"
"    <placeholder name='custom-actions-1'>"
"      <menuitem action='add-to-address-book'/>"
"      <menuitem action='send-reply'/>"
"    </placeholder>"
"    <placeholder name='custom-actions-3'>"
"      <menu action='search-folder-menu'>"
"        <menuitem action='search-folder-recipient'/>"
"        <menuitem action='search-folder-sender'/>"
"      </menu>"
"    </placeholder>"
"  </popup>"
"</ui>";

static GtkActionEntry mailto_entries[] = {

    { "add-to-address-book",
      "contact-new",
      N_("_Add to Address Book..."),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      NULL   /* Handled by EMailReader */ },

    { "search-folder-recipient",
      NULL,
      N_("_To This Address"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      NULL   /* Handled by EMailReader */ },

    { "search-folder-sender",
      NULL,
      N_("_From This Address"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      NULL   /* Handled by EMailReader */ },

    { "send-reply",
      NULL,
      N_("Send _Reply To..."),
      NULL,
      N_("Send a reply message to this address"),  
      NULL   /* Handled by EMailReader */ },

    /*** Menus ***/

    { "search-folder-menu",
      "folder-saved-search",
      N_("Create Search _Folder"),
      NULL,
      NULL,
      NULL }
};

static void
mail_display_update_formatter_colors (EMailDisplay *display)
{
    EMFormatHTMLColorType type;
    EMFormatHTML *formatter;
    GdkColor *color;
    GtkStateType state;
    GtkStyle *style;

    state = gtk_widget_get_state (GTK_WIDGET (display));
    formatter = display->priv->formatter;

    style = gtk_widget_get_style (GTK_WIDGET (display));
    if (style == NULL)
        return;

    g_object_freeze_notify (G_OBJECT (formatter));

    color = &style->bg[state];
    type = EM_FORMAT_HTML_COLOR_BODY;
    em_format_html_set_color (formatter, type, color);

    color = &style->base[GTK_STATE_NORMAL];
    type = EM_FORMAT_HTML_COLOR_CONTENT;
    em_format_html_set_color (formatter, type, color);

    color = &style->dark[state];
    type = EM_FORMAT_HTML_COLOR_FRAME;
    em_format_html_set_color (formatter, type, color);

    color = &style->fg[state];
    type = EM_FORMAT_HTML_COLOR_HEADER;
    em_format_html_set_color (formatter, type, color);

    color = &style->text[state];
    type = EM_FORMAT_HTML_COLOR_TEXT;
    em_format_html_set_color (formatter, type, color);

    g_object_thaw_notify (G_OBJECT (formatter));
}

static void
mail_display_set_property (GObject *object,
                           guint property_id,
                           const GValue *value,
                           GParamSpec *pspec)
{
    switch (property_id) {
        case PROP_FORMATTER:
            e_mail_display_set_formatter (
                E_MAIL_DISPLAY (object),
                g_value_get_object (value));
            return;
    }

    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}

static void
mail_display_get_property (GObject *object,
                           guint property_id,
                           GValue *value,
                           GParamSpec *pspec)
{
    switch (property_id) {
        case PROP_FORMATTER:
            g_value_set_object (
                value, e_mail_display_get_formatter (
                E_MAIL_DISPLAY (object)));
            return;
    }

    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}

static void
mail_display_dispose (GObject *object)
{
    EMailDisplayPrivate *priv;

    priv = E_MAIL_DISPLAY (object)->priv;

    if (priv->formatter) {
        g_object_unref (priv->formatter);
        priv->formatter = NULL;
    }

    /* Chain up to parent's dispose() method. */
    G_OBJECT_CLASS (parent_class)->dispose (object);
}

static void
mail_display_realize (GtkWidget *widget)
{
    /* Chain up to parent's realize() method. */
    GTK_WIDGET_CLASS (parent_class)->realize (widget);

    mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget));
}

static void
mail_display_style_set (GtkWidget *widget,
                        GtkStyle *previous_style)
{
    EMailDisplayPrivate *priv;

    priv = E_MAIL_DISPLAY (widget)->priv;

    /* Chain up to parent's style_set() method. */
    GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);

    mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget));
    em_format_queue_redraw (EM_FORMAT (priv->formatter));
}

static void
mail_display_load_string (EWebView *web_view,
                          const gchar *string)
{
    EMailDisplayPrivate *priv;

    priv = E_MAIL_DISPLAY (web_view)->priv;
    g_return_if_fail (priv->formatter != NULL);

    if (em_format_busy (EM_FORMAT (priv->formatter)))
        return;

    /* Chain up to parent's load_string() method. */
    E_WEB_VIEW_CLASS (parent_class)->load_string (web_view, string);
}

static void
mail_display_url_requested (GtkHTML *html,
                            const gchar *uri,
                            GtkHTMLStream *stream)
{
    /* XXX Sadly, we must block the default method
     *     until EMFormatHTML is made asynchronous. */
}

static gboolean
mail_display_process_mailto (EWebView *web_view,
                             const gchar *mailto_uri)
{
    g_return_val_if_fail (web_view != NULL, FALSE);
    g_return_val_if_fail (mailto_uri != NULL, FALSE);
    g_return_val_if_fail (E_IS_MAIL_DISPLAY (web_view), FALSE);

    if (g_ascii_strncasecmp (mailto_uri, "mailto:", 7) == 0) {
        EMailDisplayPrivate *priv;
        EMFormat *format;
        CamelFolder *folder = NULL;
        EShell *shell;

        priv = E_MAIL_DISPLAY (web_view)->priv;
        g_return_val_if_fail (priv->formatter != NULL, FALSE);

        format = EM_FORMAT (priv->formatter);

        if (format != NULL && format->folder != NULL)
            folder = format->folder;

        shell = e_shell_get_default ();
        em_utils_compose_new_message_with_mailto (
            shell, mailto_uri, folder);

        return TRUE;
    }

    return FALSE;
}

static void
mail_display_link_clicked (GtkHTML *html,
                           const gchar *uri)
{
    EMailDisplayPrivate *priv;

    priv = E_MAIL_DISPLAY (html)->priv;
    g_return_if_fail (priv->formatter != NULL);

    if (g_str_has_prefix (uri, "##")) {
        guint32 flags;

        flags = priv->formatter->header_wrap_flags;

        if (strcmp (uri, "##TO##") == 0) {
            if (!(flags & EM_FORMAT_HTML_HEADER_TO))
                flags |= EM_FORMAT_HTML_HEADER_TO;
            else
                flags &= ~EM_FORMAT_HTML_HEADER_TO;
        } else if (strcmp (uri, "##CC##") == 0) {
            if (!(flags & EM_FORMAT_HTML_HEADER_CC))
                flags |= EM_FORMAT_HTML_HEADER_CC;
            else
                flags &= ~EM_FORMAT_HTML_HEADER_CC;
        } else if (strcmp (uri, "##BCC##") == 0) {
            if (!(flags & EM_FORMAT_HTML_HEADER_BCC))
                flags |= EM_FORMAT_HTML_HEADER_BCC;
            else
                flags &= ~EM_FORMAT_HTML_HEADER_BCC;
        } else if (strcmp (uri, "##HEADERS##") == 0) {
            EMFormatHTMLHeadersState state;

            state = em_format_html_get_headers_state (
                priv->formatter);

            if (state == EM_FORMAT_HTML_HEADERS_STATE_COLLAPSED)
                state = EM_FORMAT_HTML_HEADERS_STATE_EXPANDED;
            else
                state = EM_FORMAT_HTML_HEADERS_STATE_COLLAPSED;

            em_format_html_set_headers_state (
                priv->formatter, state);
        }

        priv->formatter->header_wrap_flags = flags;
        em_format_queue_redraw (EM_FORMAT (priv->formatter));

    } else if (mail_display_process_mailto (E_WEB_VIEW (html), uri)) {
        /* do nothing, function handled the "mailto:" uri already */
    } else if (*uri == '#')
        gtk_html_jump_to_anchor (html, uri + 1);

    else if (g_ascii_strncasecmp (uri, "thismessage:", 12) == 0)
        /* ignore */ ;

    else if (g_ascii_strncasecmp (uri, "cid:", 4) == 0)
        /* ignore */ ;

    else {
        /* Chain up to parent's link_clicked() method. */
        GTK_HTML_CLASS (parent_class)->link_clicked (html, uri);
    }
}

static void
mail_display_class_init (EMailDisplayClass *class)
{
    GObjectClass *object_class;
    GtkWidgetClass *widget_class;
    EWebViewClass *web_view_class;
    GtkHTMLClass *html_class;

    parent_class = g_type_class_peek_parent (class);
    g_type_class_add_private (class, sizeof (EMailDisplayPrivate));

    object_class = G_OBJECT_CLASS (class);
    object_class->set_property = mail_display_set_property;
    object_class->get_property = mail_display_get_property;
    object_class->dispose = mail_display_dispose;

    widget_class = GTK_WIDGET_CLASS (class);
    widget_class->realize = mail_display_realize;
    widget_class->style_set = mail_display_style_set;

    web_view_class = E_WEB_VIEW_CLASS (class);
    web_view_class->load_string = mail_display_load_string;
    web_view_class->process_mailto = mail_display_process_mailto;

    html_class = GTK_HTML_CLASS (class);
    html_class->url_requested = mail_display_url_requested;
    html_class->link_clicked = mail_display_link_clicked;

    g_object_class_install_property (
        object_class,
        PROP_FORMATTER,
        g_param_spec_object (
            "formatter",
            "HTML Formatter",
            NULL,
            EM_TYPE_FORMAT_HTML,
            G_PARAM_READWRITE));
}

static void
mail_display_init (EMailDisplay *display)
{
    EWebView *web_view;
    GtkUIManager *ui_manager;
    GtkActionGroup *action_group;
    GError *error = NULL;

    web_view = E_WEB_VIEW (display);

    display->priv = G_TYPE_INSTANCE_GET_PRIVATE (
        display, E_TYPE_MAIL_DISPLAY, EMailDisplayPrivate);

    /* EWebView's action groups are added during its instance
     * initialization function (like what we're in now), so it
     * is safe to fetch them this early in construction. */
    action_group = e_web_view_get_action_group (web_view, "mailto");

    /* We don't actually handle the actions we're adding.
     * EMailReader handles them.  How devious is that? */
    gtk_action_group_add_actions (
        action_group, mailto_entries,
        G_N_ELEMENTS (mailto_entries), display);

    /* Because we are loading from a hard-coded string, there is
     * no chance of I/O errors.  Failure here implies a malformed
     * UI definition.  Full stop. */
    ui_manager = e_web_view_get_ui_manager (web_view);
    gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
    if (error != NULL)
        g_error ("%s", error->message);
}

GType
e_mail_display_get_type (void)
{
    static GType type = 0;

    if (G_UNLIKELY (type == 0)) {
        static const GTypeInfo type_info = {
            sizeof (EMailDisplayClass),
            (GBaseInitFunc) NULL,
            (GBaseFinalizeFunc) NULL,
            (GClassInitFunc) mail_display_class_init,
            (GClassFinalizeFunc) NULL,
            NULL,  /* class_data */
            sizeof (EMailDisplay),
            0,     /* n_preallocs */
            (GInstanceInitFunc) mail_display_init,
            NULL   /* value_table */
        };

        type = g_type_register_static (
            E_TYPE_WEB_VIEW, "EMailDisplay", &type_info, 0);
    }

    return type;
}

EMFormatHTML *
e_mail_display_get_formatter (EMailDisplay *display)
{
    g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);

    return display->priv->formatter;
}

void
e_mail_display_set_formatter (EMailDisplay *display,
                              EMFormatHTML *formatter)
{
    g_return_if_fail (E_IS_MAIL_DISPLAY (display));
    g_return_if_fail (EM_IS_FORMAT_HTML (formatter));

    if (display->priv->formatter != NULL)
        g_object_unref (display->priv->formatter);

    display->priv->formatter = g_object_ref (formatter);

    g_object_notify (G_OBJECT (display), "formatter");
}