1 /*
2  * e-html-editor-cell-dialog.c
3  *
4  * Copyright (C) 2012 Dan Vrátil <dvratil@redhat.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) version 3.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with the program; if not, see <http://www.gnu.org/licenses/>
18  *
19  */
20 
21 #include "evolution-config.h"
22 
23 #include "e-html-editor-cell-dialog.h"
24 
25 #include <glib/gi18n-lib.h>
26 #include <stdlib.h>
27 
28 #include "e-color-combo.h"
29 #include "e-dialog-widgets.h"
30 #include "e-image-chooser-dialog.h"
31 #include "e-misc-utils.h"
32 
33 #define E_HTML_EDITOR_CELL_DIALOG_GET_PRIVATE(obj) \
34 	(G_TYPE_INSTANCE_GET_PRIVATE \
35 	((obj), E_TYPE_HTML_EDITOR_CELL_DIALOG, EHTMLEditorCellDialogPrivate))
36 
37 struct _EHTMLEditorCellDialogPrivate {
38 	GtkWidget *scope_cell_button;
39 	GtkWidget *scope_table_button;
40 	GtkWidget *scope_row_button;
41 	GtkWidget *scope_column_button;
42 
43 	GtkWidget *halign_combo;
44 	GtkWidget *valign_combo;
45 
46 	GtkWidget *wrap_text_check;
47 	GtkWidget *header_style_check;
48 
49 	GtkWidget *width_check;
50 	GtkWidget *width_edit;
51 	GtkWidget *width_units;
52 
53 	GtkWidget *row_span_edit;
54 	GtkWidget *col_span_edit;
55 
56 	GtkWidget *background_color_picker;
57 	GtkWidget *background_image_chooser;
58 
59 	GtkWidget *remove_image_button;
60 
61 	guint scope;
62 };
63 
64 enum {
65 	SCOPE_CELL,
66 	SCOPE_ROW,
67 	SCOPE_COLUMN,
68 	SCOPE_TABLE
69 } DialogScope;
70 
71 static GdkRGBA transparent = { 0, 0, 0, 0 };
72 
73 G_DEFINE_TYPE (
74 	EHTMLEditorCellDialog,
75 	e_html_editor_cell_dialog,
76 	E_TYPE_HTML_EDITOR_DIALOG);
77 
78 static void
html_editor_cell_dialog_set_scope(EHTMLEditorCellDialog * dialog)79 html_editor_cell_dialog_set_scope (EHTMLEditorCellDialog *dialog)
80 {
81 	if (gtk_toggle_button_get_active (
82 		GTK_TOGGLE_BUTTON (dialog->priv->scope_cell_button))) {
83 
84 		dialog->priv->scope = SCOPE_CELL;
85 
86 	} else if (gtk_toggle_button_get_active (
87 		GTK_TOGGLE_BUTTON (dialog->priv->scope_row_button))) {
88 
89 		dialog->priv->scope = SCOPE_ROW;
90 
91 	} else if (gtk_toggle_button_get_active (
92 		GTK_TOGGLE_BUTTON (dialog->priv->scope_column_button))) {
93 
94 		dialog->priv->scope = SCOPE_COLUMN;
95 
96 	} else if (gtk_toggle_button_get_active (
97 		GTK_TOGGLE_BUTTON (dialog->priv->scope_table_button))) {
98 
99 		dialog->priv->scope = SCOPE_TABLE;
100 
101 	}
102 }
103 
104 static  void
html_editor_cell_dialog_set_valign(EHTMLEditorCellDialog * dialog)105 html_editor_cell_dialog_set_valign (EHTMLEditorCellDialog *dialog)
106 {
107 	EHTMLEditor *editor;
108 	EContentEditor *cnt_editor;
109 
110 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
111 	cnt_editor = e_html_editor_get_content_editor (editor);
112 
113 	e_content_editor_cell_set_v_align (
114 		cnt_editor,
115 		gtk_combo_box_get_active_id (
116 			GTK_COMBO_BOX (dialog->priv->valign_combo)),
117 		dialog->priv->scope);
118 }
119 
120 static void
html_editor_cell_dialog_set_halign(EHTMLEditorCellDialog * dialog)121 html_editor_cell_dialog_set_halign (EHTMLEditorCellDialog *dialog)
122 {
123 	EHTMLEditor *editor;
124 	EContentEditor *cnt_editor;
125 
126 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
127 	cnt_editor = e_html_editor_get_content_editor (editor);
128 
129 	e_content_editor_cell_set_align (
130 		cnt_editor,
131 		gtk_combo_box_get_active_id (
132 			GTK_COMBO_BOX (dialog->priv->halign_combo)),
133 		dialog->priv->scope);
134 }
135 
136 static void
html_editor_cell_dialog_set_wrap_text(EHTMLEditorCellDialog * dialog)137 html_editor_cell_dialog_set_wrap_text (EHTMLEditorCellDialog *dialog)
138 {
139 	EHTMLEditor *editor;
140 	EContentEditor *cnt_editor;
141 
142 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
143 	cnt_editor = e_html_editor_get_content_editor (editor);
144 
145 	e_content_editor_cell_set_wrap (
146 		cnt_editor,
147 		gtk_toggle_button_get_active (
148 			GTK_TOGGLE_BUTTON (dialog->priv->wrap_text_check)),
149 		dialog->priv->scope);
150 }
151 
152 static void
html_editor_cell_dialog_set_header_style(EHTMLEditorCellDialog * dialog)153 html_editor_cell_dialog_set_header_style (EHTMLEditorCellDialog *dialog)
154 {
155 	EHTMLEditor *editor;
156 	EContentEditor *cnt_editor;
157 
158 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
159 	cnt_editor = e_html_editor_get_content_editor (editor);
160 
161 	e_content_editor_cell_set_header_style (
162 		cnt_editor,
163 		gtk_toggle_button_get_active (
164 			GTK_TOGGLE_BUTTON (dialog->priv->header_style_check)),
165 		dialog->priv->scope);
166 }
167 
168 static void
html_editor_cell_dialog_set_width(EHTMLEditorCellDialog * dialog)169 html_editor_cell_dialog_set_width (EHTMLEditorCellDialog *dialog)
170 {
171 	EHTMLEditor *editor;
172 	EContentEditor *cnt_editor;
173 
174 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
175 	cnt_editor = e_html_editor_get_content_editor (editor);
176 
177 	if (gtk_toggle_button_get_active (
178 		GTK_TOGGLE_BUTTON (dialog->priv->width_check))) {
179 
180 		e_content_editor_cell_set_width (
181 			cnt_editor,
182 			gtk_spin_button_get_value_as_int (
183 				GTK_SPIN_BUTTON (dialog->priv->width_edit)),
184 			(gtk_combo_box_get_active (
185 				GTK_COMBO_BOX (dialog->priv->width_units)) == 0) ?
186 					E_CONTENT_EDITOR_UNIT_PIXEL :
187 					E_CONTENT_EDITOR_UNIT_PERCENTAGE,
188 			dialog->priv->scope);
189 	} else
190 		e_content_editor_cell_set_width (
191 			cnt_editor, 0, E_CONTENT_EDITOR_UNIT_AUTO, dialog->priv->scope);
192 }
193 
194 static void
html_editor_cell_dialog_width_units_changed(GtkWidget * widget,EHTMLEditorCellDialog * dialog)195 html_editor_cell_dialog_width_units_changed (GtkWidget *widget,
196                                              EHTMLEditorCellDialog *dialog)
197 {
198 	if (gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->width_units)) == 0) {
199 		gtk_spin_button_set_range (
200 			GTK_SPIN_BUTTON (dialog->priv->width_edit), 0, G_MAXUINT);
201 	} else
202 		gtk_spin_button_set_range (
203 			GTK_SPIN_BUTTON (dialog->priv->width_edit), 0, 100);
204 
205 	html_editor_cell_dialog_set_width (dialog);
206 }
207 
208 static void
html_editor_cell_dialog_set_column_span(EHTMLEditorCellDialog * dialog)209 html_editor_cell_dialog_set_column_span (EHTMLEditorCellDialog *dialog)
210 {
211 	EHTMLEditor *editor;
212 	EContentEditor *cnt_editor;
213 
214 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
215 	cnt_editor = e_html_editor_get_content_editor (editor);
216 
217 	e_content_editor_cell_set_col_span (
218 		cnt_editor,
219 		gtk_spin_button_get_value_as_int (
220 			GTK_SPIN_BUTTON (dialog->priv->col_span_edit)),
221 		dialog->priv->scope);
222 }
223 
224 static void
html_editor_cell_dialog_set_row_span(EHTMLEditorCellDialog * dialog)225 html_editor_cell_dialog_set_row_span (EHTMLEditorCellDialog *dialog)
226 {
227 	EHTMLEditor *editor;
228 	EContentEditor *cnt_editor;
229 
230 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
231 	cnt_editor = e_html_editor_get_content_editor (editor);
232 
233 	e_content_editor_cell_set_row_span (
234 		cnt_editor,
235 		gtk_spin_button_get_value_as_int (
236 			GTK_SPIN_BUTTON (dialog->priv->row_span_edit)),
237 		dialog->priv->scope);
238 }
239 
240 static void
html_editor_cell_dialog_set_background_color(EHTMLEditorCellDialog * dialog)241 html_editor_cell_dialog_set_background_color (EHTMLEditorCellDialog *dialog)
242 {
243 	EHTMLEditor *editor;
244 	EContentEditor *cnt_editor;
245 	GdkRGBA rgba;
246 
247 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
248 	cnt_editor = e_html_editor_get_content_editor (editor);
249 
250 	e_color_combo_get_current_color (
251 		E_COLOR_COMBO (dialog->priv->background_color_picker), &rgba);
252 	e_content_editor_cell_set_background_color (cnt_editor, &rgba, dialog->priv->scope);
253 }
254 
255 static void
html_editor_cell_dialog_set_background_image(EHTMLEditorCellDialog * dialog)256 html_editor_cell_dialog_set_background_image (EHTMLEditorCellDialog *dialog)
257 {
258 	EHTMLEditor *editor;
259 	EContentEditor *cnt_editor;
260 	gchar *uri;
261 
262 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
263 	cnt_editor = e_html_editor_get_content_editor (editor);
264 
265 	uri = gtk_file_chooser_get_uri (
266 		GTK_FILE_CHOOSER (dialog->priv->background_image_chooser));
267 
268 	e_content_editor_cell_set_background_image_uri (cnt_editor, uri);
269 
270 	gtk_widget_set_sensitive (dialog->priv->remove_image_button, uri && *uri);
271 
272 	g_free (uri);
273 }
274 
275 static void
html_editor_cell_dialog_remove_image(EHTMLEditorCellDialog * dialog)276 html_editor_cell_dialog_remove_image (EHTMLEditorCellDialog *dialog)
277 {
278 	EHTMLEditor *editor;
279 	EContentEditor *cnt_editor;
280 
281 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
282 	cnt_editor = e_html_editor_get_content_editor (editor);
283 
284 	e_content_editor_cell_set_background_image_uri (cnt_editor, NULL);
285 
286 	gtk_file_chooser_unselect_all (
287 		GTK_FILE_CHOOSER (dialog->priv->background_image_chooser));
288 
289 	gtk_widget_set_sensitive (dialog->priv->remove_image_button, FALSE);
290 }
291 
292 static void
html_editor_cell_dialog_show(GtkWidget * widget)293 html_editor_cell_dialog_show (GtkWidget *widget)
294 {
295 	EHTMLEditor *editor;
296 	EContentEditor *cnt_editor;
297 	EContentEditorUnit unit;
298 	EHTMLEditorCellDialog *dialog;
299 	GdkRGBA rgba;
300 	gchar *alignment, *uri;
301 	gint width;
302 
303 	dialog = E_HTML_EDITOR_CELL_DIALOG (widget);
304 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
305 	cnt_editor = e_html_editor_get_content_editor (editor);
306 
307 	e_content_editor_on_dialog_open (cnt_editor, E_CONTENT_EDITOR_DIALOG_CELL);
308 
309 	gtk_toggle_button_set_active (
310 		GTK_TOGGLE_BUTTON (dialog->priv->scope_cell_button), TRUE);
311 
312 	alignment = e_content_editor_cell_get_align (cnt_editor);
313 	gtk_combo_box_set_active_id (
314 		GTK_COMBO_BOX (dialog->priv->halign_combo),
315 		(alignment && *alignment) ? alignment : "left");
316 	g_free (alignment);
317 
318 	alignment = e_content_editor_cell_get_v_align (cnt_editor);
319 	gtk_combo_box_set_active_id (
320 		GTK_COMBO_BOX (dialog->priv->valign_combo),
321 		(alignment && *alignment) ? alignment : "middle");
322 	g_free (alignment);
323 
324 	gtk_toggle_button_set_active (
325 		GTK_TOGGLE_BUTTON (dialog->priv->wrap_text_check),
326 		e_content_editor_cell_get_wrap (cnt_editor));
327 
328 	gtk_toggle_button_set_active (
329 		GTK_TOGGLE_BUTTON (dialog->priv->header_style_check),
330 		e_content_editor_cell_is_header (cnt_editor));
331 
332 	width = e_content_editor_cell_get_width (cnt_editor, &unit);
333 	gtk_spin_button_set_value (
334 		GTK_SPIN_BUTTON (dialog->priv->width_edit), width);
335 	gtk_toggle_button_set_active (
336 		GTK_TOGGLE_BUTTON (dialog->priv->width_check),
337 		unit != E_CONTENT_EDITOR_UNIT_AUTO);
338 	gtk_combo_box_set_active_id (
339 		GTK_COMBO_BOX (dialog->priv->width_units),
340 		(unit == E_CONTENT_EDITOR_UNIT_PIXEL) ? "units-px" : "units-percent");
341 
342 	gtk_spin_button_set_value (
343 		GTK_SPIN_BUTTON (dialog->priv->row_span_edit),
344 		e_content_editor_cell_get_row_span (cnt_editor));
345 
346 	gtk_spin_button_set_value (
347 		GTK_SPIN_BUTTON (dialog->priv->col_span_edit),
348 		e_content_editor_cell_get_col_span (cnt_editor));
349 
350 	uri = e_content_editor_cell_get_background_image_uri (cnt_editor);
351 	if (uri && *uri)
352 		gtk_file_chooser_set_uri (
353 			GTK_FILE_CHOOSER (dialog->priv->background_image_chooser), uri);
354 	else
355 		gtk_file_chooser_unselect_all (
356 			GTK_FILE_CHOOSER (dialog->priv->background_image_chooser));
357 	g_free (uri);
358 
359 	e_content_editor_cell_get_background_color (cnt_editor, &rgba);
360 	e_color_combo_set_current_color (
361 		E_COLOR_COMBO (dialog->priv->background_color_picker), &rgba);
362 
363 	GTK_WIDGET_CLASS (e_html_editor_cell_dialog_parent_class)->show (widget);
364 }
365 
366 static void
html_editor_cell_dialog_hide(GtkWidget * widget)367 html_editor_cell_dialog_hide (GtkWidget *widget)
368 {
369 	EHTMLEditor *editor;
370 	EHTMLEditorCellDialog *dialog;
371 	EContentEditor *cnt_editor;
372 
373 	dialog = E_HTML_EDITOR_CELL_DIALOG (widget);
374 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
375 	cnt_editor = e_html_editor_get_content_editor (editor);
376 
377 	e_content_editor_on_dialog_close (cnt_editor, E_CONTENT_EDITOR_DIALOG_CELL);
378 
379 	GTK_WIDGET_CLASS (e_html_editor_cell_dialog_parent_class)->hide (widget);
380 }
381 
382 static void
e_html_editor_cell_dialog_class_init(EHTMLEditorCellDialogClass * class)383 e_html_editor_cell_dialog_class_init (EHTMLEditorCellDialogClass *class)
384 {
385 	GtkWidgetClass *widget_class;
386 
387 	g_type_class_add_private (class, sizeof (EHTMLEditorCellDialogPrivate));
388 
389 	widget_class = GTK_WIDGET_CLASS (class);
390 	widget_class->show = html_editor_cell_dialog_show;
391 	widget_class->hide = html_editor_cell_dialog_hide;
392 }
393 
394 static void
e_html_editor_cell_dialog_init(EHTMLEditorCellDialog * dialog)395 e_html_editor_cell_dialog_init (EHTMLEditorCellDialog *dialog)
396 {
397 	GtkBox *box;
398 	GtkGrid *main_layout, *grid;
399 	GtkWidget *widget;
400 	GtkFileFilter *file_filter;
401 
402 	dialog->priv = E_HTML_EDITOR_CELL_DIALOG_GET_PRIVATE (dialog);
403 
404 	main_layout = e_html_editor_dialog_get_container (E_HTML_EDITOR_DIALOG (dialog));
405 
406 	/* == Scope == */
407 	widget = gtk_label_new ("");
408 	gtk_label_set_markup (GTK_LABEL (widget), _("<b>Scope</b>"));
409 	gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
410 	gtk_grid_attach (main_layout, widget, 0, 0, 1, 1);
411 
412 	grid = GTK_GRID (gtk_grid_new ());
413 	gtk_grid_set_row_spacing (grid, 5);
414 	gtk_grid_set_column_spacing (grid, 5);
415 	gtk_grid_attach (main_layout, GTK_WIDGET (grid), 0, 1, 1, 1);
416 	gtk_widget_set_margin_left (GTK_WIDGET (grid), 10);
417 
418 	/* Scope: cell */
419 	widget = gtk_image_new_from_icon_name ("stock_select-cell", GTK_ICON_SIZE_BUTTON);
420 	gtk_grid_attach (grid, widget, 0, 0, 1, 1);
421 
422 	widget = gtk_radio_button_new_with_mnemonic (NULL, _("C_ell"));
423 	gtk_grid_attach (grid, widget, 1, 0, 1, 1);
424 	dialog->priv->scope_cell_button = widget;
425 
426 	g_signal_connect_swapped (
427 		widget, "toggled",
428 		G_CALLBACK (html_editor_cell_dialog_set_scope), dialog);
429 
430 	/* Scope: row */
431 	widget = gtk_image_new_from_icon_name ("stock_select-row", GTK_ICON_SIZE_BUTTON);
432 	gtk_grid_attach (grid, widget, 2, 0, 1, 1);
433 
434 	widget = gtk_radio_button_new_with_mnemonic_from_widget (
435 		GTK_RADIO_BUTTON (dialog->priv->scope_cell_button), _("_Row"));
436 	gtk_grid_attach (grid, widget, 3, 0, 1, 1);
437 	dialog->priv->scope_row_button = widget;
438 
439 	g_signal_connect_swapped (
440 		widget, "toggled",
441 		G_CALLBACK (html_editor_cell_dialog_set_scope), dialog);
442 
443 	/* Scope: table */
444 	widget = gtk_image_new_from_icon_name ("stock_select-table", GTK_ICON_SIZE_BUTTON);
445 	gtk_grid_attach (grid, widget, 0, 1, 1, 1);
446 
447 	widget = gtk_radio_button_new_with_mnemonic_from_widget (
448 		GTK_RADIO_BUTTON (dialog->priv->scope_cell_button), _("_Table"));
449 	gtk_grid_attach (grid, widget, 1, 1, 1, 1);
450 	dialog->priv->scope_table_button = widget;
451 
452 	g_signal_connect_swapped (
453 		widget, "toggled",
454 		G_CALLBACK (html_editor_cell_dialog_set_scope), dialog);
455 
456 	/* Scope: column */
457 	widget = gtk_image_new_from_icon_name ("stock_select-column", GTK_ICON_SIZE_BUTTON);
458 	gtk_grid_attach (grid, widget, 2, 1, 1, 1);
459 
460 	widget = gtk_radio_button_new_with_mnemonic_from_widget (
461 		GTK_RADIO_BUTTON (dialog->priv->scope_cell_button), _("Col_umn"));
462 	gtk_grid_attach (grid, widget, 3, 1, 1, 1);
463 	dialog->priv->scope_column_button = widget;
464 
465 	g_signal_connect_swapped (
466 		widget, "toggled",
467 		G_CALLBACK (html_editor_cell_dialog_set_scope), dialog);
468 
469 	/* == Alignment & Behavior == */
470 	widget = gtk_label_new ("");
471 	gtk_label_set_markup (GTK_LABEL (widget), _("<b>Alignment &amp; Behavior</b>"));
472 	gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
473 	gtk_grid_attach (main_layout, widget, 0, 2, 1, 1);
474 
475 	grid = GTK_GRID (gtk_grid_new ());
476 	gtk_grid_set_row_spacing (grid, 5);
477 	gtk_grid_set_column_spacing (grid, 5);
478 	gtk_grid_attach (main_layout, GTK_WIDGET (grid), 0, 3, 1, 1);
479 	gtk_widget_set_margin_left (GTK_WIDGET (grid), 10);
480 
481 	/* Horizontal */
482 	widget = gtk_combo_box_text_new ();
483 	gtk_widget_set_hexpand (widget, TRUE);
484 	gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "left", _("Left"));
485 	gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "center", _("Center"));
486 	gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "right", _("Right"));
487 	gtk_grid_attach (grid, widget, 1, 0, 1, 1);
488 	dialog->priv->halign_combo = widget;
489 
490 	g_signal_connect_swapped (
491 		widget, "changed",
492 		G_CALLBACK (html_editor_cell_dialog_set_halign), dialog);
493 
494 	widget = gtk_label_new_with_mnemonic (_("_Horizontal:"));
495 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
496 	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), dialog->priv->halign_combo);
497 	gtk_grid_attach (grid, widget, 0, 0, 1, 1);
498 
499 	/* Vertical */
500 	widget = gtk_combo_box_text_new ();
501 	gtk_widget_set_hexpand (widget, TRUE);
502 	gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "top", _("Top"));
503 	gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "middle", _("Middle"));
504 	gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "bottom", _("Bottom"));
505 	gtk_grid_attach (grid, widget, 3, 0, 1, 1);
506 	dialog->priv->valign_combo = widget;
507 
508 	g_signal_connect_swapped (
509 		widget, "changed",
510 		G_CALLBACK (html_editor_cell_dialog_set_valign), dialog);
511 
512 	widget = gtk_label_new_with_mnemonic (_("_Vertical:"));
513 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
514 	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), dialog->priv->valign_combo);
515 	gtk_grid_attach (grid, widget, 2, 0, 1, 1);
516 
517 	/* Wrap Text */
518 	widget = gtk_check_button_new_with_mnemonic (_("_Wrap Text"));
519 	dialog->priv->wrap_text_check = widget;
520 
521 	g_signal_connect_swapped (
522 		widget, "toggled",
523 		G_CALLBACK (html_editor_cell_dialog_set_wrap_text), dialog);
524 
525 	/* Header Style */
526 	widget = gtk_check_button_new_with_mnemonic (_("_Header Style"));
527 	dialog->priv->header_style_check = widget;
528 
529 	g_signal_connect_swapped (
530 		widget, "toggled",
531 		G_CALLBACK (html_editor_cell_dialog_set_header_style), dialog);
532 
533 	widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
534 	gtk_box_pack_start (GTK_BOX (widget), dialog->priv->wrap_text_check, FALSE, FALSE, 0);
535 	gtk_box_pack_start (GTK_BOX (widget), dialog->priv->header_style_check, FALSE, FALSE, 0);
536 	gtk_grid_attach (grid, widget, 0, 1, 4, 1);
537 
538 	/* == Layout == */
539 	widget = gtk_label_new ("");
540 	gtk_label_set_markup (GTK_LABEL (widget), _("<b>Layout</b>"));
541 	gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
542 	gtk_grid_attach (main_layout, widget, 0, 4, 1, 1);
543 
544 	grid = GTK_GRID (gtk_grid_new ());
545 	gtk_grid_set_row_spacing (grid, 5);
546 	gtk_grid_set_column_spacing (grid, 5);
547 	gtk_grid_attach (main_layout, GTK_WIDGET (grid), 0, 5, 1, 1);
548 	gtk_widget_set_margin_left (GTK_WIDGET (grid), 10);
549 
550 	/* Width */
551 	widget = gtk_check_button_new_with_mnemonic (_("_Width"));
552 	gtk_grid_attach (grid, widget, 0, 0, 1, 1);
553 	dialog->priv->width_check = widget;
554 
555 	widget = gtk_spin_button_new_with_range (1, 100, 1);
556 	gtk_spin_button_set_digits (GTK_SPIN_BUTTON (widget), 0);
557 	gtk_grid_attach (grid, widget, 1, 0, 1, 1);
558 	dialog->priv->width_edit = widget;
559 
560 	g_signal_connect_swapped (
561 		widget, "value-changed",
562 		G_CALLBACK (html_editor_cell_dialog_set_width), dialog);
563 	e_binding_bind_property (
564 		dialog->priv->width_check, "active",
565 		widget, "sensitive",
566 		G_BINDING_SYNC_CREATE);
567 
568 	widget = gtk_combo_box_text_new ();
569 	gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "units-px", "px");
570 	gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "units-percent", "%");
571 	gtk_grid_attach (grid, widget, 2, 0, 1, 1);
572 	dialog->priv->width_units = widget;
573 
574 	g_signal_connect (
575 		widget, "changed",
576 		G_CALLBACK (html_editor_cell_dialog_width_units_changed), dialog);
577 	e_binding_bind_property (
578 		dialog->priv->width_check, "active",
579 		widget, "sensitive",
580 		G_BINDING_SYNC_CREATE);
581 
582 	/* Row Span */
583 	widget = gtk_spin_button_new_with_range (0, G_MAXUINT, 1);
584 	gtk_grid_attach (grid, widget, 4, 0, 1, 1);
585 	dialog->priv->row_span_edit = widget;
586 
587 	g_signal_connect_swapped (
588 		widget, "value-changed",
589 		G_CALLBACK (html_editor_cell_dialog_set_row_span), dialog);
590 
591 	widget = gtk_label_new_with_mnemonic (_("Row S_pan:"));
592 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
593 	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), dialog->priv->row_span_edit);
594 	gtk_grid_attach (grid, widget, 3, 0, 1, 1);
595 
596 	/* Column Span */
597 	widget = gtk_spin_button_new_with_range (0, G_MAXUINT, 1);
598 	gtk_grid_attach (grid, widget, 4, 1, 1, 1);
599 	dialog->priv->col_span_edit = widget;
600 
601 	g_signal_connect_swapped (
602 		widget, "value-changed",
603 		G_CALLBACK (html_editor_cell_dialog_set_column_span), dialog);
604 
605 	widget = gtk_label_new_with_mnemonic (_("Co_lumn Span:"));
606 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
607 	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), dialog->priv->col_span_edit);
608 	gtk_grid_attach (grid, widget, 3, 1, 1, 1);
609 
610 	/* == Background == */
611 	widget = gtk_label_new ("");
612 	gtk_label_set_markup (GTK_LABEL (widget), _("<b>Background</b>"));
613 	gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
614 	gtk_grid_attach (main_layout, widget, 0, 6, 1, 1);
615 
616 	grid = GTK_GRID (gtk_grid_new ());
617 	gtk_grid_set_row_spacing (grid, 5);
618 	gtk_grid_set_column_spacing (grid, 5);
619 	gtk_grid_attach (main_layout, GTK_WIDGET (grid), 0, 7, 1, 1);
620 	gtk_widget_set_margin_left (GTK_WIDGET (grid), 10);
621 
622 	/* Color */
623 	widget = e_color_combo_new ();
624 	e_color_combo_set_default_color (E_COLOR_COMBO (widget), &transparent);
625 	e_color_combo_set_default_label (E_COLOR_COMBO (widget), _("Transparent"));
626 	gtk_widget_set_hexpand (widget, TRUE);
627 	gtk_grid_attach (grid, widget, 1, 0, 1, 1);
628 	g_signal_connect_swapped (
629 		widget, "notify::current-color",
630 		G_CALLBACK (html_editor_cell_dialog_set_background_color), dialog);
631 	dialog->priv->background_color_picker = widget;
632 
633 	widget = gtk_label_new_with_mnemonic (_("C_olor:"));
634 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
635 	gtk_label_set_mnemonic_widget (
636 		GTK_LABEL (widget), dialog->priv->background_color_picker);
637 	gtk_grid_attach (grid, widget, 0, 0, 1, 1);
638 
639 	file_filter = gtk_file_filter_new ();
640 	gtk_file_filter_set_name (file_filter, _("Images"));
641 	gtk_file_filter_add_mime_type (file_filter, "image/*");
642 
643 	/* Image */
644 	if (e_util_is_running_flatpak ()) {
645 		widget = gtk_file_chooser_button_new (_("Choose Background Image"), GTK_FILE_CHOOSER_ACTION_OPEN);
646 	} else {
647 		widget = e_image_chooser_dialog_new (
648 				_("Choose Background Image"),
649 				GTK_WINDOW (dialog));
650 
651 		widget = gtk_file_chooser_button_new_with_dialog (widget);
652 	}
653 
654 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (widget), file_filter);
655 	gtk_widget_set_hexpand (widget, TRUE);
656 	gtk_grid_attach (grid, widget, 1, 1, 1, 1);
657 	g_signal_connect_swapped (
658 		widget, "file-set",
659 		G_CALLBACK (html_editor_cell_dialog_set_background_image), dialog);
660 	dialog->priv->background_image_chooser = widget;
661 
662 	widget =gtk_label_new_with_mnemonic (_("_Image:"));
663 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
664 	gtk_label_set_mnemonic_widget (
665 		GTK_LABEL (widget), dialog->priv->background_image_chooser);
666 	gtk_grid_attach (grid, widget, 0, 1, 1, 1);
667 
668 	box = e_html_editor_dialog_get_button_box (E_HTML_EDITOR_DIALOG (dialog));
669 	widget = e_dialog_button_new_with_icon (NULL, _("_Remove image"));
670 	g_signal_connect_swapped (
671 		widget, "clicked",
672 		G_CALLBACK (html_editor_cell_dialog_remove_image), dialog);
673 	dialog->priv->remove_image_button = widget;
674 
675 	gtk_widget_set_sensitive (dialog->priv->remove_image_button, FALSE);
676 	gtk_box_pack_start (box, widget, FALSE, FALSE, 5);
677 	gtk_box_reorder_child (box, widget, 0);
678 
679 	gtk_widget_show_all (GTK_WIDGET (main_layout));
680 }
681 
682 GtkWidget *
e_html_editor_cell_dialog_new(EHTMLEditor * editor)683 e_html_editor_cell_dialog_new (EHTMLEditor *editor)
684 {
685 	return GTK_WIDGET (
686 		g_object_new (
687 			E_TYPE_HTML_EDITOR_CELL_DIALOG,
688 			"editor", editor,
689 			"title", _("Cell Properties"),
690 			NULL));
691 }
692