1 /*
2 * xed-spell-plugin.c
3 *
4 * Copyright (C) 2002-2005 Paolo Maggi
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include <config.h>
22 #include <string.h> /* For strlen */
23 #include <glib/gi18n-lib.h>
24 #include <libpeas-gtk/peas-gtk-configurable.h>
25 #include <xed/xed-app.h>
26 #include <xed/xed-window.h>
27 #include <xed/xed-window-activatable.h>
28 #include <xed/xed-debug.h>
29 #include <xed/xed-utils.h>
30 #include <gspell/gspell.h>
31
32 #include "xed-spell-plugin.h"
33
34 #define XED_METADATA_ATTRIBUTE_SPELL_LANGUAGE "metadata::xed-spell-language"
35 #define XED_METADATA_ATTRIBUTE_SPELL_ENABLED "metadata::xed-spell-enabled"
36
37 #define SPELL_ENABLED_STR "1"
38
39 #define MENU_PATH "/MenuBar/ToolsMenu/ToolsOps_1"
40
41 /* GSettings keys */
42 #define SPELL_SCHEMA "org.x.editor.plugins.spell"
43 #define AUTOCHECK_TYPE_KEY "autocheck-type"
44
45 static void xed_window_activatable_iface_init (XedWindowActivatableInterface *iface);
46 static void peas_gtk_configurable_iface_init (PeasGtkConfigurableInterface *iface);
47
48 struct _XedSpellPluginPrivate
49 {
50 XedWindow *window;
51
52 GtkActionGroup *action_group;
53 guint ui_id;
54
55 GSettings *settings;
56 };
57
58 enum
59 {
60 PROP_0,
61 PROP_WINDOW
62 };
63
64 G_DEFINE_DYNAMIC_TYPE_EXTENDED (XedSpellPlugin,
65 xed_spell_plugin,
66 PEAS_TYPE_EXTENSION_BASE,
67 0,
68 G_IMPLEMENT_INTERFACE_DYNAMIC (XED_TYPE_WINDOW_ACTIVATABLE,
69 xed_window_activatable_iface_init)
70 G_IMPLEMENT_INTERFACE_DYNAMIC (PEAS_GTK_TYPE_CONFIGURABLE,
71 peas_gtk_configurable_iface_init)
72 G_ADD_PRIVATE_DYNAMIC (XedSpellPlugin))
73
74 static void check_spell_cb (GtkAction *action,
75 XedSpellPlugin *plugin);
76 static void set_language_cb (GtkAction *action,
77 XedSpellPlugin *plugin);
78 static void inline_checker_cb (GtkAction *action,
79 XedSpellPlugin *plugin);
80
81 /* UI actions. */
82 static const GtkActionEntry action_entries[] =
83 {
84 { "CheckSpell",
85 "tools-check-spelling-symbolic",
86 N_("_Check Spelling..."),
87 "<shift>F7",
88 N_("Check the current document for incorrect spelling"),
89 G_CALLBACK (check_spell_cb)
90 },
91
92 { "ConfigSpell",
93 NULL,
94 N_("Set _Language..."),
95 NULL,
96 N_("Set the language of the current document"),
97 G_CALLBACK (set_language_cb)
98 }
99 };
100
101 static const GtkToggleActionEntry toggle_action_entries[] =
102 {
103 { "InlineSpellChecker",
104 NULL,
105 N_("_Autocheck Spelling"),
106 NULL,
107 N_("Automatically spell-check the current document"),
108 G_CALLBACK (inline_checker_cb),
109 FALSE
110 }
111 };
112
113 typedef struct _SpellConfigureWidget SpellConfigureWidget;
114
115 struct _SpellConfigureWidget
116 {
117 GtkWidget *content;
118
119 GtkWidget *never;
120 GtkWidget *always;
121 GtkWidget *document;
122
123 GSettings *settings;
124 };
125
126 typedef enum
127 {
128 AUTOCHECK_NEVER = 0,
129 AUTOCHECK_DOCUMENT,
130 AUTOCHECK_ALWAYS
131 } XedSpellPluginAutocheckType;
132
133 static void
xed_spell_plugin_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)134 xed_spell_plugin_set_property (GObject *object,
135 guint prop_id,
136 const GValue *value,
137 GParamSpec *pspec)
138 {
139 XedSpellPlugin *plugin = XED_SPELL_PLUGIN (object);
140
141 switch (prop_id)
142 {
143 case PROP_WINDOW:
144 plugin->priv->window = XED_WINDOW (g_value_dup_object (value));
145 break;
146 default:
147 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
148 break;
149 }
150 }
151
152 static void
xed_spell_plugin_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)153 xed_spell_plugin_get_property (GObject *object,
154 guint prop_id,
155 GValue *value,
156 GParamSpec *pspec)
157 {
158 XedSpellPlugin *plugin = XED_SPELL_PLUGIN (object);
159
160 switch (prop_id)
161 {
162 case PROP_WINDOW:
163 g_value_set_object (value, plugin->priv->window);
164 break;
165 default:
166 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
167 break;
168 }
169 }
170
171 static void
xed_spell_plugin_dispose(GObject * object)172 xed_spell_plugin_dispose (GObject *object)
173 {
174 XedSpellPlugin *plugin = XED_SPELL_PLUGIN (object);
175
176 xed_debug_message (DEBUG_PLUGINS, "XedSpellPlugin disposing");
177
178 g_clear_object (&plugin->priv->settings);
179 g_clear_object (&plugin->priv->window);
180 g_clear_object (&plugin->priv->action_group);
181 g_clear_object (&plugin->priv->settings);
182
183 G_OBJECT_CLASS (xed_spell_plugin_parent_class)->dispose (object);
184 }
185
186 static void
xed_spell_plugin_class_init(XedSpellPluginClass * klass)187 xed_spell_plugin_class_init (XedSpellPluginClass *klass)
188 {
189 GObjectClass *object_class = G_OBJECT_CLASS (klass);
190
191 object_class->dispose = xed_spell_plugin_dispose;
192 object_class->set_property = xed_spell_plugin_set_property;
193 object_class->get_property = xed_spell_plugin_get_property;
194
195 g_object_class_override_property (object_class, PROP_WINDOW, "window");
196 }
197
198 static void
xed_spell_plugin_class_finalize(XedSpellPluginClass * klass)199 xed_spell_plugin_class_finalize (XedSpellPluginClass *klass)
200 {
201 }
202
203 static void
xed_spell_plugin_init(XedSpellPlugin * plugin)204 xed_spell_plugin_init (XedSpellPlugin *plugin)
205 {
206 xed_debug_message (DEBUG_PLUGINS, "XedSpellPlugin initializing");
207
208 plugin->priv = xed_spell_plugin_get_instance_private (plugin);
209
210 plugin->priv->settings = g_settings_new (SPELL_SCHEMA);
211 }
212
213 static GspellChecker *
get_spell_checker(XedDocument * doc)214 get_spell_checker (XedDocument *doc)
215 {
216 GspellTextBuffer *gspell_buffer;
217
218 gspell_buffer = gspell_text_buffer_get_from_gtk_text_buffer (GTK_TEXT_BUFFER (doc));
219 return gspell_text_buffer_get_spell_checker (gspell_buffer);
220 }
221
222 static const GspellLanguage *
get_language_from_metadata(XedDocument * doc)223 get_language_from_metadata (XedDocument *doc)
224 {
225 const GspellLanguage *lang = NULL;
226 gchar *language_code = NULL;
227
228 language_code = xed_document_get_metadata (doc, XED_METADATA_ATTRIBUTE_SPELL_LANGUAGE);
229
230 if (language_code != NULL)
231 {
232 lang = gspell_language_lookup (language_code);
233 g_free (language_code);
234 }
235
236 return lang;
237 }
238
239 static void
check_spell_cb(GtkAction * action,XedSpellPlugin * plugin)240 check_spell_cb (GtkAction *action,
241 XedSpellPlugin *plugin)
242 {
243 XedSpellPluginPrivate *priv;
244 XedView *view;
245 GspellNavigator *navigator;
246 GtkWidget *dialog;
247
248 xed_debug (DEBUG_PLUGINS);
249
250 priv = plugin->priv;
251
252 view = xed_window_get_active_view (priv->window);
253 g_return_if_fail (view != NULL);
254
255 navigator = gspell_navigator_text_view_new (GTK_TEXT_VIEW (view));
256 dialog = gspell_checker_dialog_new (GTK_WINDOW (priv->window), navigator);
257
258 gtk_widget_show (dialog);
259 }
260
261 static XedSpellPluginAutocheckType
get_autocheck_type(XedSpellPlugin * plugin)262 get_autocheck_type (XedSpellPlugin *plugin)
263 {
264 XedSpellPluginAutocheckType autocheck_type;
265
266 autocheck_type = g_settings_get_enum (plugin->priv->settings, AUTOCHECK_TYPE_KEY);
267
268 return autocheck_type;
269 }
270
271 static void
set_autocheck_type(GSettings * settings,XedSpellPluginAutocheckType autocheck_type)272 set_autocheck_type (GSettings *settings,
273 XedSpellPluginAutocheckType autocheck_type)
274 {
275 if (!g_settings_is_writable (settings, AUTOCHECK_TYPE_KEY))
276 {
277 return;
278 }
279
280 g_settings_set_enum (settings, AUTOCHECK_TYPE_KEY, autocheck_type);
281 }
282
283 static void
language_dialog_response_cb(GtkDialog * dialog,gint response_id,gpointer user_data)284 language_dialog_response_cb (GtkDialog *dialog,
285 gint response_id,
286 gpointer user_data)
287 {
288 if (response_id == GTK_RESPONSE_HELP)
289 {
290 xed_app_show_help (XED_APP (g_application_get_default ()),
291 GTK_WINDOW (dialog),
292 NULL,
293 "xed-spell-checker-plugin");
294 return;
295 }
296
297 gtk_widget_destroy (GTK_WIDGET (dialog));
298 }
299
300 static void
configure_widget_button_toggled(GtkToggleButton * button,SpellConfigureWidget * conf_widget)301 configure_widget_button_toggled (GtkToggleButton *button,
302 SpellConfigureWidget *conf_widget)
303 {
304 xed_debug (DEBUG_PLUGINS);
305
306 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (conf_widget->always)))
307 {
308 set_autocheck_type (conf_widget->settings, AUTOCHECK_ALWAYS);
309 }
310 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (conf_widget->document)))
311 {
312 set_autocheck_type (conf_widget->settings, AUTOCHECK_DOCUMENT);
313 }
314 else
315 {
316 set_autocheck_type (conf_widget->settings, AUTOCHECK_NEVER);
317 }
318 }
319
320 static void
configure_widget_destroyed(GtkWidget * widget,gpointer data)321 configure_widget_destroyed (GtkWidget *widget,
322 gpointer data)
323 {
324 SpellConfigureWidget *conf_widget = (SpellConfigureWidget *)data;
325
326 xed_debug (DEBUG_PLUGINS);
327
328 g_object_unref (conf_widget->settings);
329 g_slice_free (SpellConfigureWidget, data);
330
331 xed_debug_message (DEBUG_PLUGINS, "END");
332 }
333
334 static SpellConfigureWidget *
get_configure_widget(XedSpellPlugin * plugin)335 get_configure_widget (XedSpellPlugin *plugin)
336 {
337 SpellConfigureWidget *widget;
338 gchar *data_dir;
339 gchar *ui_file;
340 XedSpellPluginAutocheckType autocheck_type;
341 GtkWidget *error_widget;
342 gboolean ret;
343 gchar *root_objects[] = {
344 "spell_dialog_content",
345 NULL
346 };
347
348 xed_debug (DEBUG_PLUGINS);
349
350 widget = g_slice_new (SpellConfigureWidget);
351 widget->settings = g_object_ref (plugin->priv->settings);
352
353 data_dir = peas_extension_base_get_data_dir (PEAS_EXTENSION_BASE (plugin));
354 ui_file = g_build_filename (data_dir, "xed-spell-setup-dialog.ui", NULL);
355 ret = xed_utils_get_ui_objects (ui_file,
356 root_objects,
357 &error_widget,
358 "spell_dialog_content", &widget->content,
359 "autocheck_never", &widget->never,
360 "autocheck_document", &widget->document,
361 "autocheck_always", &widget->always,
362 NULL);
363
364 g_free (data_dir);
365 g_free (ui_file);
366
367 if (!ret)
368 {
369 return NULL;
370 }
371
372 autocheck_type = get_autocheck_type (plugin);
373
374 if (autocheck_type == AUTOCHECK_ALWAYS)
375 {
376 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget->always), TRUE);
377 }
378 else if (autocheck_type == AUTOCHECK_DOCUMENT)
379 {
380 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget->document), TRUE);
381 }
382 else
383 {
384 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget->never), TRUE);
385 }
386
387 g_signal_connect (widget->always, "toggled",
388 G_CALLBACK (configure_widget_button_toggled), widget);
389 g_signal_connect (widget->document, "toggled",
390 G_CALLBACK (configure_widget_button_toggled), widget);
391 g_signal_connect (widget->never, "toggled",
392 G_CALLBACK (configure_widget_button_toggled), widget);
393 g_signal_connect (widget->content, "destroy",
394 G_CALLBACK (configure_widget_destroyed), widget);
395
396 return widget;
397 }
398
399 static void
set_language_cb(GtkAction * action,XedSpellPlugin * plugin)400 set_language_cb (GtkAction *action,
401 XedSpellPlugin *plugin)
402 {
403 XedSpellPluginPrivate *priv;
404 XedDocument *doc;
405 GspellChecker *checker;
406 const GspellLanguage *lang;
407 GtkWidget *dialog;
408 GtkWindowGroup *window_group;
409
410 xed_debug (DEBUG_PLUGINS);
411
412 priv = plugin->priv;
413
414 doc = xed_window_get_active_document (priv->window);
415 g_return_if_fail (doc != NULL);
416
417 checker = get_spell_checker (doc);
418 g_return_if_fail (checker != NULL);
419
420 lang = gspell_checker_get_language (checker);
421
422 dialog = gspell_language_chooser_dialog_new (GTK_WINDOW (priv->window),
423 lang,
424 GTK_DIALOG_MODAL |
425 GTK_DIALOG_DESTROY_WITH_PARENT);
426
427 g_object_bind_property (dialog, "language",
428 checker, "language",
429 G_BINDING_DEFAULT);
430
431 window_group = xed_window_get_group (priv->window);
432
433 gtk_window_group_add_window (window_group, GTK_WINDOW (dialog));
434
435 gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Help"), GTK_RESPONSE_HELP);
436
437 g_signal_connect (dialog, "response",
438 G_CALLBACK (language_dialog_response_cb), NULL);
439
440 gtk_widget_show (dialog);
441 }
442
443 static void
inline_checker_cb(GtkAction * action,XedSpellPlugin * plugin)444 inline_checker_cb (GtkAction *action,
445 XedSpellPlugin *plugin)
446 {
447 XedSpellPluginPrivate *priv;
448 XedView *view;
449 gboolean active;
450
451 xed_debug (DEBUG_PLUGINS);
452
453 priv = plugin->priv;
454 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
455
456 xed_debug_message (DEBUG_PLUGINS, active ? "Inline Checker activated" : "Inline Checker deactivated");
457
458 view = xed_window_get_active_view (priv->window);
459 if (view != NULL)
460 {
461 XedDocument *doc;
462 GspellTextView *gspell_view;
463
464 doc = XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
465
466 if (get_autocheck_type (plugin) == AUTOCHECK_DOCUMENT)
467 {
468 xed_document_set_metadata (doc,
469 XED_METADATA_ATTRIBUTE_SPELL_ENABLED,
470 active ? SPELL_ENABLED_STR : NULL,
471 NULL);
472 }
473
474 gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (view));
475 gspell_text_view_set_inline_spell_checking (gspell_view, active);
476 }
477 }
478
479 static void
update_ui(XedSpellPlugin * plugin)480 update_ui (XedSpellPlugin *plugin)
481 {
482 XedSpellPluginPrivate *priv;
483 XedView *view;
484 GtkAction *action;
485
486 xed_debug (DEBUG_PLUGINS);
487
488 priv = plugin->priv;
489
490 view = xed_window_get_active_view (priv->window);
491
492 if (view != NULL)
493 {
494 XedTab *tab;
495
496 tab = xed_window_get_active_tab (priv->window);
497 g_return_if_fail (xed_tab_get_view (tab) == view);
498
499 /* If the document is loading we can't get the metadata so we
500 endup with an useless speller */
501 if (xed_tab_get_state (tab) == XED_TAB_STATE_NORMAL)
502 {
503 GspellTextView *gspell_view;
504 gboolean inline_checking_enabled;
505
506 gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (view));
507 inline_checking_enabled = gspell_text_view_get_inline_spell_checking (gspell_view);
508
509 action = gtk_action_group_get_action (priv->action_group, "InlineSpellChecker");
510
511 g_signal_handlers_block_by_func (action, inline_checker_cb, plugin);
512 gspell_text_view_set_inline_spell_checking (gspell_view, inline_checking_enabled);
513 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), inline_checking_enabled);
514 g_signal_handlers_unblock_by_func (action, inline_checker_cb, plugin);
515 }
516 }
517
518 gtk_action_group_set_sensitive (priv->action_group,
519 (view != NULL) &&
520 gtk_text_view_get_editable (GTK_TEXT_VIEW (view)));
521 }
522
523 static void
setup_inline_checker_from_metadata(XedSpellPlugin * plugin,XedView * view)524 setup_inline_checker_from_metadata (XedSpellPlugin *plugin,
525 XedView *view)
526 {
527 XedSpellPluginPrivate *priv;
528 XedDocument *doc;
529 gboolean enabled = FALSE;
530 gchar *enabled_str = NULL;
531 GspellTextView *gspell_view;
532 XedView *active_view;
533 XedSpellPluginAutocheckType autocheck_type;
534
535 priv = plugin->priv;
536
537 autocheck_type = get_autocheck_type (plugin);
538
539 doc = XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
540
541 switch (autocheck_type)
542 {
543 case AUTOCHECK_ALWAYS:
544 {
545 enabled = TRUE;
546 break;
547 }
548 case AUTOCHECK_DOCUMENT:
549 {
550 enabled_str = xed_document_get_metadata (doc, XED_METADATA_ATTRIBUTE_SPELL_ENABLED);
551 break;
552 }
553 case AUTOCHECK_NEVER:
554 default:
555 enabled = FALSE;
556 break;
557 }
558
559 if (enabled_str != NULL)
560 {
561 enabled = g_str_equal (enabled_str, SPELL_ENABLED_STR);
562 g_free (enabled_str);
563 }
564
565 gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (view));
566 gspell_text_view_set_inline_spell_checking (gspell_view, enabled);
567
568 /* In case that the view is the active one we mark the spell action */
569 active_view = xed_window_get_active_view (plugin->priv->window);
570
571 if (active_view == view && priv->action_group != NULL)
572 {
573 GtkAction *action;
574
575 action = gtk_action_group_get_action (priv->action_group, "InlineSpellChecker");
576
577 g_signal_handlers_block_by_func (action, inline_checker_cb, plugin);
578 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), enabled);
579 g_signal_handlers_unblock_by_func (action, inline_checker_cb, plugin);
580 }
581 }
582
583 static void
language_notify_cb(GspellChecker * checker,GParamSpec * pspec,XedDocument * doc)584 language_notify_cb (GspellChecker *checker,
585 GParamSpec *pspec,
586 XedDocument *doc)
587 {
588 const GspellLanguage *lang;
589 const gchar *language_code;
590
591 g_return_if_fail (XED_IS_DOCUMENT (doc));
592
593 lang = gspell_checker_get_language (checker);
594 g_return_if_fail (lang != NULL);
595
596 language_code = gspell_language_get_code (lang);
597 g_return_if_fail (language_code != NULL);
598
599 xed_document_set_metadata (doc, XED_METADATA_ATTRIBUTE_SPELL_LANGUAGE, language_code, NULL);
600 }
601
602 static void
on_document_loaded(XedDocument * doc,XedSpellPlugin * plugin)603 on_document_loaded (XedDocument *doc,
604 XedSpellPlugin *plugin)
605 {
606
607 GspellChecker *checker;
608 XedTab *tab;
609 XedView *view;
610
611 checker = get_spell_checker (doc);
612
613 if (checker != NULL)
614 {
615 const GspellLanguage *lang;
616
617 lang = get_language_from_metadata (doc);
618
619 if (lang != NULL)
620 {
621 g_signal_handlers_block_by_func (checker, language_notify_cb, doc);
622 gspell_checker_set_language (checker, lang);
623 g_signal_handlers_unblock_by_func (checker, language_notify_cb, doc);
624 }
625 }
626
627 tab = xed_tab_get_from_document (doc);
628 view = xed_tab_get_view (tab);
629 setup_inline_checker_from_metadata (plugin, view);
630 }
631
632 static void
on_document_saved(XedDocument * doc,XedSpellPlugin * plugin)633 on_document_saved (XedDocument *doc,
634 XedSpellPlugin *plugin)
635 {
636 XedTab *tab;
637 XedView *view;
638 GspellChecker *checker;
639 const gchar *language_code = NULL;
640 GspellTextView *gspell_view;
641 gboolean inline_checking_enabled;
642
643 /* Make sure to save the metadata here too */
644 checker = get_spell_checker (doc);
645
646 if (checker != NULL)
647 {
648 const GspellLanguage *lang;
649
650 lang = gspell_checker_get_language (checker);
651 if (lang != NULL)
652 {
653 language_code = gspell_language_get_code (lang);
654 }
655 }
656
657 tab = xed_tab_get_from_document (doc);
658 view = xed_tab_get_view (tab);
659
660 gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (view));
661 inline_checking_enabled = gspell_text_view_get_inline_spell_checking (gspell_view);
662
663 if (get_autocheck_type (plugin) == AUTOCHECK_DOCUMENT)
664 {
665
666 xed_document_set_metadata (doc,
667 XED_METADATA_ATTRIBUTE_SPELL_ENABLED,
668 inline_checking_enabled ? SPELL_ENABLED_STR : NULL,
669 XED_METADATA_ATTRIBUTE_SPELL_LANGUAGE,
670 language_code,
671 NULL);
672 }
673 else
674 {
675 xed_document_set_metadata (doc, XED_METADATA_ATTRIBUTE_SPELL_LANGUAGE, language_code, NULL);
676 }
677 }
678
679 static void
activate_spell_checking_in_view(XedSpellPlugin * plugin,XedView * view)680 activate_spell_checking_in_view (XedSpellPlugin *plugin,
681 XedView *view)
682 {
683 XedDocument *doc;
684
685 doc = XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
686
687 /* It is possible that a GspellChecker has already been set, for example
688 * if a XedTab has moved to another window.
689 */
690 if (get_spell_checker (doc) == NULL)
691 {
692 const GspellLanguage *lang;
693 GspellChecker *checker;
694 GspellTextBuffer *gspell_buffer;
695
696 lang = get_language_from_metadata (doc);
697 checker = gspell_checker_new (lang);
698
699 g_signal_connect_object (checker, "notify::language",
700 G_CALLBACK (language_notify_cb), doc, 0);
701
702 gspell_buffer = gspell_text_buffer_get_from_gtk_text_buffer (GTK_TEXT_BUFFER (doc));
703 gspell_text_buffer_set_spell_checker (gspell_buffer, checker);
704 g_object_unref (checker);
705
706 setup_inline_checker_from_metadata (plugin, view);
707 }
708
709 g_signal_connect_object (doc, "loaded",
710 G_CALLBACK (on_document_loaded), plugin, 0);
711 g_signal_connect_object (doc, "saved",
712 G_CALLBACK (on_document_saved), plugin, 0);
713 }
714
715 static void
disconnect_view(XedSpellPlugin * plugin,XedView * view)716 disconnect_view (XedSpellPlugin *plugin,
717 XedView *view)
718 {
719 GtkTextBuffer *buffer;
720
721 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
722
723 /* It should still be the same buffer as the one where the signal
724 * handlers were connected. If not, we assume that the old buffer is
725 * finalized. And it is anyway safe to call
726 * g_signal_handlers_disconnect_by_func() if no signal handlers are
727 * found.
728 */
729 g_signal_handlers_disconnect_by_func (buffer, on_document_loaded, plugin);
730 g_signal_handlers_disconnect_by_func (buffer, on_document_saved, plugin);
731 }
732
733 static void
deactivate_spell_checking_in_view(XedSpellPlugin * plugin,XedView * view)734 deactivate_spell_checking_in_view (XedSpellPlugin *plugin,
735 XedView *view)
736 {
737 GtkTextBuffer *gtk_buffer;
738 GspellTextBuffer *gspell_buffer;
739 GspellTextView *gspell_view;
740
741 disconnect_view (plugin, view);
742
743 gtk_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
744 gspell_buffer = gspell_text_buffer_get_from_gtk_text_buffer (gtk_buffer);
745 gspell_text_buffer_set_spell_checker (gspell_buffer, NULL);
746
747 gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (view));
748 gspell_text_view_set_inline_spell_checking (gspell_view, FALSE);
749 }
750
751 static void
tab_added_cb(XedWindow * window,XedTab * tab,XedSpellPlugin * plugin)752 tab_added_cb (XedWindow *window,
753 XedTab *tab,
754 XedSpellPlugin *plugin)
755 {
756 activate_spell_checking_in_view (plugin, xed_tab_get_view (tab));
757 }
758
759 static void
tab_removed_cb(XedWindow * window,XedTab * tab,XedSpellPlugin * plugin)760 tab_removed_cb (XedWindow *window,
761 XedTab *tab,
762 XedSpellPlugin *plugin)
763 {
764 /* Don't deactivate completely the spell checking in @tab, since the tab
765 * can be moved to another window and we don't want to loose the spell
766 * checking settings (they are not saved in metadata for unsaved
767 * documents).
768 */
769 disconnect_view (plugin, xed_tab_get_view (tab));
770 }
771
772 static void
xed_spell_plugin_activate(XedWindowActivatable * activatable)773 xed_spell_plugin_activate (XedWindowActivatable *activatable)
774 {
775 XedSpellPlugin *plugin;
776 XedSpellPluginPrivate *priv;
777 GtkUIManager *manager;
778 GList *views;
779 GList *l;
780
781 xed_debug (DEBUG_PLUGINS);
782
783 plugin = XED_SPELL_PLUGIN (activatable);
784 priv = plugin->priv;
785
786 manager = xed_window_get_ui_manager (priv->window);
787
788 priv->action_group = gtk_action_group_new ("XedSpellPluginActions");
789 gtk_action_group_set_translation_domain (priv->action_group, GETTEXT_PACKAGE);
790 gtk_action_group_add_actions (priv->action_group,
791 action_entries,
792 G_N_ELEMENTS (action_entries),
793 activatable);
794 gtk_action_group_add_toggle_actions (priv->action_group,
795 toggle_action_entries,
796 G_N_ELEMENTS (toggle_action_entries),
797 activatable);
798
799 gtk_ui_manager_insert_action_group (manager, priv->action_group, -1);
800
801 priv->ui_id = gtk_ui_manager_new_merge_id (manager);
802
803 gtk_ui_manager_add_ui (manager,
804 priv->ui_id,
805 MENU_PATH,
806 "CheckSpell",
807 "CheckSpell",
808 GTK_UI_MANAGER_MENUITEM,
809 FALSE);
810
811 gtk_ui_manager_add_ui (manager,
812 priv->ui_id,
813 MENU_PATH,
814 "InlineSpellChecker",
815 "InlineSpellChecker",
816 GTK_UI_MANAGER_MENUITEM,
817 FALSE);
818
819 gtk_ui_manager_add_ui (manager,
820 priv->ui_id,
821 MENU_PATH,
822 "ConfigSpell",
823 "ConfigSpell",
824 GTK_UI_MANAGER_MENUITEM,
825 FALSE);
826
827 update_ui (XED_SPELL_PLUGIN (activatable));
828
829 views = xed_window_get_views (priv->window);
830 for (l = views; l != NULL; l = l->next)
831 {
832 activate_spell_checking_in_view (plugin, XED_VIEW (l->data));
833 }
834
835 g_signal_connect (priv->window, "tab-added",
836 G_CALLBACK (tab_added_cb), activatable);
837 g_signal_connect (priv->window, "tab-removed",
838 G_CALLBACK (tab_removed_cb), activatable);
839 }
840
841 static void
xed_spell_plugin_deactivate(XedWindowActivatable * activatable)842 xed_spell_plugin_deactivate (XedWindowActivatable *activatable)
843 {
844 XedSpellPlugin *plugin;
845 XedSpellPluginPrivate *priv;
846 GtkUIManager *manager;
847 GList *views;
848 GList *l;
849
850 xed_debug (DEBUG_PLUGINS);
851
852 plugin = XED_SPELL_PLUGIN (activatable);
853 priv = plugin->priv;
854 manager = xed_window_get_ui_manager (priv->window);
855
856 gtk_ui_manager_remove_ui (manager, priv->ui_id);
857 gtk_ui_manager_remove_action_group (manager, priv->action_group);
858
859 g_signal_handlers_disconnect_by_func (priv->window, tab_added_cb, activatable);
860 g_signal_handlers_disconnect_by_func (priv->window, tab_removed_cb, activatable);
861
862 views = xed_window_get_views (priv->window);
863 for (l = views; l != NULL; l = l->next)
864 {
865 deactivate_spell_checking_in_view (plugin, XED_VIEW (l->data));
866 }
867 }
868
869 static void
xed_spell_plugin_update_state(XedWindowActivatable * activatable)870 xed_spell_plugin_update_state (XedWindowActivatable *activatable)
871 {
872 xed_debug (DEBUG_PLUGINS);
873
874 update_ui (XED_SPELL_PLUGIN (activatable));
875 }
876
877 static GtkWidget *
xed_spell_plugin_create_configure_widget(PeasGtkConfigurable * configurable)878 xed_spell_plugin_create_configure_widget (PeasGtkConfigurable *configurable)
879 {
880 SpellConfigureWidget *widget;
881
882 widget = get_configure_widget (XED_SPELL_PLUGIN (configurable));
883
884 return widget->content;
885 }
886
887 static void
xed_window_activatable_iface_init(XedWindowActivatableInterface * iface)888 xed_window_activatable_iface_init (XedWindowActivatableInterface *iface)
889 {
890 iface->activate = xed_spell_plugin_activate;
891 iface->deactivate = xed_spell_plugin_deactivate;
892 iface->update_state = xed_spell_plugin_update_state;
893 }
894
895 static void
peas_gtk_configurable_iface_init(PeasGtkConfigurableInterface * iface)896 peas_gtk_configurable_iface_init (PeasGtkConfigurableInterface *iface)
897 {
898 iface->create_configure_widget = xed_spell_plugin_create_configure_widget;
899 }
900
901 G_MODULE_EXPORT void
peas_register_types(PeasObjectModule * module)902 peas_register_types (PeasObjectModule *module)
903 {
904 xed_spell_plugin_register_type (G_TYPE_MODULE (module));
905
906 peas_object_module_register_extension_type (module,
907 XED_TYPE_WINDOW_ACTIVATABLE,
908 XED_TYPE_SPELL_PLUGIN);
909
910 peas_object_module_register_extension_type (module,
911 PEAS_GTK_TYPE_CONFIGURABLE,
912 XED_TYPE_SPELL_PLUGIN);
913 }
914