/*
* 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'/>"
" </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 */ },
/*** 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");
}