1 /*
2 * pluma-spell-plugin.c
3 *
4 * Copyright (C) 2002-2005 Paolo Maggi
5 * Copyright (C) 2012-2021 MATE Developers
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 * $Id$
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include "pluma-spell-plugin.h"
29 #include "pluma-spell-utils.h"
30
31 #include <string.h> /* For strlen */
32
33 #include <glib/gi18n.h>
34 #include <gmodule.h>
35 #include <libpeas-gtk/peas-gtk-configurable.h>
36
37 #include <pluma/pluma-window-activatable.h>
38 #include <pluma/pluma-window.h>
39 #include <pluma/pluma-debug.h>
40 #include <pluma/pluma-statusbar.h>
41 #include <pluma/pluma-utils.h>
42
43 #include "pluma-spell-checker.h"
44 #include "pluma-spell-checker-dialog.h"
45 #include "pluma-spell-language-dialog.h"
46 #include "pluma-automatic-spell-checker.h"
47
48 #define PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE "metadata::pluma-spell-language"
49 #define PLUMA_METADATA_ATTRIBUTE_SPELL_ENABLED "metadata::pluma-spell-enabled"
50
51 #define MENU_PATH "/MenuBar/ToolsMenu/ToolsOps_1"
52
53 /* GSettings keys */
54 #define SPELL_SCHEMA "org.mate.pluma.plugins.spell"
55 #define AUTOCHECK_TYPE_KEY "autocheck-type"
56
57 static void pluma_window_activatable_iface_init (PlumaWindowActivatableInterface *iface);
58 static void peas_gtk_configurable_iface_init (PeasGtkConfigurableInterface *iface);
59
60 enum {
61 PROP_0,
62 PROP_WINDOW
63 };
64
65 struct _PlumaSpellPluginPrivate
66 {
67 PlumaWindow *window;
68
69 GtkActionGroup *action_group;
70 guint ui_id;
71 guint message_cid;
72 gulong tab_added_id;
73 gulong tab_removed_id;
74
75 GSettings *settings;
76 };
77
78 G_DEFINE_DYNAMIC_TYPE_EXTENDED (PlumaSpellPlugin,
79 pluma_spell_plugin,
80 PEAS_TYPE_EXTENSION_BASE,
81 0,
82 G_ADD_PRIVATE_DYNAMIC (PlumaSpellPlugin)
83 G_IMPLEMENT_INTERFACE_DYNAMIC (PLUMA_TYPE_WINDOW_ACTIVATABLE,
84 pluma_window_activatable_iface_init)
85 G_IMPLEMENT_INTERFACE_DYNAMIC (PEAS_GTK_TYPE_CONFIGURABLE,
86 peas_gtk_configurable_iface_init))
87
88 static void spell_cb (GtkAction *action, PlumaSpellPlugin *plugin);
89 static void set_language_cb (GtkAction *action, PlumaSpellPlugin *plugin);
90 static void auto_spell_cb (GtkAction *action, PlumaSpellPlugin *plugin);
91
92 /* UI actions. */
93 static const GtkActionEntry action_entries[] =
94 {
95 { "CheckSpell",
96 "tools-check-spelling",
97 N_("_Check Spelling..."),
98 "<shift>F7",
99 N_("Check the current document for incorrect spelling"),
100 G_CALLBACK (spell_cb)
101 },
102
103 { "ConfigSpell",
104 NULL,
105 N_("Set _Language..."),
106 NULL,
107 N_("Set the language of the current document"),
108 G_CALLBACK (set_language_cb)
109 }
110 };
111
112 static const GtkToggleActionEntry toggle_action_entries[] =
113 {
114 { "AutoSpell",
115 NULL,
116 N_("_Autocheck Spelling"),
117 "<control>F7",
118 N_("Automatically spell-check the current document"),
119 G_CALLBACK (auto_spell_cb),
120 FALSE
121 }
122 };
123
124 typedef struct _SpellConfigureDialog SpellConfigureDialog;
125
126 struct _SpellConfigureDialog
127 {
128 GtkWidget *content;
129
130 GtkWidget *never;
131 GtkWidget *always;
132 GtkWidget *document;
133
134 GSettings *settings;
135 };
136
137 typedef enum
138 {
139 AUTOCHECK_NEVER = 0,
140 AUTOCHECK_DOCUMENT,
141 AUTOCHECK_ALWAYS
142 } PlumaSpellPluginAutocheckType;
143
144 typedef struct _CheckRange CheckRange;
145
146 struct _CheckRange
147 {
148 GtkTextMark *start_mark;
149 GtkTextMark *end_mark;
150
151 gint mw_start; /* misspelled word start */
152 gint mw_end; /* end */
153
154 GtkTextMark *current_mark;
155 };
156
157 static GQuark spell_checker_id = 0;
158 static GQuark check_range_id = 0;
159
160 static void
pluma_spell_plugin_init(PlumaSpellPlugin * plugin)161 pluma_spell_plugin_init (PlumaSpellPlugin *plugin)
162 {
163 pluma_debug_message (DEBUG_PLUGINS, "PlumaSpellPlugin initializing");
164
165 plugin->priv = pluma_spell_plugin_get_instance_private (plugin);
166
167 plugin->priv->settings = g_settings_new (SPELL_SCHEMA);
168 }
169
170 static void
pluma_spell_plugin_dispose(GObject * object)171 pluma_spell_plugin_dispose (GObject *object)
172 {
173 PlumaSpellPlugin *plugin = PLUMA_SPELL_PLUGIN (object);
174
175 pluma_debug_message (DEBUG_PLUGINS, "PlumaSpellPlugin disposing");
176
177 if (plugin->priv->window != NULL)
178 {
179 g_object_unref (plugin->priv->window);
180 plugin->priv->window = NULL;
181 }
182
183 if (plugin->priv->action_group)
184 {
185 g_object_unref (plugin->priv->action_group);
186 plugin->priv->action_group = NULL;
187 }
188
189 g_object_unref (G_OBJECT (plugin->priv->settings));
190
191 G_OBJECT_CLASS (pluma_spell_plugin_parent_class)->dispose (object);
192 }
193
194 static void
set_spell_language_cb(PlumaSpellChecker * spell,const PlumaSpellCheckerLanguage * lang,PlumaDocument * doc)195 set_spell_language_cb (PlumaSpellChecker *spell,
196 const PlumaSpellCheckerLanguage *lang,
197 PlumaDocument *doc)
198 {
199 const gchar *key;
200
201 g_return_if_fail (PLUMA_IS_DOCUMENT (doc));
202 g_return_if_fail (lang != NULL);
203
204 key = pluma_spell_checker_language_to_key (lang);
205 g_return_if_fail (key != NULL);
206
207 pluma_document_set_metadata (doc, PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE,
208 key, NULL);
209 }
210
211 static void
set_language_from_metadata(PlumaSpellChecker * spell,PlumaDocument * doc)212 set_language_from_metadata (PlumaSpellChecker *spell,
213 PlumaDocument *doc)
214 {
215 const PlumaSpellCheckerLanguage *lang = NULL;
216 gchar *value = NULL;
217
218 value = pluma_document_get_metadata (doc, PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE);
219
220 if (value != NULL)
221 {
222 lang = pluma_spell_checker_language_from_key (value);
223 g_free (value);
224 }
225
226 if (lang != NULL)
227 {
228 g_signal_handlers_block_by_func (spell, set_spell_language_cb, doc);
229 pluma_spell_checker_set_language (spell, lang);
230 g_signal_handlers_unblock_by_func (spell, set_spell_language_cb, doc);
231 }
232 }
233
234 static PlumaSpellPluginAutocheckType
get_autocheck_type(PlumaSpellPlugin * plugin)235 get_autocheck_type (PlumaSpellPlugin *plugin)
236 {
237 PlumaSpellPluginAutocheckType autocheck_type;
238
239 autocheck_type = g_settings_get_enum (plugin->priv->settings,
240 AUTOCHECK_TYPE_KEY);
241
242 return autocheck_type;
243 }
244
245 static void
set_autocheck_type(GSettings * settings,PlumaSpellPluginAutocheckType autocheck_type)246 set_autocheck_type (GSettings *settings,
247 PlumaSpellPluginAutocheckType autocheck_type)
248 {
249 if (!g_settings_is_writable (settings,
250 AUTOCHECK_TYPE_KEY))
251 {
252 return;
253 }
254
255 g_settings_set_enum (settings,
256 AUTOCHECK_TYPE_KEY,
257 autocheck_type);
258 }
259
260 static PlumaSpellChecker *
get_spell_checker_from_document(PlumaDocument * doc)261 get_spell_checker_from_document (PlumaDocument *doc)
262 {
263 PlumaSpellChecker *spell;
264 gpointer data;
265
266 pluma_debug (DEBUG_PLUGINS);
267
268 g_return_val_if_fail (doc != NULL, NULL);
269
270 data = g_object_get_qdata (G_OBJECT (doc), spell_checker_id);
271
272 if (data == NULL)
273 {
274 spell = pluma_spell_checker_new ();
275
276 set_language_from_metadata (spell, doc);
277
278 g_object_set_qdata_full (G_OBJECT (doc),
279 spell_checker_id,
280 spell,
281 (GDestroyNotify) g_object_unref);
282
283 g_signal_connect (spell,
284 "set_language",
285 G_CALLBACK (set_spell_language_cb),
286 doc);
287 }
288 else
289 {
290 g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (data), NULL);
291 spell = PLUMA_SPELL_CHECKER (data);
292 }
293
294 return spell;
295 }
296
297 static CheckRange *
get_check_range(PlumaDocument * doc)298 get_check_range (PlumaDocument *doc)
299 {
300 CheckRange *range;
301
302 pluma_debug (DEBUG_PLUGINS);
303
304 g_return_val_if_fail (doc != NULL, NULL);
305
306 range = (CheckRange *) g_object_get_qdata (G_OBJECT (doc), check_range_id);
307
308 return range;
309 }
310
311 static void
update_current(PlumaDocument * doc,gint current)312 update_current (PlumaDocument *doc,
313 gint current)
314 {
315 CheckRange *range;
316 GtkTextIter iter;
317 GtkTextIter end_iter;
318
319 pluma_debug (DEBUG_PLUGINS);
320
321 g_return_if_fail (doc != NULL);
322 g_return_if_fail (current >= 0);
323
324 range = get_check_range (doc);
325 g_return_if_fail (range != NULL);
326
327 gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc),
328 &iter, current);
329
330 if (!gtk_text_iter_inside_word (&iter))
331 {
332 /* if we're not inside a word,
333 * we must be in some spaces.
334 * skip forward to the beginning of the next word. */
335 if (!gtk_text_iter_is_end (&iter))
336 {
337 gtk_text_iter_forward_word_end (&iter);
338 gtk_text_iter_backward_word_start (&iter);
339 }
340 }
341 else
342 {
343 if (!gtk_text_iter_starts_word (&iter))
344 gtk_text_iter_backward_word_start (&iter);
345 }
346
347 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc),
348 &end_iter,
349 range->end_mark);
350
351 if (gtk_text_iter_compare (&end_iter, &iter) < 0)
352 {
353 gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc),
354 range->current_mark,
355 &end_iter);
356 }
357 else
358 {
359 gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc),
360 range->current_mark,
361 &iter);
362 }
363 }
364
365 static void
set_check_range(PlumaDocument * doc,GtkTextIter * start,GtkTextIter * end)366 set_check_range (PlumaDocument *doc,
367 GtkTextIter *start,
368 GtkTextIter *end)
369 {
370 CheckRange *range;
371 GtkTextIter iter;
372
373 pluma_debug (DEBUG_PLUGINS);
374
375 range = get_check_range (doc);
376
377 if (range == NULL)
378 {
379 pluma_debug_message (DEBUG_PLUGINS, "There was not a previous check range");
380
381 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &iter);
382
383 range = g_new0 (CheckRange, 1);
384
385 range->start_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc),
386 "check_range_start_mark", &iter, TRUE);
387
388 range->end_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc),
389 "check_range_end_mark", &iter, FALSE);
390
391 range->current_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc),
392 "check_range_current_mark", &iter, TRUE);
393
394 g_object_set_qdata_full (G_OBJECT (doc),
395 check_range_id,
396 range,
397 (GDestroyNotify)g_free);
398 }
399
400 if (pluma_spell_utils_skip_no_spell_check (start, end))
401 {
402 if (!gtk_text_iter_inside_word (end))
403 {
404 /* if we're neither inside a word,
405 * we must be in some spaces.
406 * skip backward to the end of the previous word. */
407 if (!gtk_text_iter_is_end (end))
408 {
409 gtk_text_iter_backward_word_start (end);
410 gtk_text_iter_forward_word_end (end);
411 }
412 }
413 else
414 {
415 if (!gtk_text_iter_ends_word (end))
416 gtk_text_iter_forward_word_end (end);
417 }
418 }
419 else
420 {
421 /* no spell checking in the specified range */
422 start = end;
423 }
424
425 gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc),
426 range->start_mark,
427 start);
428 gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc),
429 range->end_mark,
430 end);
431
432 range->mw_start = -1;
433 range->mw_end = -1;
434
435 update_current (doc, gtk_text_iter_get_offset (start));
436 }
437
438 static gchar *
get_current_word(PlumaDocument * doc,gint * start,gint * end)439 get_current_word (PlumaDocument *doc, gint *start, gint *end)
440 {
441 const CheckRange *range;
442 GtkTextIter end_iter;
443 GtkTextIter current_iter;
444 gint range_end;
445
446 pluma_debug (DEBUG_PLUGINS);
447
448 g_return_val_if_fail (doc != NULL, NULL);
449 g_return_val_if_fail (start != NULL, NULL);
450 g_return_val_if_fail (end != NULL, NULL);
451
452 range = get_check_range (doc);
453 g_return_val_if_fail (range != NULL, NULL);
454
455 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc),
456 &end_iter, range->end_mark);
457
458 range_end = gtk_text_iter_get_offset (&end_iter);
459
460 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc),
461 ¤t_iter, range->current_mark);
462
463 end_iter = current_iter;
464
465 if (!gtk_text_iter_is_end (&end_iter))
466 {
467 pluma_debug_message (DEBUG_PLUGINS, "Current is not end");
468
469 gtk_text_iter_forward_word_end (&end_iter);
470 }
471
472 *start = gtk_text_iter_get_offset (¤t_iter);
473 *end = MIN (gtk_text_iter_get_offset (&end_iter), range_end);
474
475 pluma_debug_message (DEBUG_PLUGINS, "Current word extends [%d, %d]", *start, *end);
476
477 if (!(*start < *end))
478 return NULL;
479
480 return gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc),
481 ¤t_iter,
482 &end_iter,
483 TRUE);
484 }
485
486 static gboolean
goto_next_word(PlumaDocument * doc)487 goto_next_word (PlumaDocument *doc)
488 {
489 CheckRange *range;
490 GtkTextIter current_iter;
491 GtkTextIter old_current_iter;
492 GtkTextIter end_iter;
493
494 pluma_debug (DEBUG_PLUGINS);
495
496 g_return_val_if_fail (doc != NULL, FALSE);
497
498 range = get_check_range (doc);
499 g_return_val_if_fail (range != NULL, FALSE);
500
501 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc),
502 ¤t_iter,
503 range->current_mark);
504 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end_iter);
505
506 old_current_iter = current_iter;
507
508 gtk_text_iter_forward_word_ends (¤t_iter, 2);
509 gtk_text_iter_backward_word_start (¤t_iter);
510
511 if (pluma_spell_utils_skip_no_spell_check (¤t_iter, &end_iter) &&
512 (gtk_text_iter_compare (&old_current_iter, ¤t_iter) < 0) &&
513 (gtk_text_iter_compare (¤t_iter, &end_iter) < 0))
514 {
515 update_current (doc, gtk_text_iter_get_offset (¤t_iter));
516 return TRUE;
517 }
518
519 return FALSE;
520 }
521
522 static gchar *
get_next_misspelled_word(PlumaView * view)523 get_next_misspelled_word (PlumaView *view)
524 {
525 PlumaDocument *doc;
526 CheckRange *range;
527 gint start, end;
528 gchar *word;
529 PlumaSpellChecker *spell;
530
531 g_return_val_if_fail (view != NULL, NULL);
532
533 doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
534 g_return_val_if_fail (doc != NULL, NULL);
535
536 range = get_check_range (doc);
537 g_return_val_if_fail (range != NULL, NULL);
538
539 spell = get_spell_checker_from_document (doc);
540 g_return_val_if_fail (spell != NULL, NULL);
541
542 word = get_current_word (doc, &start, &end);
543 if (word == NULL)
544 return NULL;
545
546 pluma_debug_message (DEBUG_PLUGINS, "Word to check: %s", word);
547
548 while (pluma_spell_checker_check_word (spell, word, -1))
549 {
550 g_free (word);
551
552 if (!goto_next_word (doc))
553 return NULL;
554
555 /* may return null if we reached the end of the selection */
556 word = get_current_word (doc, &start, &end);
557 if (word == NULL)
558 return NULL;
559
560 pluma_debug_message (DEBUG_PLUGINS, "Word to check: %s", word);
561 }
562
563 if (!goto_next_word (doc))
564 update_current (doc, gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (doc)));
565
566 if (word != NULL)
567 {
568 GtkTextIter s, e;
569
570 range->mw_start = start;
571 range->mw_end = end;
572
573 pluma_debug_message (DEBUG_PLUGINS, "Select [%d, %d]", start, end);
574
575 gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &s, start);
576 gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &e, end);
577
578 gtk_text_buffer_select_range (GTK_TEXT_BUFFER (doc), &s, &e);
579
580 pluma_view_scroll_to_cursor (view);
581 }
582 else
583 {
584 range->mw_start = -1;
585 range->mw_end = -1;
586 }
587
588 return word;
589 }
590
591 static void
ignore_cb(PlumaSpellCheckerDialog * dlg,const gchar * w,PlumaView * view)592 ignore_cb (PlumaSpellCheckerDialog *dlg,
593 const gchar *w,
594 PlumaView *view)
595 {
596 gchar *word = NULL;
597
598 pluma_debug (DEBUG_PLUGINS);
599
600 g_return_if_fail (w != NULL);
601 g_return_if_fail (view != NULL);
602
603 word = get_next_misspelled_word (view);
604 if (word == NULL)
605 {
606 pluma_spell_checker_dialog_set_completed (dlg);
607
608 return;
609 }
610
611 pluma_spell_checker_dialog_set_misspelled_word (PLUMA_SPELL_CHECKER_DIALOG (dlg),
612 word,
613 -1);
614
615 g_free (word);
616 }
617
618 static void
change_cb(PlumaSpellCheckerDialog * dlg,const gchar * word,const gchar * change,PlumaView * view)619 change_cb (PlumaSpellCheckerDialog *dlg,
620 const gchar *word,
621 const gchar *change,
622 PlumaView *view)
623 {
624 PlumaDocument *doc;
625 CheckRange *range;
626 gchar *w = NULL;
627 GtkTextIter start, end;
628
629 pluma_debug (DEBUG_PLUGINS);
630
631 g_return_if_fail (view != NULL);
632 g_return_if_fail (word != NULL);
633 g_return_if_fail (change != NULL);
634
635 doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
636 g_return_if_fail (doc != NULL);
637
638 range = get_check_range (doc);
639 g_return_if_fail (range != NULL);
640
641 gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &start, range->mw_start);
642 if (range->mw_end < 0)
643 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end);
644 else
645 gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &end, range->mw_end);
646
647 w = gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), &start, &end, TRUE);
648 g_return_if_fail (w != NULL);
649
650 if (strcmp (w, word) != 0)
651 {
652 g_free (w);
653 return;
654 }
655
656 g_free (w);
657
658 gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER(doc));
659
660 gtk_text_buffer_delete (GTK_TEXT_BUFFER (doc), &start, &end);
661 gtk_text_buffer_insert (GTK_TEXT_BUFFER (doc), &start, change, -1);
662
663 gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER(doc));
664
665 update_current (doc, range->mw_start + g_utf8_strlen (change, -1));
666
667 /* go to next misspelled word */
668 ignore_cb (dlg, word, view);
669 }
670
671 static void
change_all_cb(PlumaSpellCheckerDialog * dlg,const gchar * word,const gchar * change,PlumaView * view)672 change_all_cb (PlumaSpellCheckerDialog *dlg,
673 const gchar *word,
674 const gchar *change,
675 PlumaView *view)
676 {
677 PlumaDocument *doc;
678 CheckRange *range;
679 gchar *w = NULL;
680 GtkTextIter start, end;
681 gint flags = 0;
682
683 pluma_debug (DEBUG_PLUGINS);
684
685 g_return_if_fail (view != NULL);
686 g_return_if_fail (word != NULL);
687 g_return_if_fail (change != NULL);
688
689 doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
690 g_return_if_fail (doc != NULL);
691
692 range = get_check_range (doc);
693 g_return_if_fail (range != NULL);
694
695 gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &start, range->mw_start);
696 if (range->mw_end < 0)
697 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end);
698 else
699 gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &end, range->mw_end);
700
701 w = gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), &start, &end, TRUE);
702 g_return_if_fail (w != NULL);
703
704 if (strcmp (w, word) != 0)
705 {
706 g_free (w);
707 return;
708 }
709
710 g_free (w);
711
712 PLUMA_SEARCH_SET_CASE_SENSITIVE (flags, TRUE);
713 PLUMA_SEARCH_SET_ENTIRE_WORD (flags, TRUE);
714
715 /* CHECK: currently this function does escaping etc */
716 pluma_document_replace_all (doc, word, change, flags);
717
718 update_current (doc, range->mw_start + g_utf8_strlen (change, -1));
719
720 /* go to next misspelled word */
721 ignore_cb (dlg, word, view);
722 }
723
724 static void
add_word_cb(PlumaSpellCheckerDialog * dlg,const gchar * word,PlumaView * view)725 add_word_cb (PlumaSpellCheckerDialog *dlg,
726 const gchar *word,
727 PlumaView *view)
728 {
729 g_return_if_fail (view != NULL);
730 g_return_if_fail (word != NULL);
731
732 /* go to next misspelled word */
733 ignore_cb (dlg, word, view);
734 }
735
736 static void
language_dialog_response(GtkDialog * dlg,gint res_id,PlumaSpellChecker * spell)737 language_dialog_response (GtkDialog *dlg,
738 gint res_id,
739 PlumaSpellChecker *spell)
740 {
741 if (res_id == GTK_RESPONSE_OK)
742 {
743 const PlumaSpellCheckerLanguage *lang;
744
745 lang = pluma_spell_language_get_selected_language (PLUMA_SPELL_LANGUAGE_DIALOG (dlg));
746 if (lang != NULL)
747 pluma_spell_checker_set_language (spell, lang);
748 }
749
750 gtk_widget_destroy (GTK_WIDGET (dlg));
751 }
752
753 static SpellConfigureDialog *
get_configure_dialog(PlumaSpellPlugin * plugin)754 get_configure_dialog (PlumaSpellPlugin *plugin)
755 {
756 SpellConfigureDialog *dialog = NULL;
757 gchar *data_dir;
758 gchar *ui_file;
759 PlumaSpellPluginAutocheckType autocheck_type;
760 GtkWidget *error_widget;
761 gboolean ret;
762 gchar *root_objects[] = {
763 "spell_dialog_content",
764 NULL
765 };
766
767 pluma_debug (DEBUG_PLUGINS);
768
769 dialog = g_slice_new (SpellConfigureDialog);
770 dialog->settings = g_object_ref (plugin->priv->settings);
771
772 data_dir = peas_extension_base_get_data_dir (PEAS_EXTENSION_BASE (plugin));
773 ui_file = g_build_filename (data_dir, "pluma-spell-setup-dialog.ui", NULL);
774 ret = pluma_utils_get_ui_objects (ui_file,
775 root_objects,
776 &error_widget,
777 "spell_dialog_content", &dialog->content,
778 "autocheck_never", &dialog->never,
779 "autocheck_document", &dialog->document,
780 "autocheck_always", &dialog->always,
781 NULL);
782
783 g_free (data_dir);
784 g_free (ui_file);
785
786 if (!ret)
787 {
788 return NULL;
789 }
790
791 autocheck_type = get_autocheck_type (plugin);
792
793 if (autocheck_type == AUTOCHECK_ALWAYS)
794 {
795 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->always), TRUE);
796 }
797 else if (autocheck_type == AUTOCHECK_DOCUMENT)
798 {
799 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->document), TRUE);
800 }
801 else
802 {
803 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->never), TRUE);
804 }
805
806 return dialog;
807 }
808
809 static void
configure_dialog_button_toggled(GtkToggleButton * button,SpellConfigureDialog * dialog)810 configure_dialog_button_toggled (GtkToggleButton *button,
811 SpellConfigureDialog *dialog)
812 {
813 pluma_debug (DEBUG_PLUGINS);
814
815 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->always)))
816 {
817 set_autocheck_type (dialog->settings, AUTOCHECK_ALWAYS);
818 }
819 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->document)))
820 {
821 set_autocheck_type (dialog->settings, AUTOCHECK_DOCUMENT);
822 }
823 else
824 {
825 set_autocheck_type (dialog->settings, AUTOCHECK_NEVER);
826 }
827 }
828
829 static void
configure_dialog_destroyed(GtkWidget * widget,gpointer data)830 configure_dialog_destroyed (GtkWidget *widget,
831 gpointer data)
832 {
833 SpellConfigureDialog *dialog = (SpellConfigureDialog *) data;
834
835 pluma_debug (DEBUG_PLUGINS);
836
837 g_object_unref (dialog->settings);
838 g_slice_free (SpellConfigureDialog, data);
839 }
840
841 static void
set_language_cb(GtkAction * action,PlumaSpellPlugin * plugin)842 set_language_cb (GtkAction *action,
843 PlumaSpellPlugin *plugin)
844 {
845 PlumaWindow *window;
846 PlumaDocument *doc;
847 PlumaSpellChecker *spell;
848 const PlumaSpellCheckerLanguage *lang;
849 GtkWidget *dlg;
850 GtkWindowGroup *wg;
851 gchar *data_dir;
852
853 pluma_debug (DEBUG_PLUGINS);
854
855 window = PLUMA_WINDOW (plugin->priv->window);
856 doc = pluma_window_get_active_document (window);
857 g_return_if_fail (doc != NULL);
858
859 spell = get_spell_checker_from_document (doc);
860 g_return_if_fail (spell != NULL);
861
862 lang = pluma_spell_checker_get_language (spell);
863
864 data_dir = peas_extension_base_get_data_dir (PEAS_EXTENSION_BASE (plugin));
865 dlg = pluma_spell_language_dialog_new (GTK_WINDOW (window),
866 lang,
867 data_dir);
868 g_free (data_dir);
869
870 wg = pluma_window_get_group (window);
871
872 gtk_window_group_add_window (wg, GTK_WINDOW (dlg));
873
874 gtk_window_set_modal (GTK_WINDOW (dlg), TRUE);
875
876 g_signal_connect (dlg,
877 "response",
878 G_CALLBACK (language_dialog_response),
879 spell);
880
881 gtk_widget_show (dlg);
882 }
883
884 static void
spell_cb(GtkAction * action,PlumaSpellPlugin * plugin)885 spell_cb (GtkAction *action,
886 PlumaSpellPlugin *plugin)
887 {
888 PlumaSpellPluginPrivate *data;
889 PlumaWindow *window;
890 PlumaView *view;
891 PlumaDocument *doc;
892 PlumaSpellChecker *spell;
893 GtkWidget *dlg;
894 GtkTextIter start, end;
895 gchar *word;
896 gchar *data_dir;
897
898 pluma_debug (DEBUG_PLUGINS);
899
900 data = plugin->priv;
901 window = PLUMA_WINDOW (data->window);
902 view = pluma_window_get_active_view (window);
903 g_return_if_fail (view != NULL);
904
905 doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
906 g_return_if_fail (doc != NULL);
907
908 spell = get_spell_checker_from_document (doc);
909 g_return_if_fail (spell != NULL);
910
911 if (gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (doc)) <= 0)
912 {
913 GtkWidget *statusbar;
914
915 statusbar = pluma_window_get_statusbar (window);
916 pluma_statusbar_flash_message (PLUMA_STATUSBAR (statusbar),
917 data->message_cid,
918 _("The document is empty."));
919
920 return;
921 }
922
923 if (!gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
924 &start,
925 &end))
926 {
927 /* no selection, get the whole doc */
928 gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc),
929 &start,
930 &end);
931 }
932
933 set_check_range (doc, &start, &end);
934
935 word = get_next_misspelled_word (view);
936 if (word == NULL)
937 {
938 GtkWidget *statusbar;
939
940 statusbar = pluma_window_get_statusbar (window);
941 pluma_statusbar_flash_message (PLUMA_STATUSBAR (statusbar),
942 data->message_cid,
943 _("No misspelled words"));
944
945 return;
946 }
947
948 data_dir = peas_extension_base_get_data_dir (PEAS_EXTENSION_BASE (plugin));
949 dlg = pluma_spell_checker_dialog_new_from_spell_checker (spell, data_dir);
950 g_free (data_dir);
951
952 gtk_window_set_modal (GTK_WINDOW (dlg), TRUE);
953 gtk_window_set_transient_for (GTK_WINDOW (dlg),
954 GTK_WINDOW (window));
955
956 g_signal_connect (dlg, "ignore", G_CALLBACK (ignore_cb), view);
957 g_signal_connect (dlg, "ignore_all", G_CALLBACK (ignore_cb), view);
958
959 g_signal_connect (dlg, "change", G_CALLBACK (change_cb), view);
960 g_signal_connect (dlg, "change_all", G_CALLBACK (change_all_cb), view);
961
962 g_signal_connect (dlg, "add_word_to_personal", G_CALLBACK (add_word_cb), view);
963
964 pluma_spell_checker_dialog_set_misspelled_word (PLUMA_SPELL_CHECKER_DIALOG (dlg),
965 word,
966 -1);
967
968 g_free (word);
969
970 gtk_widget_show (dlg);
971 }
972
973 static void
set_auto_spell(PlumaWindow * window,PlumaDocument * doc,gboolean active)974 set_auto_spell (PlumaWindow *window,
975 PlumaDocument *doc,
976 gboolean active)
977 {
978 PlumaAutomaticSpellChecker *autospell;
979 PlumaSpellChecker *spell;
980
981 spell = get_spell_checker_from_document (doc);
982 g_return_if_fail (spell != NULL);
983
984 autospell = pluma_automatic_spell_checker_get_from_document (doc);
985
986 if (active)
987 {
988 if (autospell == NULL)
989 {
990 PlumaView *active_view;
991
992 active_view = pluma_window_get_active_view (window);
993 g_return_if_fail (active_view != NULL);
994
995 autospell = pluma_automatic_spell_checker_new (doc, spell);
996
997 if (doc == pluma_window_get_active_document (window))
998 {
999 pluma_automatic_spell_checker_attach_view (autospell, active_view);
1000 }
1001
1002 pluma_automatic_spell_checker_recheck_all (autospell);
1003 }
1004 }
1005 else
1006 {
1007 if (autospell != NULL)
1008 pluma_automatic_spell_checker_free (autospell);
1009 }
1010 }
1011
1012 static void
auto_spell_cb(GtkAction * action,PlumaSpellPlugin * plugin)1013 auto_spell_cb (GtkAction *action,
1014 PlumaSpellPlugin *plugin)
1015 {
1016 PlumaWindow *window;
1017 PlumaDocument *doc;
1018 gboolean active;
1019
1020 pluma_debug (DEBUG_PLUGINS);
1021
1022 window = PLUMA_WINDOW (plugin->priv->window);
1023
1024 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1025
1026 pluma_debug_message (DEBUG_PLUGINS, active ? "Auto Spell activated" : "Auto Spell deactivated");
1027
1028 doc = pluma_window_get_active_document (window);
1029 if (doc == NULL)
1030 return;
1031
1032 if (get_autocheck_type (plugin) == AUTOCHECK_DOCUMENT)
1033 {
1034 pluma_document_set_metadata (doc,
1035 PLUMA_METADATA_ATTRIBUTE_SPELL_ENABLED,
1036 active ? "1" : NULL, NULL);
1037 }
1038
1039 set_auto_spell (window, doc, active);
1040 }
1041
1042 static void
update_ui(PlumaSpellPlugin * plugin)1043 update_ui (PlumaSpellPlugin *plugin)
1044 {
1045 PlumaSpellPluginPrivate *data;
1046 PlumaWindow *window;
1047 PlumaDocument *doc;
1048 PlumaView *view;
1049 gboolean autospell;
1050 GtkAction *action;
1051
1052 pluma_debug (DEBUG_PLUGINS);
1053
1054 data = plugin->priv;
1055 window = PLUMA_WINDOW (data->window);
1056 doc = pluma_window_get_active_document (window);
1057 view = pluma_window_get_active_view (window);
1058
1059 autospell = (doc != NULL &&
1060 pluma_automatic_spell_checker_get_from_document (doc) != NULL);
1061
1062 if (doc != NULL)
1063 {
1064 PlumaTab *tab;
1065 PlumaTabState state;
1066
1067 tab = pluma_window_get_active_tab (window);
1068 state = pluma_tab_get_state (tab);
1069
1070 /* If the document is loading we can't get the metadata so we
1071 endup with an useless speller */
1072 if (state == PLUMA_TAB_STATE_NORMAL)
1073 {
1074 action = gtk_action_group_get_action (data->action_group,
1075 "AutoSpell");
1076
1077 g_signal_handlers_block_by_func (action, auto_spell_cb,
1078 plugin);
1079 set_auto_spell (window, doc, autospell);
1080 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1081 autospell);
1082 g_signal_handlers_unblock_by_func (action, auto_spell_cb,
1083 plugin);
1084 }
1085 }
1086
1087 gtk_action_group_set_sensitive (data->action_group,
1088 (view != NULL) &&
1089 gtk_text_view_get_editable (GTK_TEXT_VIEW (view)));
1090 }
1091
1092 static void
set_auto_spell_from_metadata(PlumaSpellPlugin * plugin,PlumaDocument * doc,GtkActionGroup * action_group)1093 set_auto_spell_from_metadata (PlumaSpellPlugin *plugin,
1094 PlumaDocument *doc,
1095 GtkActionGroup *action_group)
1096 {
1097 gboolean active = FALSE;
1098 gchar *active_str = NULL;
1099 PlumaWindow *window;
1100 PlumaDocument *active_doc;
1101 PlumaSpellPluginAutocheckType autocheck_type;
1102
1103 autocheck_type = get_autocheck_type (plugin);
1104
1105 switch (autocheck_type)
1106 {
1107 case AUTOCHECK_ALWAYS:
1108 {
1109 active = TRUE;
1110 break;
1111 }
1112 case AUTOCHECK_DOCUMENT:
1113 {
1114 active_str = pluma_document_get_metadata (doc,
1115 PLUMA_METADATA_ATTRIBUTE_SPELL_ENABLED);
1116 break;
1117 }
1118 case AUTOCHECK_NEVER:
1119 default:
1120 active = FALSE;
1121 break;
1122 }
1123
1124 if (active_str)
1125 {
1126 active = *active_str == '1';
1127
1128 g_free (active_str);
1129 }
1130
1131 window = PLUMA_WINDOW (plugin->priv->window);
1132
1133 set_auto_spell (window, doc, active);
1134
1135 /* In case that the doc is the active one we mark the spell action */
1136 active_doc = pluma_window_get_active_document (window);
1137
1138 if (active_doc == doc && action_group != NULL)
1139 {
1140 GtkAction *action;
1141
1142 action = gtk_action_group_get_action (action_group,
1143 "AutoSpell");
1144
1145 g_signal_handlers_block_by_func (action, auto_spell_cb,
1146 plugin);
1147 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1148 active);
1149 g_signal_handlers_unblock_by_func (action, auto_spell_cb,
1150 plugin);
1151 }
1152 }
1153
1154 static void
on_document_loaded(PlumaDocument * doc,const GError * error,PlumaSpellPlugin * plugin)1155 on_document_loaded (PlumaDocument *doc,
1156 const GError *error,
1157 PlumaSpellPlugin *plugin)
1158 {
1159 if (error == NULL)
1160 {
1161 PlumaSpellChecker *spell;
1162
1163 spell = PLUMA_SPELL_CHECKER (g_object_get_qdata (G_OBJECT (doc),
1164 spell_checker_id));
1165 if (spell != NULL)
1166 {
1167 set_language_from_metadata (spell, doc);
1168 }
1169
1170 set_auto_spell_from_metadata (plugin, doc, plugin->priv->action_group);
1171 }
1172 }
1173
1174 static void
on_document_saved(PlumaDocument * doc,const GError * error,PlumaSpellPlugin * plugin)1175 on_document_saved (PlumaDocument *doc,
1176 const GError *error,
1177 PlumaSpellPlugin *plugin)
1178 {
1179 PlumaAutomaticSpellChecker *autospell;
1180 PlumaSpellChecker *spell;
1181 const gchar *key;
1182
1183 if (error != NULL)
1184 {
1185 return;
1186 }
1187
1188 /* Make sure to save the metadata here too */
1189 autospell = pluma_automatic_spell_checker_get_from_document (doc);
1190 spell = PLUMA_SPELL_CHECKER (g_object_get_qdata (G_OBJECT (doc), spell_checker_id));
1191
1192 if (spell != NULL)
1193 {
1194 key = pluma_spell_checker_language_to_key (pluma_spell_checker_get_language (spell));
1195 }
1196 else
1197 {
1198 key = NULL;
1199 }
1200
1201 if (get_autocheck_type (plugin) == AUTOCHECK_DOCUMENT)
1202 {
1203
1204 pluma_document_set_metadata (doc,
1205 PLUMA_METADATA_ATTRIBUTE_SPELL_ENABLED,
1206 autospell != NULL ? "1" : NULL,
1207 PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE,
1208 key,
1209 NULL);
1210 }
1211 else
1212 {
1213 pluma_document_set_metadata (doc,
1214 PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE,
1215 key,
1216 NULL);
1217 }
1218 }
1219
1220 static void
tab_added_cb(PlumaWindow * window,PlumaTab * tab,PlumaSpellPlugin * plugin)1221 tab_added_cb (PlumaWindow *window,
1222 PlumaTab *tab,
1223 PlumaSpellPlugin *plugin)
1224 {
1225 PlumaDocument *doc;
1226 gchar *uri;
1227
1228 doc = pluma_tab_get_document (tab);
1229
1230 g_object_get(G_OBJECT(doc), "uri", &uri, NULL);
1231
1232 if (!uri)
1233 {
1234 set_auto_spell_from_metadata (plugin, doc, plugin->priv->action_group);
1235
1236 g_free(uri);
1237 }
1238
1239 g_signal_connect (doc, "loaded",
1240 G_CALLBACK (on_document_loaded),
1241 plugin);
1242
1243 g_signal_connect (doc, "saved",
1244 G_CALLBACK (on_document_saved),
1245 plugin);
1246 }
1247
1248 static void
tab_removed_cb(PlumaWindow * window,PlumaTab * tab,PlumaSpellPlugin * plugin)1249 tab_removed_cb (PlumaWindow *window,
1250 PlumaTab *tab,
1251 PlumaSpellPlugin *plugin)
1252 {
1253 PlumaDocument *doc;
1254
1255 doc = pluma_tab_get_document (tab);
1256
1257 g_signal_handlers_disconnect_by_func (doc, on_document_loaded, plugin);
1258 g_signal_handlers_disconnect_by_func (doc, on_document_saved, plugin);
1259 }
1260
1261 static void
pluma_spell_plugin_activate(PlumaWindowActivatable * activatable)1262 pluma_spell_plugin_activate (PlumaWindowActivatable *activatable)
1263 {
1264 PlumaSpellPlugin *plugin;
1265 PlumaSpellPluginPrivate *data;
1266 PlumaWindow *window;
1267 GtkUIManager *manager;
1268 GList *docs, *l;
1269
1270 pluma_debug (DEBUG_PLUGINS);
1271
1272 plugin = PLUMA_SPELL_PLUGIN (activatable);
1273 data = plugin->priv;
1274 window = PLUMA_WINDOW (data->window);
1275
1276 manager = pluma_window_get_ui_manager (window);
1277
1278 data->action_group = gtk_action_group_new ("PlumaSpellPluginActions");
1279 gtk_action_group_set_translation_domain (data->action_group,
1280 GETTEXT_PACKAGE);
1281 gtk_action_group_add_actions (data->action_group,
1282 action_entries,
1283 G_N_ELEMENTS (action_entries),
1284 plugin);
1285 gtk_action_group_add_toggle_actions (data->action_group,
1286 toggle_action_entries,
1287 G_N_ELEMENTS (toggle_action_entries),
1288 plugin);
1289
1290 gtk_ui_manager_insert_action_group (manager, data->action_group, -1);
1291
1292 data->ui_id = gtk_ui_manager_new_merge_id (manager);
1293
1294 data->message_cid = gtk_statusbar_get_context_id
1295 (GTK_STATUSBAR (pluma_window_get_statusbar (window)),
1296 "spell_plugin_message");
1297
1298 gtk_ui_manager_add_ui (manager,
1299 data->ui_id,
1300 MENU_PATH,
1301 "CheckSpell",
1302 "CheckSpell",
1303 GTK_UI_MANAGER_MENUITEM,
1304 FALSE);
1305
1306 gtk_ui_manager_add_ui (manager,
1307 data->ui_id,
1308 MENU_PATH,
1309 "AutoSpell",
1310 "AutoSpell",
1311 GTK_UI_MANAGER_MENUITEM,
1312 FALSE);
1313
1314 gtk_ui_manager_add_ui (manager,
1315 data->ui_id,
1316 MENU_PATH,
1317 "ConfigSpell",
1318 "ConfigSpell",
1319 GTK_UI_MANAGER_MENUITEM,
1320 FALSE);
1321
1322 update_ui (plugin);
1323
1324 docs = pluma_window_get_documents (window);
1325 for (l = docs; l != NULL; l = g_list_next (l))
1326 {
1327 PlumaDocument *doc = PLUMA_DOCUMENT (l->data);
1328
1329 set_auto_spell_from_metadata (plugin, doc,
1330 data->action_group);
1331
1332 g_signal_handlers_disconnect_by_func (doc,
1333 on_document_loaded,
1334 plugin);
1335
1336 g_signal_handlers_disconnect_by_func (doc,
1337 on_document_saved,
1338 plugin);
1339 }
1340
1341 data->tab_added_id =
1342 g_signal_connect (window, "tab-added",
1343 G_CALLBACK (tab_added_cb), plugin);
1344 data->tab_removed_id =
1345 g_signal_connect (window, "tab-removed",
1346 G_CALLBACK (tab_removed_cb), plugin);
1347 }
1348
1349 static void
pluma_spell_plugin_deactivate(PlumaWindowActivatable * activatable)1350 pluma_spell_plugin_deactivate (PlumaWindowActivatable *activatable)
1351 {
1352 PlumaSpellPluginPrivate *data;
1353 PlumaWindow *window;
1354 GtkUIManager *manager;
1355
1356 pluma_debug (DEBUG_PLUGINS);
1357
1358 data = PLUMA_SPELL_PLUGIN (activatable)->priv;
1359 window = PLUMA_WINDOW (data->window);
1360
1361 manager = pluma_window_get_ui_manager (window);
1362
1363 gtk_ui_manager_remove_ui (manager, data->ui_id);
1364 gtk_ui_manager_remove_action_group (manager, data->action_group);
1365
1366 g_signal_handler_disconnect (window, data->tab_added_id);
1367 g_signal_handler_disconnect (window, data->tab_removed_id);
1368 }
1369
1370 static void
pluma_spell_plugin_update_state(PlumaWindowActivatable * activatable)1371 pluma_spell_plugin_update_state (PlumaWindowActivatable *activatable)
1372 {
1373 pluma_debug (DEBUG_PLUGINS);
1374
1375 update_ui (PLUMA_SPELL_PLUGIN (activatable));
1376 }
1377
1378 static void
pluma_spell_plugin_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1379 pluma_spell_plugin_set_property (GObject *object,
1380 guint prop_id,
1381 const GValue *value,
1382 GParamSpec *pspec)
1383 {
1384 PlumaSpellPlugin *plugin = PLUMA_SPELL_PLUGIN (object);
1385
1386 switch (prop_id)
1387 {
1388 case PROP_WINDOW:
1389 plugin->priv->window = PLUMA_WINDOW (g_value_dup_object (value));
1390 break;
1391
1392 default:
1393 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1394 break;
1395 }
1396 }
1397
1398 static void
pluma_spell_plugin_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1399 pluma_spell_plugin_get_property (GObject *object,
1400 guint prop_id,
1401 GValue *value,
1402 GParamSpec *pspec)
1403 {
1404 PlumaSpellPlugin *plugin = PLUMA_SPELL_PLUGIN (object);
1405
1406 switch (prop_id)
1407 {
1408 case PROP_WINDOW:
1409 g_value_set_object (value, plugin->priv->window);
1410 break;
1411
1412 default:
1413 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1414 break;
1415 }
1416 }
1417
1418 static GtkWidget *
pluma_spell_plugin_create_configure_widget(PeasGtkConfigurable * configurable)1419 pluma_spell_plugin_create_configure_widget (PeasGtkConfigurable *configurable)
1420 {
1421 SpellConfigureDialog *dialog;
1422
1423 dialog = get_configure_dialog (PLUMA_SPELL_PLUGIN (configurable));
1424
1425 g_signal_connect (dialog->always,
1426 "toggled",
1427 G_CALLBACK (configure_dialog_button_toggled),
1428 dialog);
1429 g_signal_connect (dialog->document,
1430 "toggled",
1431 G_CALLBACK (configure_dialog_button_toggled),
1432 dialog);
1433 g_signal_connect (dialog->never,
1434 "toggled",
1435 G_CALLBACK (configure_dialog_button_toggled),
1436 dialog);
1437
1438 g_signal_connect (dialog->content,
1439 "destroy",
1440 G_CALLBACK (configure_dialog_destroyed),
1441 dialog);
1442
1443 return dialog->content;
1444 }
1445
1446 static void
pluma_spell_plugin_class_init(PlumaSpellPluginClass * klass)1447 pluma_spell_plugin_class_init (PlumaSpellPluginClass *klass)
1448 {
1449 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1450
1451 object_class->dispose = pluma_spell_plugin_dispose;
1452 object_class->set_property = pluma_spell_plugin_set_property;
1453 object_class->get_property = pluma_spell_plugin_get_property;
1454
1455 g_object_class_override_property (object_class, PROP_WINDOW, "window");
1456
1457 if (spell_checker_id == 0)
1458 spell_checker_id = g_quark_from_string ("PlumaSpellCheckerID");
1459
1460 if (check_range_id == 0)
1461 check_range_id = g_quark_from_string ("CheckRangeID");
1462 }
1463
1464 static void
pluma_spell_plugin_class_finalize(PlumaSpellPluginClass * klass)1465 pluma_spell_plugin_class_finalize (PlumaSpellPluginClass *klass)
1466 {
1467 /* dummy function - used by G_DEFINE_DYNAMIC_TYPE_EXTENDED */
1468 }
1469
1470 static void
pluma_window_activatable_iface_init(PlumaWindowActivatableInterface * iface)1471 pluma_window_activatable_iface_init (PlumaWindowActivatableInterface *iface)
1472 {
1473 iface->activate = pluma_spell_plugin_activate;
1474 iface->deactivate = pluma_spell_plugin_deactivate;
1475 iface->update_state = pluma_spell_plugin_update_state;
1476 }
1477
1478 static void
peas_gtk_configurable_iface_init(PeasGtkConfigurableInterface * iface)1479 peas_gtk_configurable_iface_init (PeasGtkConfigurableInterface *iface)
1480 {
1481 iface->create_configure_widget = pluma_spell_plugin_create_configure_widget;
1482 }
1483
1484 G_MODULE_EXPORT void
peas_register_types(PeasObjectModule * module)1485 peas_register_types (PeasObjectModule *module)
1486 {
1487 pluma_spell_plugin_register_type (G_TYPE_MODULE (module));
1488
1489 peas_object_module_register_extension_type (module,
1490 PLUMA_TYPE_WINDOW_ACTIVATABLE,
1491 PLUMA_TYPE_SPELL_PLUGIN);
1492
1493 peas_object_module_register_extension_type (module,
1494 PEAS_GTK_TYPE_CONFIGURABLE,
1495 PLUMA_TYPE_SPELL_PLUGIN);
1496 }
1497