1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * pluma-spell-checker-dialog.c
4  * This file is part of pluma
5  *
6  * Copyright (C) 2002 Paolo Maggi
7  * Copyright (C) 2012-2021 MATE Developers
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 
25 /*
26  * Modified by the pluma Team, 2002. See the AUTHORS file for a
27  * list of people on the pluma Team.
28  * See the ChangeLog files for a list of changes.
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34 
35 #include <string.h>
36 #include <glib/gi18n.h>
37 #include <gtk/gtk.h>
38 #include <pluma/pluma-utils.h>
39 #include "pluma-spell-checker-dialog.h"
40 
41 struct _PlumaSpellCheckerDialog
42 {
43 	GtkWindow parent_instance;
44 
45 	PlumaSpellChecker 	*spell_checker;
46 
47 	gchar			*misspelled_word;
48 
49 	GtkWidget 		*misspelled_word_label;
50 	GtkWidget		*word_entry;
51 	GtkWidget		*check_word_button;
52 	GtkWidget		*ignore_button;
53 	GtkWidget		*ignore_all_button;
54 	GtkWidget		*change_button;
55 	GtkWidget		*change_all_button;
56 	GtkWidget		*add_word_button;
57 	GtkWidget		*close_button;
58 	GtkWidget		*suggestions_list;
59 	GtkWidget		*language_label;
60 
61 	GtkTreeModel		*suggestions_list_model;
62 };
63 
64 enum
65 {
66 	IGNORE,
67 	IGNORE_ALL,
68 	CHANGE,
69 	CHANGE_ALL,
70 	ADD_WORD_TO_PERSONAL,
71 	LAST_SIGNAL
72 };
73 
74 enum
75 {
76 	COLUMN_SUGGESTIONS,
77 	NUM_COLUMNS
78 };
79 
80 static void	update_suggestions_list_model 			(PlumaSpellCheckerDialog *dlg,
81 								 GSList *suggestions);
82 
83 static void	word_entry_changed_handler			(GtkEditable *editable,
84 								 PlumaSpellCheckerDialog *dlg);
85 static void	close_button_clicked_handler 			(GtkButton *button,
86 								 PlumaSpellCheckerDialog *dlg);
87 static void	suggestions_list_selection_changed_handler 	(GtkTreeSelection *selection,
88 								 PlumaSpellCheckerDialog *dlg);
89 static void	check_word_button_clicked_handler 		(GtkButton *button,
90 								 PlumaSpellCheckerDialog *dlg);
91 static void	add_word_button_clicked_handler 		(GtkButton *button,
92 								 PlumaSpellCheckerDialog *dlg);
93 static void	ignore_button_clicked_handler 			(GtkButton *button,
94 								 PlumaSpellCheckerDialog *dlg);
95 static void	ignore_all_button_clicked_handler 		(GtkButton *button,
96 								 PlumaSpellCheckerDialog *dlg);
97 static void	change_button_clicked_handler 			(GtkButton *button,
98 								 PlumaSpellCheckerDialog *dlg);
99 static void	change_all_button_clicked_handler 		(GtkButton *button,
100 								 PlumaSpellCheckerDialog *dlg);
101 static void	suggestions_list_row_activated_handler		(GtkTreeView *view,
102 								 GtkTreePath *path,
103 								 GtkTreeViewColumn *column,
104 								 PlumaSpellCheckerDialog *dlg);
105 
106 
107 static guint signals [LAST_SIGNAL] = { 0 };
108 
G_DEFINE_TYPE(PlumaSpellCheckerDialog,pluma_spell_checker_dialog,GTK_TYPE_WINDOW)109 G_DEFINE_TYPE(PlumaSpellCheckerDialog, pluma_spell_checker_dialog, GTK_TYPE_WINDOW)
110 
111 static void
112 pluma_spell_checker_dialog_dispose (GObject *object)
113 {
114 	PlumaSpellCheckerDialog *dlg = PLUMA_SPELL_CHECKER_DIALOG (object);
115 
116 	if (dlg->spell_checker != NULL)
117 	{
118 		g_object_unref (dlg->spell_checker);
119 		dlg->spell_checker = NULL;
120 	}
121 
122 	if (dlg->misspelled_word != NULL)
123 	{
124 		g_free (dlg->misspelled_word);
125 		dlg->misspelled_word = NULL;
126 	}
127 
128 	G_OBJECT_CLASS (pluma_spell_checker_dialog_parent_class)->dispose (object);
129 }
130 
131 static void
pluma_spell_checker_dialog_class_init(PlumaSpellCheckerDialogClass * klass)132 pluma_spell_checker_dialog_class_init (PlumaSpellCheckerDialogClass * klass)
133 {
134 	GObjectClass *object_class;
135 
136 	object_class = G_OBJECT_CLASS (klass);
137 
138 	object_class->dispose = pluma_spell_checker_dialog_dispose;
139 
140 	signals[IGNORE] =
141 		g_signal_new ("ignore",
142  			      G_OBJECT_CLASS_TYPE (object_class),
143 			      G_SIGNAL_RUN_LAST,
144 			      G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, ignore),
145 			      NULL, NULL, NULL,
146 			      G_TYPE_NONE,
147 			      1,
148 			      G_TYPE_STRING);
149 
150 	signals[IGNORE_ALL] =
151 		g_signal_new ("ignore_all",
152  			      G_OBJECT_CLASS_TYPE (object_class),
153 			      G_SIGNAL_RUN_LAST,
154 			      G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, ignore_all),
155 			      NULL, NULL, NULL,
156 			      G_TYPE_NONE,
157 			      1,
158 			      G_TYPE_STRING);
159 
160 	signals[CHANGE] =
161 		g_signal_new ("change",
162  			      G_OBJECT_CLASS_TYPE (object_class),
163 			      G_SIGNAL_RUN_LAST,
164 			      G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, change),
165 			      NULL, NULL, NULL,
166 			      G_TYPE_NONE,
167 			      2,
168 			      G_TYPE_STRING,
169 			      G_TYPE_STRING);
170 
171 	signals[CHANGE_ALL] =
172 		g_signal_new ("change_all",
173  			      G_OBJECT_CLASS_TYPE (object_class),
174 			      G_SIGNAL_RUN_LAST,
175 			      G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, change_all),
176 			      NULL, NULL, NULL,
177 			      G_TYPE_NONE,
178 			      2,
179 			      G_TYPE_STRING,
180 			      G_TYPE_STRING);
181 
182 	signals[ADD_WORD_TO_PERSONAL] =
183 		g_signal_new ("add_word_to_personal",
184  			      G_OBJECT_CLASS_TYPE (object_class),
185 			      G_SIGNAL_RUN_LAST,
186 			      G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, add_word_to_personal),
187 			      NULL, NULL, NULL,
188 			      G_TYPE_NONE,
189 			      1,
190 			      G_TYPE_STRING);
191 }
192 
193 static void
create_dialog(PlumaSpellCheckerDialog * dlg,const gchar * data_dir)194 create_dialog (PlumaSpellCheckerDialog *dlg,
195 	       const gchar *data_dir)
196 {
197 	GtkWidget *error_widget;
198 	GtkWidget *content;
199 	GtkTreeViewColumn *column;
200 	GtkCellRenderer *cell;
201 	GtkTreeSelection *selection;
202 	gchar *root_objects[] = {
203 		"content",
204 		"check_word_image",
205 		"add_word_image",
206                 "ignore_image",
207                 "change_image",
208                 "ignore_all_image",
209                 "change_all_image",
210 		NULL
211 	};
212 	gboolean ret;
213 	gchar *ui_file;
214 
215 	g_return_if_fail (dlg != NULL);
216 
217 	dlg->spell_checker = NULL;
218 	dlg->misspelled_word = NULL;
219 
220 	ui_file = g_build_filename (data_dir, "spell-checker.ui", NULL);
221 	ret = pluma_utils_get_ui_objects (ui_file,
222 		root_objects,
223 		&error_widget,
224 
225 		"content", &content,
226 		"misspelled_word_label", &dlg->misspelled_word_label,
227 		"word_entry", &dlg->word_entry,
228 		"check_word_button", &dlg->check_word_button,
229 		"ignore_button", &dlg->ignore_button,
230 		"ignore_all_button", &dlg->ignore_all_button,
231 		"change_button", &dlg->change_button,
232 		"change_all_button", &dlg->change_all_button,
233 		"add_word_button", &dlg->add_word_button,
234 		"close_button", &dlg->close_button,
235 		"suggestions_list", &dlg->suggestions_list,
236 		"language_label", &dlg->language_label,
237 		NULL);
238 	g_free (ui_file);
239 
240 	if (!ret)
241 	{
242 		gtk_widget_show (error_widget);
243 
244 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
245 				    error_widget, TRUE, TRUE, 0);
246 
247 		return;
248 	}
249 
250 	gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), "");
251 	gtk_widget_set_sensitive (dlg->word_entry, FALSE);
252 	gtk_widget_set_sensitive (dlg->check_word_button, FALSE);
253 	gtk_widget_set_sensitive (dlg->ignore_button, FALSE);
254 	gtk_widget_set_sensitive (dlg->ignore_all_button, FALSE);
255 	gtk_widget_set_sensitive (dlg->change_button, FALSE);
256 	gtk_widget_set_sensitive (dlg->change_all_button, FALSE);
257 	gtk_widget_set_sensitive (dlg->add_word_button, FALSE);
258 
259 	gtk_label_set_label (GTK_LABEL (dlg->language_label), "");
260 
261 	gtk_container_add (GTK_CONTAINER (dlg), content);
262 	g_object_unref (content);
263 
264 	gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE);
265 	gtk_window_set_title (GTK_WINDOW (dlg), _("Check Spelling"));
266 
267 	/* Suggestion list */
268 	dlg->suggestions_list_model = GTK_TREE_MODEL (
269 			gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING));
270 
271 	gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->suggestions_list),
272 			dlg->suggestions_list_model);
273 
274 	/* Add the suggestions column */
275 	cell = gtk_cell_renderer_text_new ();
276 	column = gtk_tree_view_column_new_with_attributes (_("Suggestions"), cell,
277 			"text", COLUMN_SUGGESTIONS, NULL);
278 
279 	gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->suggestions_list), column);
280 
281 	gtk_tree_view_set_search_column (GTK_TREE_VIEW (dlg->suggestions_list),
282 					 COLUMN_SUGGESTIONS);
283 
284 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->suggestions_list));
285 
286 	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
287 
288 	/* Set default button */
289 	gtk_widget_set_can_default (dlg->change_button, TRUE);
290 	gtk_widget_grab_default (dlg->change_button);
291 
292 	gtk_entry_set_activates_default (GTK_ENTRY (dlg->word_entry), TRUE);
293 
294 	gtk_button_set_image (GTK_BUTTON (dlg->close_button),
295 			      gtk_image_new_from_icon_name ("window-close", GTK_ICON_SIZE_BUTTON));
296 
297 	/* Connect signals */
298 	g_signal_connect (dlg->word_entry, "changed",
299 			  G_CALLBACK (word_entry_changed_handler), dlg);
300 	g_signal_connect (dlg->close_button, "clicked",
301 			  G_CALLBACK (close_button_clicked_handler), dlg);
302 	g_signal_connect (selection, "changed",
303 			  G_CALLBACK (suggestions_list_selection_changed_handler),
304 			  dlg);
305 	g_signal_connect (dlg->check_word_button, "clicked",
306 			  G_CALLBACK (check_word_button_clicked_handler), dlg);
307 	g_signal_connect (dlg->add_word_button, "clicked",
308 			  G_CALLBACK (add_word_button_clicked_handler), dlg);
309 	g_signal_connect (dlg->ignore_button, "clicked",
310 			  G_CALLBACK (ignore_button_clicked_handler), dlg);
311 	g_signal_connect (dlg->ignore_all_button, "clicked",
312 			  G_CALLBACK (ignore_all_button_clicked_handler), dlg);
313 	g_signal_connect (dlg->change_button, "clicked",
314 			  G_CALLBACK (change_button_clicked_handler), dlg);
315 	g_signal_connect (dlg->change_all_button, "clicked",
316 			  G_CALLBACK (change_all_button_clicked_handler), dlg);
317 	g_signal_connect (dlg->suggestions_list, "row-activated",
318 			  G_CALLBACK (suggestions_list_row_activated_handler), dlg);
319 }
320 
321 static void
pluma_spell_checker_dialog_init(PlumaSpellCheckerDialog * dlg)322 pluma_spell_checker_dialog_init (PlumaSpellCheckerDialog *dlg)
323 {
324 }
325 
326 GtkWidget *
pluma_spell_checker_dialog_new(const gchar * data_dir)327 pluma_spell_checker_dialog_new (const gchar *data_dir)
328 {
329 	PlumaSpellCheckerDialog *dlg;
330 
331 	dlg = PLUMA_SPELL_CHECKER_DIALOG (
332 			g_object_new (PLUMA_TYPE_SPELL_CHECKER_DIALOG, NULL));
333 
334 	g_return_val_if_fail (dlg != NULL, NULL);
335 
336 	create_dialog (dlg, data_dir);
337 
338 	return GTK_WIDGET (dlg);
339 }
340 
341 GtkWidget *
pluma_spell_checker_dialog_new_from_spell_checker(PlumaSpellChecker * spell,const gchar * data_dir)342 pluma_spell_checker_dialog_new_from_spell_checker (PlumaSpellChecker *spell,
343 						   const gchar *data_dir)
344 {
345 	PlumaSpellCheckerDialog *dlg;
346 
347 	g_return_val_if_fail (spell != NULL, NULL);
348 
349 	dlg = PLUMA_SPELL_CHECKER_DIALOG (
350 			g_object_new (PLUMA_TYPE_SPELL_CHECKER_DIALOG, NULL));
351 
352 	g_return_val_if_fail (dlg != NULL, NULL);
353 
354 	create_dialog (dlg, data_dir);
355 
356 	pluma_spell_checker_dialog_set_spell_checker (dlg, spell);
357 
358 	return GTK_WIDGET (dlg);
359 }
360 
361 void
pluma_spell_checker_dialog_set_spell_checker(PlumaSpellCheckerDialog * dlg,PlumaSpellChecker * spell)362 pluma_spell_checker_dialog_set_spell_checker (PlumaSpellCheckerDialog *dlg, PlumaSpellChecker *spell)
363 {
364 	const PlumaSpellCheckerLanguage* language;
365 	const gchar *lang;
366 	gchar *tmp;
367 
368 	g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg));
369 	g_return_if_fail (spell != NULL);
370 
371 	if (dlg->spell_checker != NULL)
372 		g_object_unref (dlg->spell_checker);
373 
374 	dlg->spell_checker = spell;
375 	g_object_ref (dlg->spell_checker);
376 
377 	language = pluma_spell_checker_get_language (dlg->spell_checker);
378 
379 	lang = pluma_spell_checker_language_to_string (language);
380 	tmp = g_strdup_printf("<b>%s</b>", lang);
381 
382 	gtk_label_set_label (GTK_LABEL (dlg->language_label), tmp);
383 	g_free (tmp);
384 
385 	if (dlg->misspelled_word != NULL)
386 		pluma_spell_checker_dialog_set_misspelled_word (dlg, dlg->misspelled_word, -1);
387 	else
388 		gtk_list_store_clear (GTK_LIST_STORE (dlg->suggestions_list_model));
389 
390 	/* TODO: reset all widgets */
391 }
392 
393 void
pluma_spell_checker_dialog_set_misspelled_word(PlumaSpellCheckerDialog * dlg,const gchar * word,gint len)394 pluma_spell_checker_dialog_set_misspelled_word (PlumaSpellCheckerDialog *dlg,
395 						const gchar             *word,
396 						gint                     len)
397 {
398 	gchar *tmp;
399 	GSList *sug;
400 
401 	g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg));
402 	g_return_if_fail (word != NULL);
403 
404 	g_return_if_fail (dlg->spell_checker != NULL);
405 	g_return_if_fail (!pluma_spell_checker_check_word (dlg->spell_checker, word, -1));
406 
407 	/* build_suggestions_list */
408 	if (dlg->misspelled_word != NULL)
409 		g_free (dlg->misspelled_word);
410 
411 	dlg->misspelled_word = g_strdup (word);
412 
413 	tmp = g_strdup_printf("<b>%s</b>", word);
414 	gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), tmp);
415 	g_free (tmp);
416 
417 	sug = pluma_spell_checker_get_suggestions (dlg->spell_checker,
418 		       				   dlg->misspelled_word,
419 		       				   -1);
420 
421 	update_suggestions_list_model (dlg, sug);
422 
423 	/* free the suggestion list */
424 	g_slist_free_full (sug, g_free);
425 
426 	gtk_widget_set_sensitive (dlg->ignore_button, TRUE);
427 	gtk_widget_set_sensitive (dlg->ignore_all_button, TRUE);
428 	gtk_widget_set_sensitive (dlg->add_word_button, TRUE);
429 }
430 
431 static void
update_suggestions_list_model(PlumaSpellCheckerDialog * dlg,GSList * suggestions)432 update_suggestions_list_model (PlumaSpellCheckerDialog *dlg, GSList *suggestions)
433 {
434 	GtkListStore *store;
435 	GtkTreeIter iter;
436 	GtkTreeSelection *sel;
437 
438 	g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg));
439 	g_return_if_fail (GTK_IS_LIST_STORE (dlg->suggestions_list_model));
440 
441 	store = GTK_LIST_STORE (dlg->suggestions_list_model);
442 	gtk_list_store_clear (store);
443 
444 	gtk_widget_set_sensitive (dlg->word_entry, TRUE);
445 
446 	if (suggestions == NULL)
447 	{
448 		gtk_list_store_append (store, &iter);
449 		gtk_list_store_set (store, &iter,
450 		                    /* Translators: Displayed in the "Check Spelling" dialog if there are no suggestions
451 		                     * for the current misspelled word */
452 				    COLUMN_SUGGESTIONS, _("(no suggested words)"),
453 				    -1);
454 
455 		gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), "");
456 
457 		gtk_widget_set_sensitive (dlg->suggestions_list, FALSE);
458 
459 		return;
460 	}
461 
462 	gtk_widget_set_sensitive (dlg->suggestions_list, TRUE);
463 
464 	gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), (gchar*)suggestions->data);
465 
466 	while (suggestions != NULL)
467 	{
468 		gtk_list_store_append (store, &iter);
469 		gtk_list_store_set (store, &iter,
470 				    COLUMN_SUGGESTIONS, (gchar*)suggestions->data,
471 				    -1);
472 
473 		suggestions = g_slist_next (suggestions);
474 	}
475 
476 	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->suggestions_list));
477 	gtk_tree_model_get_iter_first (dlg->suggestions_list_model, &iter);
478 	gtk_tree_selection_select_iter (sel, &iter);
479 }
480 
481 static void
word_entry_changed_handler(GtkEditable * editable,PlumaSpellCheckerDialog * dlg)482 word_entry_changed_handler (GtkEditable *editable, PlumaSpellCheckerDialog *dlg)
483 {
484 	const gchar *text;
485 
486 	g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg));
487 
488 	text =  gtk_entry_get_text (GTK_ENTRY (dlg->word_entry));
489 
490 	if (g_utf8_strlen (text, -1) > 0)
491 	{
492 		gtk_widget_set_sensitive (dlg->check_word_button, TRUE);
493 		gtk_widget_set_sensitive (dlg->change_button, TRUE);
494 		gtk_widget_set_sensitive (dlg->change_all_button, TRUE);
495 	}
496 	else
497 	{
498 		gtk_widget_set_sensitive (dlg->check_word_button, FALSE);
499 		gtk_widget_set_sensitive (dlg->change_button, FALSE);
500 		gtk_widget_set_sensitive (dlg->change_all_button, FALSE);
501 	}
502 }
503 
504 static void
close_button_clicked_handler(GtkButton * button,PlumaSpellCheckerDialog * dlg)505 close_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg)
506 {
507 	g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg));
508 
509 	gtk_widget_destroy (GTK_WIDGET (dlg));
510 }
511 
512 static void
suggestions_list_selection_changed_handler(GtkTreeSelection * selection,PlumaSpellCheckerDialog * dlg)513 suggestions_list_selection_changed_handler (GtkTreeSelection *selection,
514 		PlumaSpellCheckerDialog *dlg)
515 {
516  	GtkTreeIter iter;
517 	GValue value = {0, };
518 	const gchar *text;
519 
520 	g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg));
521 
522 	if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
523 		return;
524 
525 	gtk_tree_model_get_value (dlg->suggestions_list_model, &iter,
526 			    COLUMN_SUGGESTIONS,
527 			    &value);
528 
529 	text = g_value_get_string (&value);
530 
531 	gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), text);
532 
533 	g_value_unset (&value);
534 }
535 
536 static void
check_word_button_clicked_handler(GtkButton * button,PlumaSpellCheckerDialog * dlg)537 check_word_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg)
538 {
539 	const gchar *word;
540 	gssize len;
541 
542 	g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg));
543 
544 	word = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry));
545 	len = strlen (word);
546 	g_return_if_fail (len > 0);
547 
548 	if (pluma_spell_checker_check_word (dlg->spell_checker, word, len))
549 	{
550 		GtkListStore *store;
551 		GtkTreeIter iter;
552 
553 		store = GTK_LIST_STORE (dlg->suggestions_list_model);
554 		gtk_list_store_clear (store);
555 
556 		gtk_list_store_append (store, &iter);
557 		gtk_list_store_set (store, &iter,
558 		                    /* Translators: Displayed in the "Check Spelling" dialog if the current word isn't misspelled */
559 				    COLUMN_SUGGESTIONS, _("(correct spelling)"),
560 				    -1);
561 
562 		gtk_widget_set_sensitive (dlg->suggestions_list, FALSE);
563 	}
564 	else
565 	{
566 		GSList *sug;
567 
568 		sug = pluma_spell_checker_get_suggestions (dlg->spell_checker,
569 							   word,
570 							   len);
571 
572 		update_suggestions_list_model (dlg, sug);
573 
574 		/* free the suggestion list */
575 		g_slist_free_full (sug, g_free);
576 	}
577 }
578 
579 static void
add_word_button_clicked_handler(GtkButton * button,PlumaSpellCheckerDialog * dlg)580 add_word_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg)
581 {
582 	gchar *word;
583 
584 	g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg));
585 	g_return_if_fail (dlg->misspelled_word != NULL);
586 
587 	pluma_spell_checker_add_word_to_personal (dlg->spell_checker,
588 						  dlg->misspelled_word,
589 						  -1);
590 
591 	word = g_strdup (dlg->misspelled_word);
592 
593 	g_signal_emit (G_OBJECT (dlg), signals [ADD_WORD_TO_PERSONAL], 0, word);
594 
595 	g_free (word);
596 }
597 
598 static void
ignore_button_clicked_handler(GtkButton * button,PlumaSpellCheckerDialog * dlg)599 ignore_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg)
600 {
601 	gchar *word;
602 
603 	g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg));
604 	g_return_if_fail (dlg->misspelled_word != NULL);
605 
606 	word = g_strdup (dlg->misspelled_word);
607 
608 	g_signal_emit (G_OBJECT (dlg), signals [IGNORE], 0, word);
609 
610 	g_free (word);
611 }
612 
613 static void
ignore_all_button_clicked_handler(GtkButton * button,PlumaSpellCheckerDialog * dlg)614 ignore_all_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg)
615 {
616 	gchar *word;
617 
618 	g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg));
619 	g_return_if_fail (dlg->misspelled_word != NULL);
620 
621 	pluma_spell_checker_add_word_to_session (dlg->spell_checker,
622 						 dlg->misspelled_word,
623 						 -1);
624 
625 	word = g_strdup (dlg->misspelled_word);
626 
627 	g_signal_emit (G_OBJECT (dlg), signals [IGNORE_ALL], 0, word);
628 
629 	g_free (word);
630 }
631 
632 static void
change_button_clicked_handler(GtkButton * button,PlumaSpellCheckerDialog * dlg)633 change_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg)
634 {
635 	const gchar *entry_text;
636 	gchar *change;
637 	gchar *word;
638 
639 	g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg));
640 	g_return_if_fail (dlg->misspelled_word != NULL);
641 
642 	entry_text = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry));
643 	g_return_if_fail (entry_text != NULL);
644 	g_return_if_fail (*entry_text != '\0');
645 	change = g_strdup (entry_text);
646 
647 	pluma_spell_checker_set_correction (dlg->spell_checker,
648 					    dlg->misspelled_word, -1,
649 					    change, -1);
650 
651 	word = g_strdup (dlg->misspelled_word);
652 
653 	g_signal_emit (G_OBJECT (dlg), signals [CHANGE], 0, word, change);
654 
655 	g_free (word);
656 	g_free (change);
657 }
658 
659 /* double click on one of the suggestions is like clicking on "change" */
660 static void
suggestions_list_row_activated_handler(GtkTreeView * view,GtkTreePath * path,GtkTreeViewColumn * column,PlumaSpellCheckerDialog * dlg)661 suggestions_list_row_activated_handler (GtkTreeView *view,
662 		GtkTreePath *path,
663 		GtkTreeViewColumn *column,
664 		PlumaSpellCheckerDialog *dlg)
665 {
666 	g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg));
667 
668 	change_button_clicked_handler (GTK_BUTTON (dlg->change_button), dlg);
669 }
670 
671 static void
change_all_button_clicked_handler(GtkButton * button,PlumaSpellCheckerDialog * dlg)672 change_all_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg)
673 {
674 	const gchar *entry_text;
675 	gchar *change;
676 	gchar *word;
677 
678 	g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg));
679 	g_return_if_fail (dlg->misspelled_word != NULL);
680 
681 	entry_text = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry));
682 	g_return_if_fail (entry_text != NULL);
683 	g_return_if_fail (*entry_text != '\0');
684 	change = g_strdup (entry_text);
685 
686 	pluma_spell_checker_set_correction (dlg->spell_checker,
687 					    dlg->misspelled_word, -1,
688 					    change, -1);
689 
690 	word = g_strdup (dlg->misspelled_word);
691 
692 	g_signal_emit (G_OBJECT (dlg), signals [CHANGE_ALL], 0, word, change);
693 
694 	g_free (word);
695 	g_free (change);
696 }
697 
698 void
pluma_spell_checker_dialog_set_completed(PlumaSpellCheckerDialog * dlg)699 pluma_spell_checker_dialog_set_completed (PlumaSpellCheckerDialog *dlg)
700 {
701 	gchar *tmp;
702 
703 	g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg));
704 
705 	tmp = g_strdup_printf("<b>%s</b>", _("Completed spell checking"));
706 	gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label),
707 			     tmp);
708 	g_free (tmp);
709 
710 	gtk_list_store_clear (GTK_LIST_STORE (dlg->suggestions_list_model));
711 	gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), "");
712 
713 	gtk_widget_set_sensitive (dlg->word_entry, FALSE);
714 	gtk_widget_set_sensitive (dlg->check_word_button, FALSE);
715 	gtk_widget_set_sensitive (dlg->ignore_button, FALSE);
716 	gtk_widget_set_sensitive (dlg->ignore_all_button, FALSE);
717 	gtk_widget_set_sensitive (dlg->change_button, FALSE);
718 	gtk_widget_set_sensitive (dlg->change_all_button, FALSE);
719 	gtk_widget_set_sensitive (dlg->add_word_button, FALSE);
720 	gtk_widget_set_sensitive (dlg->suggestions_list, FALSE);
721 }
722 
723