/* * e-web-view-preview.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. * * 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 General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, see . * * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ #ifdef HAVE_CONFIG_H #include #endif #include "e-web-view-preview.h" #include #include #define E_WEB_VIEW_PREVIEW_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), E_TYPE_WEB_VIEW_PREVIEW, EWebViewPreviewPrivate)) struct _EWebViewPreviewPrivate { gboolean escape_values; GString *updating_content; /* is NULL when not between begin_update/end_update */ }; enum { PROP_0, PROP_TREE_VIEW, PROP_PREVIEW_WIDGET, PROP_ESCAPE_VALUES }; G_DEFINE_TYPE ( EWebViewPreview, e_web_view_preview, GTK_TYPE_PANED); static void web_view_preview_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { switch (property_id) { case PROP_ESCAPE_VALUES: e_web_view_preview_set_escape_values ( E_WEB_VIEW_PREVIEW (object), g_value_get_boolean (value)); return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } static void web_view_preview_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { switch (property_id) { case PROP_TREE_VIEW: g_value_set_object ( value, e_web_view_preview_get_tree_view ( E_WEB_VIEW_PREVIEW (object))); return; case PROP_PREVIEW_WIDGET: g_value_set_object ( value, e_web_view_preview_get_preview ( E_WEB_VIEW_PREVIEW (object))); return; case PROP_ESCAPE_VALUES: g_value_set_boolean ( value, e_web_view_preview_get_escape_values ( E_WEB_VIEW_PREVIEW (object))); return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } static void web_view_preview_dispose (GObject *object) { EWebViewPreviewPrivate *priv; priv = E_WEB_VIEW_PREVIEW_GET_PRIVATE (object); if (priv->updating_content != NULL) { g_string_free (priv->updating_content, TRUE); priv->updating_content = NULL; } /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (e_web_view_preview_parent_class)->dispose (object); } static void e_web_view_preview_class_init (EWebViewPreviewClass *class) { GObjectClass *object_class; g_type_class_add_private (class, sizeof (EWebViewPreviewPrivate)); object_class = G_OBJECT_CLASS (class); object_class->set_property = web_view_preview_set_property; object_class->get_property = web_view_preview_get_property; object_class->dispose = web_view_preview_dispose; g_object_class_install_property ( object_class, PROP_TREE_VIEW, g_param_spec_object ( "tree-view", "Tree View", NULL, GTK_TYPE_TREE_VIEW, G_PARAM_READABLE)); g_object_class_install_property ( object_class, PROP_PREVIEW_WIDGET, g_param_spec_object ( "preview-widget", "Preview Widget", NULL, GTK_TYPE_WIDGET, G_PARAM_READABLE)); g_object_class_install_property ( object_class, PROP_ESCAPE_VALUES, g_param_spec_boolean ( "escape-values", "Whether escaping values automatically, when inserting", NULL, TRUE, G_PARAM_READWRITE)); } static GtkWidget * in_scrolled_window (GtkWidget *widget) { GtkWidget *sw; g_return_val_if_fail (widget != NULL, NULL); sw = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add (GTK_CONTAINER (sw), widget); gtk_widget_show (widget); gtk_widget_show (sw); return sw; } static void e_web_view_preview_init (EWebViewPreview *preview) { GtkWidget *tree_view_sw, *web_view_sw; preview->priv = E_WEB_VIEW_PREVIEW_GET_PRIVATE (preview); preview->priv->escape_values = TRUE; gtk_orientable_set_orientation (GTK_ORIENTABLE (preview), GTK_ORIENTATION_VERTICAL); tree_view_sw = in_scrolled_window (gtk_tree_view_new ()); web_view_sw = in_scrolled_window (e_web_view_new ()); gtk_widget_hide (tree_view_sw); gtk_widget_show (web_view_sw); gtk_paned_pack1 (GTK_PANED (preview), tree_view_sw, FALSE, TRUE); gtk_paned_pack2 (GTK_PANED (preview), web_view_sw, TRUE, TRUE); /* rawly 3 lines of a text plus a little bit more */ if (gtk_paned_get_position (GTK_PANED (preview)) < 85) gtk_paned_set_position (GTK_PANED (preview), 85); } GtkWidget * e_web_view_preview_new (void) { return g_object_new (E_TYPE_WEB_VIEW_PREVIEW, NULL); } GtkTreeView * e_web_view_preview_get_tree_view (EWebViewPreview *preview) { g_return_val_if_fail (E_IS_WEB_VIEW_PREVIEW (preview), NULL); return GTK_TREE_VIEW (gtk_bin_get_child (GTK_BIN (gtk_paned_get_child1 (GTK_PANED (preview))))); } GtkWidget * e_web_view_preview_get_preview (EWebViewPreview *preview) { g_return_val_if_fail (E_IS_WEB_VIEW_PREVIEW (preview), NULL); return gtk_bin_get_child (GTK_BIN (gtk_paned_get_child2 (GTK_PANED (preview)))); } void e_web_view_preview_set_preview (EWebViewPreview *preview, GtkWidget *preview_widget) { GtkWidget *old_child; g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview)); g_return_if_fail (GTK_IS_WIDGET (preview_widget)); old_child = gtk_bin_get_child (GTK_BIN (gtk_paned_get_child2 (GTK_PANED (preview)))); if (old_child) { g_return_if_fail (old_child != preview_widget); gtk_widget_destroy (old_child); } gtk_container_add (GTK_CONTAINER (gtk_paned_get_child2 (GTK_PANED (preview))), preview_widget); } void e_web_view_preview_show_tree_view (EWebViewPreview *preview) { g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview)); gtk_widget_show (gtk_paned_get_child1 (GTK_PANED (preview))); } void e_web_view_preview_hide_tree_view (EWebViewPreview *preview) { g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview)); gtk_widget_hide (gtk_paned_get_child1 (GTK_PANED (preview))); } gboolean e_web_view_preview_get_escape_values (EWebViewPreview *preview) { g_return_val_if_fail (E_IS_WEB_VIEW_PREVIEW (preview), FALSE); return preview->priv->escape_values; } void e_web_view_preview_set_escape_values (EWebViewPreview *preview, gboolean escape) { g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview)); preview->priv->escape_values = escape; } void e_web_view_preview_begin_update (EWebViewPreview *preview) { g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview)); if (preview->priv->updating_content) { g_warning ("%s: Previous content update isn't finished with e_web_view_preview_end_update()", G_STRFUNC); g_string_free (preview->priv->updating_content, TRUE); } preview->priv->updating_content = g_string_new (""); } void e_web_view_preview_end_update (EWebViewPreview *preview) { GtkWidget *web_view; g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview)); g_return_if_fail (preview->priv->updating_content != NULL); g_string_append (preview->priv->updating_content, "
"); web_view = e_web_view_preview_get_preview (preview); if (E_IS_WEB_VIEW (web_view)) e_web_view_load_string (E_WEB_VIEW (web_view), preview->priv->updating_content->str); g_string_free (preview->priv->updating_content, TRUE); preview->priv->updating_content = NULL; } static gchar * replace_string (const gchar *text, const gchar *find, const gchar *replace) { const gchar *p, *next; GString *str; gint find_len; g_return_val_if_fail (text != NULL, NULL); g_return_val_if_fail (find != NULL, NULL); g_return_val_if_fail (*find, NULL); find_len = strlen (find); str = g_string_new (""); p = text; while (next = strstr (p, find), next) { if (p + 1 < next) g_string_append_len (str, p, next - p); if (replace && *replace) g_string_append (str, replace); p = next + find_len; } g_string_append (str, p); return g_string_free (str, FALSE); } static gchar * web_view_preview_escape_text (EWebViewPreview *preview, const gchar *text) { gchar *utf8_valid, *res, *end; if (!e_web_view_preview_get_escape_values (preview)) return NULL; g_return_val_if_fail (text != NULL, NULL); if (g_utf8_validate (text, -1, NULL)) { res = g_markup_escape_text (text, -1); } else { utf8_valid = g_strdup (text); while (end = NULL, !g_utf8_validate (utf8_valid, -1, (const gchar **) &end) && end && *end) *end = '?'; res = g_markup_escape_text (utf8_valid, -1); g_free (utf8_valid); } if (res && strchr (res, '\n')) { /* replace line breaks with
*/ if (strchr (res, '\r')) { end = replace_string (res, "\r", ""); g_free (res); res = end; } end = replace_string (res, "\n", "
"); g_free (res); res = end; } return res; } void e_web_view_preview_add_header (EWebViewPreview *preview, gint index, const gchar *header) { gchar *escaped; g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview)); g_return_if_fail (preview->priv->updating_content != NULL); g_return_if_fail (header != NULL); if (index < 1) index = 1; else if (index > 6) index = 6; escaped = web_view_preview_escape_text (preview, header); if (escaped) header = escaped; g_string_append_printf (preview->priv->updating_content, "%s", index, header, index); g_free (escaped); } void e_web_view_preview_add_text (EWebViewPreview *preview, const gchar *text) { gchar *escaped; g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview)); g_return_if_fail (preview->priv->updating_content != NULL); g_return_if_fail (text != NULL); escaped = web_view_preview_escape_text (preview, text); if (escaped) text = escaped; g_string_append_printf (preview->priv->updating_content, "%s", text); g_free (escaped); } void e_web_view_preview_add_raw_html (EWebViewPreview *preview, const gchar *raw_html) { g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview)); g_return_if_fail (preview->priv->updating_content != NULL); g_return_if_fail (raw_html != NULL); g_string_append_printf (preview->priv->updating_content, "%s", raw_html); } void e_web_view_preview_add_separator (EWebViewPreview *preview) { g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview)); g_return_if_fail (preview->priv->updating_content != NULL); g_string_append (preview->priv->updating_content, "
"); } void e_web_view_preview_add_empty_line (EWebViewPreview *preview) { g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview)); g_return_if_fail (preview->priv->updating_content != NULL); g_string_append (preview->priv->updating_content, " "); } /* section can be NULL, but value cannot */ void e_web_view_preview_add_section (EWebViewPreview *preview, const gchar *section, const gchar *value) { gchar *escaped_section = NULL, *escaped_value; g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview)); g_return_if_fail (preview->priv->updating_content != NULL); g_return_if_fail (value != NULL); if (section) { escaped_section = web_view_preview_escape_text (preview, section); if (escaped_section) section = escaped_section; } escaped_value = web_view_preview_escape_text (preview, value); if (escaped_value) value = escaped_value; g_string_append_printf (preview->priv->updating_content, "%s%s", section ? section : "", value); g_free (escaped_section); g_free (escaped_value); }