evolution-3.6.4/modules/mail/em-composer-prefs.c

No issues found

  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *		Jeffrey Stedfast <fejj@ximian.com>
 18  *
 19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 20  *
 21  */
 22 
 23 #ifdef HAVE_CONFIG_H
 24 #include <config.h>
 25 #endif
 26 
 27 #include "em-composer-prefs.h"
 28 
 29 #include <string.h>
 30 #include <sys/types.h>
 31 #include <sys/stat.h>
 32 #include <unistd.h>
 33 #include <fcntl.h>
 34 
 35 #include <glib/gi18n.h>
 36 #include <glib/gstdio.h>
 37 
 38 #include <gtkhtml/gtkhtml.h>
 39 #include <editor/gtkhtml-spell-language.h>
 40 
 41 #include <e-util/e-util.h>
 42 #include <e-util/e-util-private.h>
 43 
 44 #include <composer/e-msg-composer.h>
 45 
 46 #include <shell/e-shell-utils.h>
 47 
 48 #include <misc/e-charset-combo-box.h>
 49 #include <misc/e-mail-signature-manager.h>
 50 
 51 #include <mail/em-config.h>
 52 #include <mail/em-folder-selection-button.h>
 53 #include <mail/e-mail-junk-options.h>
 54 
 55 G_DEFINE_TYPE (
 56 	EMComposerPrefs,
 57 	em_composer_prefs,
 58 	GTK_TYPE_VBOX)
 59 
 60 static gboolean
 61 transform_old_to_new_reply_style (GBinding *binding,
 62                                   const GValue *source_value,
 63                                   GValue *target_value,
 64                                   gpointer user_data)
 65 {
 66 	gboolean success = TRUE;
 67 
 68 	/* XXX This is the kind of legacy crap we wind up
 69 	 *     with when we don't migrate things properly. */
 70 
 71 	switch (g_value_get_int (source_value)) {
 72 		case 0:  /* Quoted: 0 -> 2 */
 73 			g_value_set_int (target_value, 2);
 74 			break;
 75 
 76 		case 1:  /* Do Not Quote: 1 -> 3 */
 77 			g_value_set_int (target_value, 3);
 78 			break;
 79 
 80 		case 2:  /* Attach: 2 -> 0 */
 81 			g_value_set_int (target_value, 0);
 82 			break;
 83 
 84 		case 3:  /* Outlook: 3 -> 1 */
 85 			g_value_set_int (target_value, 1);
 86 			break;
 87 
 88 		default:
 89 			success = FALSE;
 90 			break;
 91 	}
 92 
 93 	return success;
 94 }
 95 
 96 static gboolean
 97 transform_new_to_old_reply_style (GBinding *binding,
 98                                   const GValue *source_value,
 99                                   GValue *target_value,
100                                   gpointer user_data)
101 {
102 	gboolean success = TRUE;
103 
104 	/* XXX This is the kind of legacy crap we wind up
105 	 *     with when we don't migrate things properly. */
106 
107 	switch (g_value_get_int (source_value)) {
108 		case 0:  /* Attach: 0 -> 2 */
109 			g_value_set_int (target_value, 2);
110 			break;
111 
112 		case 1:  /* Outlook: 1 -> 3 */
113 			g_value_set_int (target_value, 3);
114 			break;
115 
116 		case 2:  /* Quoted: 2 -> 0 */
117 			g_value_set_int (target_value, 0);
118 			break;
119 
120 		case 3:  /* Do Not Quote: 3 -> 1 */
121 			g_value_set_int (target_value, 1);
122 			break;
123 
124 		default:
125 			success = FALSE;
126 			break;
127 	}
128 
129 	return success;
130 }
131 
132 static void
133 composer_prefs_dispose (GObject *object)
134 {
135 	EMComposerPrefs *prefs = (EMComposerPrefs *) object;
136 
137 	if (prefs->builder != NULL) {
138 		g_object_unref (prefs->builder);
139 		prefs->builder = NULL;
140 	}
141 
142 	/* Chain up to parent's dispose() method. */
143 	G_OBJECT_CLASS (em_composer_prefs_parent_class)->dispose (object);
144 }
145 
146 static void
147 em_composer_prefs_class_init (EMComposerPrefsClass *class)
148 {
149 	GObjectClass *object_class;
150 
151 	object_class = G_OBJECT_CLASS (class);
152 	object_class->dispose = composer_prefs_dispose;
153 }
154 
155 static void
156 em_composer_prefs_init (EMComposerPrefs *prefs)
157 {
158 }
159 
160 static void
161 spell_language_toggled_cb (GtkCellRendererToggle *renderer,
162                            const gchar *path_string,
163                            EMComposerPrefs *prefs)
164 {
165 	GtkTreeModel *model;
166 	GtkTreePath *path;
167 	GtkTreeIter iter;
168 	gboolean active;
169 	gboolean valid;
170 
171 	model = prefs->language_model;
172 
173 	/* Convert the path string to a tree iterator. */
174 	path = gtk_tree_path_new_from_string (path_string);
175 	valid = gtk_tree_model_get_iter (model, &iter, path);
176 	gtk_tree_path_free (path);
177 	g_return_if_fail (valid);
178 
179 	/* Toggle the active state. */
180 	gtk_tree_model_get (model, &iter, 0, &active, -1);
181 	gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, !active, -1);
182 }
183 
184 static void
185 spell_language_save (EMComposerPrefs *prefs)
186 {
187 	GList *spell_languages = NULL;
188 	GtkTreeModel *model;
189 	GtkTreeIter iter;
190 	gboolean valid;
191 
192 	model = prefs->language_model;
193 
194 	/* Build a list of active spell languages. */
195 	valid = gtk_tree_model_get_iter_first (model, &iter);
196 	while (valid) {
197 		const GtkhtmlSpellLanguage *language;
198 		gboolean active;
199 
200 		gtk_tree_model_get (
201 			model, &iter, 0, &active, 2, &language, -1);
202 
203 		if (active)
204 			spell_languages = g_list_prepend (
205 				spell_languages, (gpointer) language);
206 
207 		valid = gtk_tree_model_iter_next (model, &iter);
208 	}
209 	spell_languages = g_list_reverse (spell_languages);
210 
211 	/* Update the GSettings value. */
212 	e_save_spell_languages (spell_languages);
213 
214 	g_list_free (spell_languages);
215 }
216 
217 static void
218 spell_setup (EMComposerPrefs *prefs)
219 {
220 	const GList *available_languages;
221 	GList *active_languages;
222 	GtkListStore *store;
223 
224 	store = GTK_LIST_STORE (prefs->language_model);
225 	available_languages = gtkhtml_spell_language_get_available ();
226 
227 	active_languages = e_load_spell_languages ();
228 
229 	/* Populate the GtkListStore. */
230 	while (available_languages != NULL) {
231 		const GtkhtmlSpellLanguage *language;
232 		GtkTreeIter tree_iter;
233 		const gchar *name;
234 		gboolean active;
235 
236 		language = available_languages->data;
237 		name = gtkhtml_spell_language_get_name (language);
238 		active = (g_list_find (active_languages, language) != NULL);
239 
240 		gtk_list_store_append (store, &tree_iter);
241 
242 		gtk_list_store_set (
243 			store, &tree_iter,
244 			0, active, 1, name, 2, language, -1);
245 
246 		available_languages = available_languages->next;
247 	}
248 
249 	g_list_free (active_languages);
250 }
251 
252 static GtkWidget *
253 emcp_widget_glade (EConfig *ec,
254                    EConfigItem *item,
255                    GtkWidget *parent,
256                    GtkWidget *old,
257                    gint position,
258                    gpointer data)
259 {
260 	EMComposerPrefs *prefs = data;
261 
262 	return e_builder_get_widget (prefs->builder, item->label);
263 }
264 
265 /* plugin meta-data */
266 static EMConfigItem emcp_items[] = {
267 
268 	{ E_CONFIG_BOOK,
269 	  (gchar *) "",
270 	  (gchar *) "composer_toplevel",
271 	  emcp_widget_glade },
272 
273 	{ E_CONFIG_PAGE,
274 	  (gchar *) "00.general",
275 	  (gchar *) "vboxComposerGeneral",
276 	  emcp_widget_glade },
277 
278 	{ E_CONFIG_SECTION,
279 	  (gchar *) "00.general/00.behavior",
280 	  (gchar *) "default-behavior-vbox",
281 	  emcp_widget_glade },
282 
283 	{ E_CONFIG_PAGE,
284 	  (gchar *) "10.signatures",
285 	  (gchar *) "vboxSignatures",
286 	  emcp_widget_glade },
287 
288 	/* signature/signatures and signature/preview parts not usable */
289 
290 	{ E_CONFIG_PAGE,
291 	  (gchar *) "20.spellcheck",
292 	  (gchar *) "vboxSpellChecking",
293 	  emcp_widget_glade }
294 };
295 
296 static void
297 emcp_free (EConfig *ec,
298            GSList *items,
299            gpointer data)
300 {
301 	/* the prefs data is freed automagically */
302 	g_slist_free (items);
303 }
304 
305 static void
306 em_composer_prefs_construct (EMComposerPrefs *prefs,
307                              EShell *shell)
308 {
309 	GtkWidget *toplevel, *widget, *info_pixmap;
310 	GtkWidget *container;
311 	EShellSettings *shell_settings;
312 	ESourceRegistry *registry;
313 	GtkTreeView *view;
314 	GtkListStore *store;
315 	GtkTreeSelection *selection;
316 	GtkCellRenderer *renderer;
317 	EMConfig *ec;
318 	EMConfigTargetPrefs *target;
319 	GSList *l;
320 	gint i;
321 
322 	registry = e_shell_get_registry (shell);
323 	shell_settings = e_shell_get_shell_settings (shell);
324 
325 	/* Make sure our custom widget classes are registered with
326 	 * GType before we load the GtkBuilder definition file. */
327 	E_TYPE_MAIL_JUNK_OPTIONS;
328 	EM_TYPE_FOLDER_SELECTION_BUTTON;
329 
330 	prefs->builder = gtk_builder_new ();
331 	e_load_ui_builder_definition (prefs->builder, "mail-config.ui");
332 
333 	/** @HookPoint-EMConfig: Mail Composer Preferences
334 	 * @Id: org.gnome.evolution.mail.composerPrefs
335 	 * @Type: E_CONFIG_BOOK
336 	 * @Class: org.gnome.evolution.mail.config:1.0
337 	 * @Target: EMConfigTargetPrefs
338 	 *
339 	 * The mail composer preferences settings page.
340 	 */
341 	ec = em_config_new (E_CONFIG_BOOK, "org.gnome.evolution.mail.composerPrefs");
342 	l = NULL;
343 	for (i = 0; i < G_N_ELEMENTS (emcp_items); i++)
344 		l = g_slist_prepend (l, &emcp_items[i]);
345 	e_config_add_items ((EConfig *) ec, l, emcp_free, prefs);
346 
347 	/* General tab */
348 
349 	/* Default Behavior */
350 
351 	/* Express mode does not honor this setting. */
352 	widget = e_builder_get_widget (prefs->builder, "chkSendHTML");
353 	if (e_shell_get_express_mode (shell))
354 		gtk_widget_hide (widget);
355 	else
356 		g_object_bind_property (
357 			shell_settings, "composer-format-html",
358 			widget, "active",
359 			G_BINDING_BIDIRECTIONAL |
360 			G_BINDING_SYNC_CREATE);
361 
362 	widget = e_builder_get_widget (prefs->builder, "chkPromptEmptySubject");
363 	g_object_bind_property (
364 		shell_settings, "composer-prompt-empty-subject",
365 		widget, "active",
366 		G_BINDING_BIDIRECTIONAL |
367 		G_BINDING_SYNC_CREATE);
368 
369 	widget = e_builder_get_widget (prefs->builder, "chkPromptBccOnly");
370 	g_object_bind_property (
371 		shell_settings, "composer-prompt-only-bcc",
372 		widget, "active",
373 		G_BINDING_BIDIRECTIONAL |
374 		G_BINDING_SYNC_CREATE);
375 
376 	widget = e_builder_get_widget (prefs->builder, "chkPromptPrivateListReply");
377 	g_object_bind_property (
378 		shell_settings, "composer-prompt-private-list-reply",
379 		widget, "active",
380 		G_BINDING_BIDIRECTIONAL |
381 		G_BINDING_SYNC_CREATE);
382 
383 	widget = e_builder_get_widget (prefs->builder, "chkPromptReplyManyRecips");
384 	g_object_bind_property (
385 		shell_settings, "composer-prompt-reply-many-recips",
386 		widget, "active",
387 		G_BINDING_BIDIRECTIONAL |
388 		G_BINDING_SYNC_CREATE);
389 
390 	widget = e_builder_get_widget (prefs->builder, "chkPromptListReplyTo");
391 	g_object_bind_property (
392 		shell_settings, "composer-prompt-list-reply-to",
393 		widget, "active",
394 		G_BINDING_BIDIRECTIONAL |
395 		G_BINDING_SYNC_CREATE);
396 
397 	widget = e_builder_get_widget (prefs->builder, "chkPromptSendInvalidRecip");
398 	g_object_bind_property (
399 		shell_settings, "composer-prompt-send-invalid-recip",
400 		widget, "active",
401 		G_BINDING_BIDIRECTIONAL |
402 		G_BINDING_SYNC_CREATE);
403 
404 	widget = e_builder_get_widget (prefs->builder, "chkAutoSmileys");
405 	g_object_bind_property (
406 		shell_settings, "composer-magic-smileys",
407 		widget, "active",
408 		G_BINDING_BIDIRECTIONAL |
409 		G_BINDING_SYNC_CREATE);
410 
411 	widget = e_builder_get_widget (prefs->builder, "chkRequestReceipt");
412 	g_object_bind_property (
413 		shell_settings, "composer-request-receipt",
414 		widget, "active",
415 		G_BINDING_BIDIRECTIONAL |
416 		G_BINDING_SYNC_CREATE);
417 
418 	widget = e_builder_get_widget (prefs->builder, "chkReplyStartBottom");
419 	g_object_bind_property (
420 		shell_settings, "composer-reply-start-bottom",
421 		widget, "active",
422 		G_BINDING_BIDIRECTIONAL |
423 		G_BINDING_SYNC_CREATE);
424 
425 	widget = e_builder_get_widget (prefs->builder, "chkOutlookFilenames");
426 	g_object_bind_property (
427 		shell_settings, "composer-outlook-filenames",
428 		widget, "active",
429 		G_BINDING_BIDIRECTIONAL |
430 		G_BINDING_SYNC_CREATE);
431 
432 	widget = e_builder_get_widget (prefs->builder, "chkIgnoreListReplyTo");
433 	g_object_bind_property (
434 		shell_settings, "composer-ignore-list-reply-to",
435 		widget, "active",
436 		G_BINDING_BIDIRECTIONAL |
437 		G_BINDING_SYNC_CREATE);
438 
439 	widget = e_builder_get_widget (prefs->builder, "chkGroupReplyToList");
440 	g_object_bind_property (
441 		shell_settings, "composer-group-reply-to-list",
442 		widget, "active",
443 		G_BINDING_BIDIRECTIONAL |
444 		G_BINDING_SYNC_CREATE);
445 
446 	widget = e_builder_get_widget (prefs->builder, "chkSignReplyIfSigned");
447 	g_object_bind_property (
448 		shell_settings, "composer-sign-reply-if-signed",
449 		widget, "active",
450 		G_BINDING_BIDIRECTIONAL |
451 		G_BINDING_SYNC_CREATE);
452 
453 	widget = e_builder_get_widget (prefs->builder, "chkTopSignature");
454 	g_object_bind_property (
455 		shell_settings, "composer-top-signature",
456 		widget, "active",
457 		G_BINDING_BIDIRECTIONAL |
458 		G_BINDING_SYNC_CREATE);
459 
460 	widget = e_builder_get_widget (prefs->builder, "chkEnableSpellChecking");
461 	g_object_bind_property (
462 		shell_settings, "composer-inline-spelling",
463 		widget, "active",
464 		G_BINDING_BIDIRECTIONAL |
465 		G_BINDING_SYNC_CREATE);
466 
467 	widget = e_charset_combo_box_new ();
468 	container = e_builder_get_widget (prefs->builder, "hboxComposerCharset");
469 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
470 	gtk_widget_show (widget);
471 	g_object_bind_property (
472 		shell_settings, "composer-charset",
473 		widget, "charset",
474 		G_BINDING_BIDIRECTIONAL |
475 		G_BINDING_SYNC_CREATE);
476 
477 	container = e_builder_get_widget (prefs->builder, "lblCharset");
478 	gtk_label_set_mnemonic_widget (GTK_LABEL (container), widget);
479 
480 	/* Spell Checking */
481 	widget = e_builder_get_widget (prefs->builder, "listSpellCheckLanguage");
482 	view = GTK_TREE_VIEW (widget);
483 	store = gtk_list_store_new (
484 		3, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER);
485 	g_signal_connect_swapped (
486 		store, "row-changed",
487 		G_CALLBACK (spell_language_save), prefs);
488 	prefs->language_model = GTK_TREE_MODEL (store);
489 	gtk_tree_view_set_model (view, prefs->language_model);
490 	renderer = gtk_cell_renderer_toggle_new ();
491 	g_signal_connect (
492 		renderer, "toggled",
493 		G_CALLBACK (spell_language_toggled_cb), prefs);
494 	gtk_tree_view_insert_column_with_attributes (
495 		view, -1, _("Enabled"),
496 		renderer, "active", 0, NULL);
497 
498 	gtk_tree_view_insert_column_with_attributes (
499 		view, -1, _("Language(s)"),
500 		gtk_cell_renderer_text_new (),
501 		"text", 1, NULL);
502 	selection = gtk_tree_view_get_selection (view);
503 	gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
504 	info_pixmap = e_builder_get_widget (prefs->builder, "pixmapSpellInfo");
505 	gtk_image_set_from_stock (
506 		GTK_IMAGE (info_pixmap),
507 		GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_BUTTON);
508 
509 	widget = e_builder_get_widget (prefs->builder, "colorButtonSpellCheckColor");
510 	g_object_bind_property_full (
511 		shell_settings, "composer-spell-color",
512 		widget, "color",
513 		G_BINDING_BIDIRECTIONAL |
514 		G_BINDING_SYNC_CREATE,
515 		e_binding_transform_string_to_color,
516 		e_binding_transform_color_to_string,
517 		NULL, (GDestroyNotify) NULL);
518 
519 	spell_setup (prefs);
520 
521 	/* Forwards and Replies */
522 	widget = e_builder_get_widget (prefs->builder, "comboboxForwardStyle");
523 	g_object_bind_property (
524 		shell_settings, "mail-forward-style",
525 		widget, "active",
526 		G_BINDING_BIDIRECTIONAL |
527 		G_BINDING_SYNC_CREATE);
528 
529 	widget = e_builder_get_widget (prefs->builder, "comboboxReplyStyle");
530 	g_object_bind_property_full (
531 		shell_settings, "mail-reply-style",
532 		widget, "active",
533 		G_BINDING_BIDIRECTIONAL |
534 		G_BINDING_SYNC_CREATE,
535 		transform_old_to_new_reply_style,
536 		transform_new_to_old_reply_style,
537 		NULL, (GDestroyNotify) NULL);
538 
539 	/* Signatures */
540 	container = e_builder_get_widget (
541 		prefs->builder, "signature-alignment");
542 	widget = e_mail_signature_manager_new (registry);
543 	gtk_container_add (GTK_CONTAINER (container), widget);
544 	gtk_widget_show (widget);
545 
546 	/* The mail shell backend responds to the "window-added" signal
547 	 * that this triggers and configures it with composer preferences. */
548 	g_signal_connect_swapped (
549 		widget, "editor-created",
550 		G_CALLBACK (gtk_application_add_window), shell);
551 
552 	/* Express mode does not honor this setting. */
553 	if (!e_shell_get_express_mode (shell))
554 		g_object_bind_property (
555 			shell_settings, "composer-format-html",
556 			widget, "prefer-html",
557 			G_BINDING_SYNC_CREATE);
558 
559 	/* Sanitize the dialog for Express mode */
560 	e_shell_hide_widgets_for_express_mode (
561 		shell, prefs->builder,
562 		"chkOutlookFilenames",
563 		"chkTopSignature",
564 		NULL);
565 
566 	/* get our toplevel widget */
567 	target = em_config_target_new_prefs (ec);
568 	e_config_set_target ((EConfig *) ec, (EConfigTarget *) target);
569 	toplevel = e_config_create_widget ((EConfig *) ec);
570 	gtk_container_add (GTK_CONTAINER (prefs), toplevel);
571 }
572 
573 GtkWidget *
574 em_composer_prefs_new (EPreferencesWindow *window)
575 {
576 	EShell *shell;
577 	EMComposerPrefs *prefs;
578 
579 	shell = e_preferences_window_get_shell (window);
580 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
581 
582 	prefs = g_object_new (EM_TYPE_COMPOSER_PREFS, NULL);
583 	em_composer_prefs_construct (prefs, shell);
584 
585 	return GTK_WIDGET (prefs);
586 }