No issues found
1 /*
2 * e-web-view-preview.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 *
17 *
18 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19 *
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include "e-web-view-preview.h"
27
28 #include <string.h>
29 #include <glib/gi18n-lib.h>
30
31 #define E_WEB_VIEW_PREVIEW_GET_PRIVATE(obj) \
32 (G_TYPE_INSTANCE_GET_PRIVATE \
33 ((obj), E_TYPE_WEB_VIEW_PREVIEW, EWebViewPreviewPrivate))
34
35 struct _EWebViewPreviewPrivate {
36 gboolean escape_values;
37 GString *updating_content; /* is NULL when not between begin_update/end_update */
38 };
39
40 enum {
41 PROP_0,
42 PROP_TREE_VIEW,
43 PROP_PREVIEW_WIDGET,
44 PROP_ESCAPE_VALUES
45 };
46
47 G_DEFINE_TYPE (
48 EWebViewPreview,
49 e_web_view_preview,
50 GTK_TYPE_VPANED);
51
52 static void
53 web_view_preview_set_property (GObject *object,
54 guint property_id,
55 const GValue *value,
56 GParamSpec *pspec)
57 {
58 switch (property_id) {
59 case PROP_ESCAPE_VALUES:
60 e_web_view_preview_set_escape_values (
61 E_WEB_VIEW_PREVIEW (object),
62 g_value_get_boolean (value));
63 return;
64 }
65
66 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
67 }
68
69 static void
70 web_view_preview_get_property (GObject *object,
71 guint property_id,
72 GValue *value,
73 GParamSpec *pspec)
74 {
75 switch (property_id) {
76 case PROP_TREE_VIEW:
77 g_value_set_object (
78 value, e_web_view_preview_get_tree_view (
79 E_WEB_VIEW_PREVIEW (object)));
80 return;
81
82 case PROP_PREVIEW_WIDGET:
83 g_value_set_object (
84 value, e_web_view_preview_get_preview (
85 E_WEB_VIEW_PREVIEW (object)));
86 return;
87
88 case PROP_ESCAPE_VALUES:
89 g_value_set_boolean (
90 value, e_web_view_preview_get_escape_values (
91 E_WEB_VIEW_PREVIEW (object)));
92 return;
93 }
94
95 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
96 }
97
98 static void
99 web_view_preview_dispose (GObject *object)
100 {
101 EWebViewPreviewPrivate *priv;
102
103 priv = E_WEB_VIEW_PREVIEW_GET_PRIVATE (object);
104
105 if (priv->updating_content != NULL) {
106 g_string_free (priv->updating_content, TRUE);
107 priv->updating_content = NULL;
108 }
109
110 /* Chain up to parent's dispose() method. */
111 G_OBJECT_CLASS (e_web_view_preview_parent_class)->dispose (object);
112 }
113
114 static void
115 e_web_view_preview_class_init (EWebViewPreviewClass *class)
116 {
117 GObjectClass *object_class;
118
119 g_type_class_add_private (class, sizeof (EWebViewPreviewPrivate));
120
121 object_class = G_OBJECT_CLASS (class);
122 object_class->set_property = web_view_preview_set_property;
123 object_class->get_property = web_view_preview_get_property;
124 object_class->dispose = web_view_preview_dispose;
125
126 g_object_class_install_property (
127 object_class,
128 PROP_TREE_VIEW,
129 g_param_spec_object (
130 "tree-view",
131 "Tree View",
132 NULL,
133 GTK_TYPE_TREE_VIEW,
134 G_PARAM_READABLE));
135
136 g_object_class_install_property (
137 object_class,
138 PROP_PREVIEW_WIDGET,
139 g_param_spec_object (
140 "preview-widget",
141 "Preview Widget",
142 NULL,
143 GTK_TYPE_WIDGET,
144 G_PARAM_READABLE));
145
146 g_object_class_install_property (
147 object_class,
148 PROP_ESCAPE_VALUES,
149 g_param_spec_boolean (
150 "escape-values",
151 "Whether escaping values automatically, when inserting",
152 NULL,
153 TRUE,
154 G_PARAM_READWRITE));
155 }
156
157 static GtkWidget *
158 in_scrolled_window (GtkWidget *widget)
159 {
160 GtkWidget *sw;
161
162 g_return_val_if_fail (widget != NULL, NULL);
163
164 sw = gtk_scrolled_window_new (NULL, NULL);
165 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
166 gtk_container_add (GTK_CONTAINER (sw), widget);
167
168 gtk_widget_show (widget);
169 gtk_widget_show (sw);
170
171 return sw;
172 }
173
174 static void
175 e_web_view_preview_init (EWebViewPreview *preview)
176 {
177 GtkWidget *tree_view_sw, *web_view_sw;
178
179 preview->priv = E_WEB_VIEW_PREVIEW_GET_PRIVATE (preview);
180 preview->priv->escape_values = TRUE;
181
182 tree_view_sw = in_scrolled_window (gtk_tree_view_new ());
183 web_view_sw = in_scrolled_window (e_web_view_new ());
184
185 gtk_widget_hide (tree_view_sw);
186 gtk_widget_show (web_view_sw);
187
188 gtk_paned_pack1 (GTK_PANED (preview), tree_view_sw, FALSE, TRUE);
189 gtk_paned_pack2 (GTK_PANED (preview), web_view_sw, TRUE, TRUE);
190
191 /* rawly 3 lines of a text plus a little bit more */
192 if (gtk_paned_get_position (GTK_PANED (preview)) < 85)
193 gtk_paned_set_position (GTK_PANED (preview), 85);
194 }
195
196 GtkWidget *
197 e_web_view_preview_new (void)
198 {
199 return g_object_new (E_TYPE_WEB_VIEW_PREVIEW, NULL);
200 }
201
202 GtkTreeView *
203 e_web_view_preview_get_tree_view (EWebViewPreview *preview)
204 {
205 g_return_val_if_fail (preview != NULL, NULL);
206 g_return_val_if_fail (E_IS_WEB_VIEW_PREVIEW (preview), NULL);
207
208 return GTK_TREE_VIEW (gtk_bin_get_child (GTK_BIN (gtk_paned_get_child1 (GTK_PANED (preview)))));
209 }
210
211 GtkWidget *
212 e_web_view_preview_get_preview (EWebViewPreview *preview)
213 {
214 g_return_val_if_fail (preview != NULL, NULL);
215 g_return_val_if_fail (E_IS_WEB_VIEW_PREVIEW (preview), NULL);
216
217 return gtk_bin_get_child (GTK_BIN (gtk_paned_get_child2 (GTK_PANED (preview))));
218 }
219
220 void
221 e_web_view_preview_set_preview (EWebViewPreview *preview,
222 GtkWidget *preview_widget)
223 {
224 GtkWidget *old_child;
225
226 g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview));
227 g_return_if_fail (GTK_IS_WIDGET (preview_widget));
228
229 old_child = gtk_bin_get_child (GTK_BIN (gtk_paned_get_child2 (GTK_PANED (preview))));
230 if (old_child) {
231 g_return_if_fail (old_child != preview_widget);
232 gtk_widget_destroy (old_child);
233 }
234
235 gtk_container_add (GTK_CONTAINER (gtk_paned_get_child2 (GTK_PANED (preview))), preview_widget);
236 }
237
238 void
239 e_web_view_preview_show_tree_view (EWebViewPreview *preview)
240 {
241 g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview));
242
243 gtk_widget_show (gtk_paned_get_child1 (GTK_PANED (preview)));
244 }
245
246 void
247 e_web_view_preview_hide_tree_view (EWebViewPreview *preview)
248 {
249 g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview));
250
251 gtk_widget_hide (gtk_paned_get_child1 (GTK_PANED (preview)));
252 }
253
254 void
255 e_web_view_preview_set_escape_values (EWebViewPreview *preview,
256 gboolean escape)
257 {
258 g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview));
259
260 preview->priv->escape_values = escape;
261 }
262
263 gboolean
264 e_web_view_preview_get_escape_values (EWebViewPreview *preview)
265 {
266 g_return_val_if_fail (preview != NULL, FALSE);
267 g_return_val_if_fail (E_IS_WEB_VIEW_PREVIEW (preview), FALSE);
268 g_return_val_if_fail (preview->priv != NULL, FALSE);
269
270 return preview->priv->escape_values;
271 }
272
273 void
274 e_web_view_preview_begin_update (EWebViewPreview *preview)
275 {
276 g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview));
277
278 if (preview->priv->updating_content) {
279 g_warning ("%s: Previous content update isn't finished with e_web_view_preview_end_update()", G_STRFUNC);
280 g_string_free (preview->priv->updating_content, TRUE);
281 }
282
283 preview->priv->updating_content = g_string_new ("<TABLE width=\"100%\" border=\"0\" cols=\"2\">");
284 }
285
286 void
287 e_web_view_preview_end_update (EWebViewPreview *preview)
288 {
289 GtkWidget *web_view;
290
291 g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview));
292 g_return_if_fail (preview->priv->updating_content != NULL);
293
294 g_string_append (preview->priv->updating_content, "</TABLE>");
295
296 web_view = e_web_view_preview_get_preview (preview);
297 if (E_IS_WEB_VIEW (web_view))
298 e_web_view_load_string (E_WEB_VIEW (web_view), preview->priv->updating_content->str);
299
300 g_string_free (preview->priv->updating_content, TRUE);
301 preview->priv->updating_content = NULL;
302 }
303
304 static gchar *
305 replace_string (const gchar *text,
306 const gchar *find,
307 const gchar *replace)
308 {
309 const gchar *p, *next;
310 GString *str;
311 gint find_len;
312
313 g_return_val_if_fail (text != NULL, NULL);
314 g_return_val_if_fail (find != NULL, NULL);
315 g_return_val_if_fail (*find, NULL);
316
317 find_len = strlen (find);
318 str = g_string_new ("");
319
320 p = text;
321 while (next = strstr (p, find), next) {
322 if (p + 1 < next)
323 g_string_append_len (str, p, next - p);
324
325 if (replace && *replace)
326 g_string_append (str, replace);
327
328 p = next + find_len;
329 }
330
331 g_string_append (str, p);
332
333 return g_string_free (str, FALSE);
334 }
335
336 static gchar *
337 web_view_preview_escape_text (EWebViewPreview *preview,
338 const gchar *text)
339 {
340 gchar *utf8_valid, *res, *end;
341
342 if (!e_web_view_preview_get_escape_values (preview))
343 return NULL;
344
345 g_return_val_if_fail (text != NULL, NULL);
346
347 if (g_utf8_validate (text, -1, NULL)) {
348 res = g_markup_escape_text (text, -1);
349 } else {
350 utf8_valid = g_strdup (text);
351 while (end = NULL, !g_utf8_validate (utf8_valid, -1, (const gchar **) &end) && end && *end)
352 *end = '?';
353
354 res = g_markup_escape_text (utf8_valid, -1);
355
356 g_free (utf8_valid);
357 }
358
359 if (res && strchr (res, '\n')) {
360 /* replace line breaks with <BR> */
361 if (strchr (res, '\r')) {
362 end = replace_string (res, "\r", "");
363 g_free (res);
364 res = end;
365 }
366
367 end = replace_string (res, "\n", "<BR>");
368 g_free (res);
369 res = end;
370 }
371
372 return res;
373 }
374
375 void
376 e_web_view_preview_add_header (EWebViewPreview *preview,
377 gint index,
378 const gchar *header)
379 {
380 gchar *escaped;
381
382 g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview));
383 g_return_if_fail (preview->priv->updating_content != NULL);
384 g_return_if_fail (header != NULL);
385
386 if (index < 1)
387 index = 1;
388 else if (index > 6)
389 index = 6;
390
391 escaped = web_view_preview_escape_text (preview, header);
392 if (escaped)
393 header = escaped;
394
395 g_string_append_printf (preview->priv->updating_content, "<TR><TD colspan=2><H%d>%s</H%d></TD></TR>", index, header, index);
396
397 g_free (escaped);
398 }
399
400 void
401 e_web_view_preview_add_text (EWebViewPreview *preview,
402 const gchar *text)
403 {
404 gchar *escaped;
405
406 g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview));
407 g_return_if_fail (preview->priv->updating_content != NULL);
408 g_return_if_fail (text != NULL);
409
410 escaped = web_view_preview_escape_text (preview, text);
411 if (escaped)
412 text = escaped;
413
414 g_string_append_printf (preview->priv->updating_content, "<TR><TD colspan=2><FONT size=\"3\">%s</FONT></TD></TR>", text);
415
416 g_free (escaped);
417 }
418
419 void
420 e_web_view_preview_add_raw_html (EWebViewPreview *preview,
421 const gchar *raw_html)
422 {
423 g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview));
424 g_return_if_fail (preview->priv->updating_content != NULL);
425 g_return_if_fail (raw_html != NULL);
426
427 g_string_append_printf (preview->priv->updating_content, "<TR><TD colspan=2>%s</TD></TR>", raw_html);
428 }
429
430 void
431 e_web_view_preview_add_separator (EWebViewPreview *preview)
432 {
433 g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview));
434 g_return_if_fail (preview->priv->updating_content != NULL);
435
436 g_string_append (preview->priv->updating_content, "<TR><TD colspan=2><HR></TD></TR>");
437 }
438
439 void
440 e_web_view_preview_add_empty_line (EWebViewPreview *preview)
441 {
442 g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview));
443 g_return_if_fail (preview->priv->updating_content != NULL);
444
445 g_string_append (preview->priv->updating_content, "<TR><TD colspan=2> </TD></TR>");
446 }
447
448 /* section can be NULL, but value cannot */
449 void
450 e_web_view_preview_add_section (EWebViewPreview *preview,
451 const gchar *section,
452 const gchar *value)
453 {
454 gchar *escaped_section = NULL, *escaped_value;
455
456 g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview));
457 g_return_if_fail (preview->priv->updating_content != NULL);
458 g_return_if_fail (value != NULL);
459
460 if (section) {
461 escaped_section = web_view_preview_escape_text (preview, section);
462 if (escaped_section)
463 section = escaped_section;
464 }
465
466 escaped_value = web_view_preview_escape_text (preview, value);
467 if (escaped_value)
468 value = escaped_value;
469
470 g_string_append_printf (preview->priv->updating_content, "<TR><TD width=\"10%%\" valign=\"top\" nowrap><FONT size=\"3\"><B>%s</B></FONT></TD><TD width=\"90%%\"><FONT size=\"3\">%s</FONT></TD></TR>", section ? section : "", value);
471
472 g_free (escaped_section);
473 g_free (escaped_value);
474 }