[gnome-builder] spellcheck: get the spellcheck plugin working again
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] spellcheck: get the spellcheck plugin working again
- Date: Wed, 19 Jul 2017 11:21:45 +0000 (UTC)
commit bdfa87d2cd7275033388cca7b77e020f4d0a4944
Author: Christian Hergert <chergert redhat com>
Date: Sun Jul 16 21:56:37 2017 -0700
spellcheck: get the spellcheck plugin working again
This mostly finishes the port to get the spellcheck plugin in working
order again.
It still needs fit and polish, but that can mostly happen after we
things merged to master.
data/gtk/menus.ui | 2 +
libide/sourceview/ide-source-style-scheme.c | 6 +-
plugins/spellcheck/gbp-spell-buffer-addin.c | 8 +
plugins/spellcheck/gbp-spell-dict.c | 19 +-
plugins/spellcheck/gbp-spell-editor-addin.c | 77 +++-
plugins/spellcheck/gbp-spell-editor-view-addin.c | 444 +++-----------
plugins/spellcheck/gbp-spell-editor-view-addin.h | 10 +-
plugins/spellcheck/gbp-spell-language-popover.c | 4 +-
plugins/spellcheck/gbp-spell-navigator.c | 89 ++-
plugins/spellcheck/gbp-spell-private.h | 97 +++
plugins/spellcheck/gbp-spell-widget-actions.c | 163 +++++
plugins/spellcheck/gbp-spell-widget.c | 731 +++++++++-------------
plugins/spellcheck/gbp-spell-widget.h | 16 +-
plugins/spellcheck/gbp-spell-widget.ui | 103 +--
plugins/spellcheck/gtk/menus.ui | 6 +
plugins/spellcheck/meson.build | 1 +
16 files changed, 854 insertions(+), 922 deletions(-)
---
diff --git a/data/gtk/menus.ui b/data/gtk/menus.ui
index a655429..a813bcf 100644
--- a/data/gtk/menus.ui
+++ b/data/gtk/menus.ui
@@ -135,6 +135,8 @@
<attribute name="action">sourceview.delete-selection</attribute>
</item>
</section>
+ <section id="ide-source-view-popup-menu-spellcheck-section">
+ </section>
<section id="ide-source-view-popup-menu-highlighting-section">
<submenu id="ide-source-view-popup-menu-highlighting-submenu">
<attribute name="label" translatable="yes">Highlighting</attribute>
diff --git a/libide/sourceview/ide-source-style-scheme.c b/libide/sourceview/ide-source-style-scheme.c
index dcfef6e..19982eb 100644
--- a/libide/sourceview/ide-source-style-scheme.c
+++ b/libide/sourceview/ide-source-style-scheme.c
@@ -65,11 +65,11 @@ ide_source_style_scheme_apply_style (GtkSourceStyleScheme *style_scheme,
g_snprintf (defname, sizeof defname, "def%s", colon);
style = gtk_source_style_scheme_get_style (style_scheme, defname);
-
- if (style == NULL)
- return FALSE;
}
+ if (style == NULL)
+ return FALSE;
+
g_object_get (style,
"background", &background,
"background-set", &background_set,
diff --git a/plugins/spellcheck/gbp-spell-buffer-addin.c b/plugins/spellcheck/gbp-spell-buffer-addin.c
index c4d8e47..e93c69f 100644
--- a/plugins/spellcheck/gbp-spell-buffer-addin.c
+++ b/plugins/spellcheck/gbp-spell-buffer-addin.c
@@ -73,8 +73,16 @@ gbp_spell_buffer_addin_apply (GbpSpellBufferAddin *self)
if (!gbp_spell_buffer_addin_get_enabled (self))
{
+ GtkTextIter begin;
+ GtkTextIter end;
+
gspell_text_buffer_set_spell_checker (spell_buffer, NULL);
g_clear_object (&self->spellchecker);
+
+ gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (self->buffer), &begin, &end);
+ gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (self->buffer),
+ self->misspelled_tag, &begin, &end);
+
return;
}
diff --git a/plugins/spellcheck/gbp-spell-dict.c b/plugins/spellcheck/gbp-spell-dict.c
index 3d1f2d8..eaa003d 100644
--- a/plugins/spellcheck/gbp-spell-dict.c
+++ b/plugins/spellcheck/gbp-spell-dict.c
@@ -175,21 +175,10 @@ gbp_spell_dict_personal_contains (GbpSpellDict *self,
{
g_assert (GBP_IS_SPELL_DICT (self));
- if (ide_str_empty0 (word))
- return FALSE;
+ if (self->words != NULL && !ide_str_empty0 (word))
+ return g_hash_table_contains (self->words, word);
- if (self->dict != NULL)
- {
- if (self->words == NULL)
- return FALSE;
-
- return (NULL != g_hash_table_lookup (self->words, word));
- }
- else
- {
- g_warning ("No dictionaries loaded");
- return FALSE;
- }
+ return FALSE;
}
gboolean
@@ -210,7 +199,7 @@ gbp_spell_dict_add_word_to_personal (GbpSpellDict *self,
}
else
{
- g_warning ("No dictionaries loaded");
+ g_warning ("No dictionaries loaded, cannot add word");
return FALSE;
}
}
diff --git a/plugins/spellcheck/gbp-spell-editor-addin.c b/plugins/spellcheck/gbp-spell-editor-addin.c
index b84e322..2cb5bf9 100644
--- a/plugins/spellcheck/gbp-spell-editor-addin.c
+++ b/plugins/spellcheck/gbp-spell-editor-addin.c
@@ -21,12 +21,16 @@
#include <glib/gi18n.h>
#include "gbp-spell-editor-addin.h"
+#include "gbp-spell-private.h"
struct _GbpSpellEditorAddin
{
- GObject parent_instance;
+ GObject parent_instance;
- DzlDockWidget *dock;
+ IdeEditorPerspective *editor;
+
+ DzlDockWidget *dock;
+ GbpSpellWidget *widget;
};
static void
@@ -39,6 +43,8 @@ gbp_spell_editor_addin_load (IdeEditorAddin *addin,
g_assert (GBP_IS_SPELL_EDITOR_ADDIN (self));
g_assert (IDE_IS_EDITOR_PERSPECTIVE (editor));
+ self->editor = editor;
+
sidebar = ide_editor_perspective_get_transient_sidebar (editor);
self->dock = g_object_new (DZL_TYPE_DOCK_WIDGET,
@@ -51,6 +57,15 @@ gbp_spell_editor_addin_load (IdeEditorAddin *addin,
G_CALLBACK (gtk_widget_destroyed),
&self->dock);
gtk_container_add (GTK_CONTAINER (sidebar), GTK_WIDGET (self->dock));
+
+ self->widget = g_object_new (GBP_TYPE_SPELL_WIDGET,
+ "visible", TRUE,
+ NULL);
+ g_signal_connect (self->widget,
+ "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &self->widget);
+ gtk_container_add (GTK_CONTAINER (self->dock), GTK_WIDGET (self->widget));
}
static void
@@ -64,6 +79,11 @@ gbp_spell_editor_addin_unload (IdeEditorAddin *addin,
if (self->dock != NULL)
gtk_widget_destroy (GTK_WIDGET (self->dock));
+
+ if (self->widget != NULL)
+ gtk_widget_destroy (GTK_WIDGET (self->widget));
+
+ self->editor = NULL;
}
static void
@@ -71,14 +91,31 @@ gbp_spell_editor_addin_view_set (IdeEditorAddin *addin,
IdeLayoutView *view)
{
GbpSpellEditorAddin *self = (GbpSpellEditorAddin *)addin;
+ IdeEditorView *current;
g_assert (GBP_IS_SPELL_EDITOR_ADDIN (self));
g_assert (!view || IDE_IS_LAYOUT_VIEW (view));
- if (!IDE_IS_EDITOR_VIEW (view))
- view = NULL;
+ /* If there is currently a view attached, and this is
+ * a new view, then we want to unset it so that the
+ * panel can be dismissed.
+ */
+
+ current = gbp_spell_widget_get_editor (self->widget);
+
+ if (current != NULL)
+ {
+ if (view == IDE_LAYOUT_VIEW (current))
+ return;
+ gbp_spell_widget_set_editor (self->widget, NULL);
+ /* TODO: We need transient sidebar API for this to dismiss our display.
+ * Normally it's done automatically, but if the last view is closed
+ * it can get confused.
+ */
+ g_object_set (self->editor, "right-visible", FALSE, NULL);
+ }
}
static void
@@ -101,3 +138,35 @@ static void
gbp_spell_editor_addin_init (GbpSpellEditorAddin *self)
{
}
+
+void
+_gbp_spell_editor_addin_begin (GbpSpellEditorAddin *self,
+ IdeEditorView *view)
+{
+ IdeLayoutTransientSidebar *sidebar;
+
+ g_return_if_fail (GBP_IS_SPELL_EDITOR_ADDIN (self));
+ g_return_if_fail (IDE_IS_EDITOR_VIEW (view));
+
+ gbp_spell_widget_set_editor (self->widget, view);
+
+ sidebar = ide_editor_perspective_get_transient_sidebar (self->editor);
+ ide_layout_transient_sidebar_set_view (sidebar, IDE_LAYOUT_VIEW (view));
+ ide_layout_transient_sidebar_set_panel (sidebar, GTK_WIDGET (self->dock));
+
+ /* TODO: This needs API via transient sidebar panel */
+ g_object_set (self->editor, "right-visible", TRUE, NULL);
+}
+
+void
+_gbp_spell_editor_addin_cancel (GbpSpellEditorAddin *self,
+ IdeEditorView *view)
+{
+ g_return_if_fail (GBP_IS_SPELL_EDITOR_ADDIN (self));
+ g_return_if_fail (IDE_IS_EDITOR_VIEW (view));
+
+ gbp_spell_widget_set_editor (self->widget, NULL);
+
+ /* TODO: This needs API via transient sidebar panel */
+ g_object_set (self->editor, "right-visible", FALSE, NULL);
+}
diff --git a/plugins/spellcheck/gbp-spell-editor-view-addin.c
b/plugins/spellcheck/gbp-spell-editor-view-addin.c
index bcd68a8..221f5f8 100644
--- a/plugins/spellcheck/gbp-spell-editor-view-addin.c
+++ b/plugins/spellcheck/gbp-spell-editor-view-addin.c
@@ -23,7 +23,10 @@
#include <glib/gi18n.h>
#include "gbp-spell-buffer-addin.h"
+#include "gbp-spell-editor-addin.h"
#include "gbp-spell-editor-view-addin.h"
+#include "gbp-spell-navigator.h"
+#include "gbp-spell-private.h"
#include "gbp-spell-utils.h"
#define SPELLCHECKER_SUBREGION_LENGTH 500
@@ -41,42 +44,57 @@ struct _GbpSpellEditorViewAddin
/* Owned references */
DzlBindingGroup *buffer_addin_bindings;
+ GspellNavigator *navigator;
gint checking_count;
};
-enum {
- COMPLETED,
- FAILED,
- WORD_CHANGED,
- N_SIGNALS
-};
+static void
+gbp_spell_editor_view_addin_begin (GSimpleAction *action,
+ GVariant *variant,
+ gpointer user_data)
+{
+ GbpSpellEditorViewAddin *self = user_data;
+ IdeEditorAddin *addin;
+ GtkWidget *editor;
-static guint signals [N_SIGNALS];
+ g_assert (G_IS_SIMPLE_ACTION (action));
+ g_assert (GBP_IS_SPELL_EDITOR_VIEW_ADDIN (self));
-static GtkTextTag *
-get_misspelled_tag (GbpSpellEditorViewAddin *self)
-{
- g_assert (GBP_IS_SPELL_BUFFER_ADDIN (self));
+ editor = gtk_widget_get_ancestor (GTK_WIDGET (self->view), IDE_TYPE_EDITOR_PERSPECTIVE);
+ addin = ide_editor_addin_find_by_module_name (IDE_EDITOR_PERSPECTIVE (editor), "spellcheck-plugin");
+ _gbp_spell_editor_addin_begin (GBP_SPELL_EDITOR_ADDIN (addin), self->view);
+}
- if (self->buffer_addin_bindings != NULL)
- {
- GObject *addin;
+static void
+gbp_spell_editor_view_addin_cancel (GSimpleAction *action,
+ GVariant *variant,
+ gpointer user_data)
+{
+ GbpSpellEditorViewAddin *self = user_data;
+ IdeEditorAddin *addin;
+ GtkWidget *editor;
- addin = dzl_binding_group_get_source (self->buffer_addin_bindings);
- if (addin != NULL)
- return gbp_spell_buffer_addin_get_misspelled_tag (GBP_SPELL_BUFFER_ADDIN (addin));
- }
+ g_assert (G_IS_SIMPLE_ACTION (action));
+ g_assert (GBP_IS_SPELL_EDITOR_VIEW_ADDIN (self));
- return NULL;
+ editor = gtk_widget_get_ancestor (GTK_WIDGET (self->view), IDE_TYPE_EDITOR_PERSPECTIVE);
+ addin = ide_editor_addin_find_by_module_name (IDE_EDITOR_PERSPECTIVE (editor), "spellcheck-plugin");
+ _gbp_spell_editor_addin_cancel (GBP_SPELL_EDITOR_ADDIN (addin), self->view);
}
+static const GActionEntry actions[] = {
+ { "spellcheck", gbp_spell_editor_view_addin_begin },
+ { "cancel-spellcheck", gbp_spell_editor_view_addin_cancel },
+};
+
static void
gbp_spell_editor_view_addin_load (IdeEditorViewAddin *addin,
IdeEditorView *view)
{
GbpSpellEditorViewAddin *self = (GbpSpellEditorViewAddin *)addin;
- g_autoptr(DzlPropertiesGroup) group = NULL;
+ g_autoptr(GSimpleActionGroup) group = NULL;
+ g_autoptr(GPropertyAction) enabled_action = NULL;
IdeBufferAddin *buffer_addin;
GspellTextView *wrapper;
IdeSourceView *source_view;
@@ -112,8 +130,10 @@ gbp_spell_editor_view_addin_load (IdeEditorViewAddin *addin,
G_BINDING_SYNC_CREATE);
dzl_binding_group_set_source (self->buffer_addin_bindings, buffer_addin);
- group = dzl_properties_group_new (G_OBJECT (buffer_addin));
- dzl_properties_group_add_all_properties (group);
+ group = g_simple_action_group_new ();
+ enabled_action = g_property_action_new ("enabled", buffer_addin, "enabled");
+ g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (enabled_action));
+ g_action_map_add_action_entries (G_ACTION_MAP (group), actions, G_N_ELEMENTS (actions), self);
gtk_widget_insert_action_group (GTK_WIDGET (view), "spellcheck", G_ACTION_GROUP (group));
}
@@ -131,6 +151,8 @@ gbp_spell_editor_view_addin_unload (IdeEditorViewAddin *addin,
dzl_binding_group_set_source (self->buffer_addin_bindings, NULL);
g_clear_object (&self->buffer_addin_bindings);
+ g_clear_object (&self->navigator);
+
self->view = NULL;
}
@@ -141,333 +163,12 @@ editor_view_addin_iface_init (IdeEditorViewAddinInterface *iface)
iface->unload = gbp_spell_editor_view_addin_unload;
}
-static void
-gbp_spell_editor_view_addin_select_misspelled_word (GbpSpellEditorViewAddin *self)
-{
- IdeSourceView *view;
- GtkTextBuffer *buffer;
- GtkTextTag *tag;
- GtkTextIter begin;
- GtkTextIter end;
-
- g_assert (GBP_IS_SPELL_EDITOR_VIEW_ADDIN (self));
-
- if (self->view == NULL)
- return;
-
- view = ide_editor_view_get_view (self->view);
- buffer = GTK_TEXT_BUFFER (ide_editor_view_get_buffer (self->view));
- tag = get_misspelled_tag (self);
-
- if (buffer != NULL && tag != NULL)
- {
- gtk_text_buffer_get_iter_at_mark (buffer, &begin, self->start_boundary);
- gtk_text_buffer_get_iter_at_mark (buffer, &end, self->end_boundary);
- gtk_text_buffer_remove_tag (buffer, tag, &begin, &end);
-
- gtk_text_buffer_get_iter_at_mark (buffer, &begin, self->word_begin);
- gtk_text_buffer_get_iter_at_mark (buffer, &end, self->word_end);
- gtk_text_buffer_apply_tag (buffer, tag, &begin, &end);
-
- gtk_widget_queue_draw (GTK_WIDGET (view));
-
- ide_source_view_scroll_to_mark (view, self->word_begin, 0.25, TRUE, 1.0, 0.0, TRUE);
- }
-}
-
-static gboolean
-gbp_spell_editor_view_addin_goto_next (GspellNavigator *navigator,
- gchar **word,
- GspellChecker **checker,
- GError **error)
-{
- GbpSpellEditorViewAddin *self = (GbpSpellEditorViewAddin *)navigator;
- g_autofree gchar *real_word = NULL;
- GspellChecker *spell_checker;
- GtkTextBuffer *buffer;
- GtkTextIter word_begin;
- GtkTextIter word_end;
- GtkTextIter end;
- GtkTextTag *no_spell_check_tag;
- gboolean ret = FALSE;
-
- g_assert (GBP_IS_SPELL_EDITOR_VIEW_ADDIN (self));
-
- if (self->view == NULL)
- {
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVAL,
- "Cannot run spellchecker without view");
- goto complete;
- }
-
- if (self->checking_count < 1)
- {
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVAL,
- "Cannot run spellchecker before gbp_spell_editor_view_addin_begin_checking()");
- goto complete;
- }
-
- g_assert (self->word_begin != NULL);
- g_assert (self->word_end != NULL);
- g_assert (self->start_boundary != NULL);
- g_assert (self->end_boundary != NULL);
-
- buffer = GTK_TEXT_BUFFER (ide_editor_view_get_buffer (self->view));
- spell_checker = gbp_spell_editor_view_addin_get_checker (self);
-
- if (spell_checker == NULL)
- {
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVAL,
- "Cannot run spellchecker without buffer");
- goto complete;
- }
-
- if (gspell_checker_get_language (spell_checker) == NULL)
- {
- g_set_error (error,
- GSPELL_CHECKER_ERROR,
- GSPELL_CHECKER_ERROR_NO_LANGUAGE_SET,
- "%s",
- _("No language set. Check your dictionary installation."));
- goto complete;
- }
-
- gtk_text_buffer_get_iter_at_mark (buffer, &end, self->end_boundary);
- gtk_text_buffer_get_iter_at_mark (buffer, &word_end, self->word_end);
-
- if (gtk_text_iter_compare (&end, &word_end) <= 0)
- goto complete;
-
- word_begin = word_end;
- no_spell_check_tag = gbp_spell_utils_get_no_spell_check_tag (buffer);
-
- while (TRUE)
- {
- g_autofree gchar *local_word = NULL;
- g_autoptr(GError) local_error = NULL;
- gboolean correctly_spelled;
-
- if (!gbp_spell_utils_text_iter_starts_word (&word_begin))
- {
- GtkTextIter iter;
-
- iter = word_begin;
- gbp_spell_utils_text_iter_forward_word_end (&word_begin);
-
- if (gtk_text_iter_equal (&iter, &word_begin))
- goto complete;
-
- gbp_spell_utils_text_iter_backward_word_start (&word_begin);
- }
-
- if (!gbp_spell_utils_skip_no_spell_check (no_spell_check_tag, &word_begin, &end))
- goto complete;
-
- g_return_val_if_fail (gbp_spell_utils_text_iter_starts_word (&word_begin), FALSE);
-
- word_end = word_begin;
- gbp_spell_utils_text_iter_forward_word_end (&word_end);
-
- if (gtk_text_iter_compare (&end, &word_end) < 0)
- goto complete;
-
- local_word = gtk_text_buffer_get_text (buffer, &word_begin, &word_end, FALSE);
- correctly_spelled = gspell_checker_check_word (spell_checker, local_word, -1, &local_error);
-
- if (local_error != NULL)
- {
- g_propagate_error (error, g_steal_pointer (&local_error));
- goto complete;
- }
-
- if (!correctly_spelled)
- {
- /* Found! */
- gtk_text_buffer_move_mark (buffer, self->word_begin, &word_begin);
- gtk_text_buffer_move_mark (buffer, self->word_end, &word_end);
-
- gbp_spell_editor_view_addin_select_misspelled_word (self);
-
- real_word = g_steal_pointer (&local_word);
- ret = TRUE;
- goto complete;
- }
-
- word_begin = word_end;
- }
-
-complete:
-
- if (ret)
- {
- if (word != NULL)
- *word = g_steal_pointer (&real_word);
-
- if (checker != NULL)
- *checker = g_object_ref (spell_checker);
- }
-
- return ret;
-}
-
-static void
-gbp_spell_editor_view_addin_change (GspellNavigator *navigator,
- const gchar *word,
- const gchar *change_to)
-{
- GbpSpellEditorViewAddin *self = (GbpSpellEditorViewAddin *)navigator;
- g_autofree gchar *word_in_buffer = NULL;
- GtkTextBuffer *buffer;
- GtkTextIter word_begin;
- GtkTextIter word_end;
-
- g_assert (GBP_IS_SPELL_EDITOR_VIEW_ADDIN (navigator));
- g_assert (word != NULL);
- g_assert (change_to != NULL);
- g_assert (GTK_IS_TEXT_MARK (self->word_begin));
- g_assert (GTK_IS_TEXT_MARK (self->word_end));
-
- if (self->view == NULL)
- return;
-
- buffer = GTK_TEXT_BUFFER (ide_editor_view_get_buffer (self->view));
-
- gtk_text_buffer_get_iter_at_mark (buffer, &word_begin, self->word_begin);
- gtk_text_buffer_get_iter_at_mark (buffer, &word_end, self->word_end);
-
- word_in_buffer = gtk_text_buffer_get_slice (buffer, &word_begin, &word_end, TRUE);
- g_return_if_fail (word_in_buffer != NULL);
- g_return_if_fail (g_str_equal (word_in_buffer, word));
-
- gtk_text_buffer_begin_user_action (buffer);
-
- gtk_text_buffer_delete (buffer, &word_begin, &word_end);
- gtk_text_buffer_insert (buffer, &word_begin, change_to, -1);
-
- gtk_text_buffer_end_user_action (buffer);
-}
-
-static void
-gbp_spell_editor_view_addin_change_all (GspellNavigator *navigator,
- const gchar *word,
- const gchar *change_to)
-{
- GbpSpellEditorViewAddin *self = (GbpSpellEditorViewAddin *)navigator;
- GtkTextBuffer *buffer;
- GtkTextIter iter;
-
- g_assert (GSPELL_IS_NAVIGATOR (navigator));
- g_assert (GBP_IS_SPELL_EDITOR_VIEW_ADDIN (self));
- g_assert (word != NULL);
- g_assert (change_to != NULL);
- g_assert (GTK_IS_TEXT_MARK (self->start_boundary));
- g_assert (GTK_IS_TEXT_MARK (self->end_boundary));
-
- if (self->view == NULL)
- return;
-
- buffer = GTK_TEXT_BUFFER (ide_editor_view_get_buffer (self->view));
-
- gtk_text_buffer_get_iter_at_mark (buffer, &iter, self->start_boundary);
- gtk_text_buffer_begin_user_action (buffer);
-
- while (TRUE)
- {
- gboolean found;
- GtkTextIter match_begin;
- GtkTextIter match_end;
- GtkTextIter limit;
-
- gtk_text_buffer_get_iter_at_mark (buffer, &limit, self->end_boundary);
- found = gtk_text_iter_forward_search (&iter,
- word,
- (GTK_TEXT_SEARCH_VISIBLE_ONLY |
- GTK_TEXT_SEARCH_TEXT_ONLY),
- &match_begin,
- &match_end,
- &limit);
-
- if (!found)
- break;
-
- if (gbp_spell_utils_text_iter_starts_word (&match_begin) &&
- gbp_spell_utils_text_iter_ends_word (&match_end))
- {
- gtk_text_buffer_delete (buffer, &match_begin, &match_end);
- gtk_text_buffer_insert (buffer, &match_end, change_to, -1);
- }
-
- iter = match_end;
- }
-
- gtk_text_buffer_end_user_action (buffer);
-}
-
-static void
-navigator_iface_init (GspellNavigatorInterface *iface)
-{
- iface->goto_next = gbp_spell_editor_view_addin_goto_next;
- iface->change = gbp_spell_editor_view_addin_change;
- iface->change_all = gbp_spell_editor_view_addin_change_all;
-}
-
G_DEFINE_TYPE_WITH_CODE (GbpSpellEditorViewAddin, gbp_spell_editor_view_addin, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (GSPELL_TYPE_NAVIGATOR, navigator_iface_init)
- G_IMPLEMENT_INTERFACE (IDE_TYPE_EDITOR_VIEW_ADDIN,
- editor_view_addin_iface_init))
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_EDITOR_VIEW_ADDIN, editor_view_addin_iface_init))
static void
gbp_spell_editor_view_addin_class_init (GbpSpellEditorViewAddinClass *klass)
{
- /**
- * GbpSpellEditorViewAddin::completed:
- *
- * The "completed" signal is emitted after moving past the last word.
- */
- signals [COMPLETED] =
- g_signal_new ("completed",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0, NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- /**
- * GbpSpellEditorViewAddin::failed:
- * @self: A #GbpSpellEditorViewAddin
- * @error: (in) (transfer none): A #GError containing the reason
- *
- * The "failed" signal is emitted when a failure to move to the next
- * item has occurred. @error contains the reason.
- */
- signals [FAILED] =
- g_signal_new ("completed",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0, NULL, NULL,
- g_cclosure_marshal_VOID__BOXED,
- G_TYPE_NONE, 1, G_TYPE_ERROR | G_SIGNAL_TYPE_STATIC_SCOPE);
-
- /**
- * GbpSpellEditorViewAddin::word-changed:
- *
- * The "word-changed" signal is emitted when the navigator has advanced
- * to the next word. Connect to this to update your UI in reaction to
- * a change in the underlying navigator.
- */
- signals [WORD_CHANGED] =
- g_signal_new ("word-changed",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0, NULL, NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE, 1, G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
}
static void
@@ -569,22 +270,30 @@ gbp_spell_editor_view_addin_end_checking (GbpSpellEditorViewAddin *self)
if (GBP_IS_SPELL_BUFFER_ADDIN (buffer_addin))
gbp_spell_buffer_addin_end_checking (GBP_SPELL_BUFFER_ADDIN (buffer_addin));
-
if (self->view != NULL)
{
- IdeSourceView *view = ide_editor_view_get_view (self->view);
- GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
-
- gtk_text_buffer_delete_mark (buffer, self->word_begin);
- gtk_text_buffer_delete_mark (buffer, self->word_end);
- gtk_text_buffer_delete_mark (buffer, self->start_boundary);
- gtk_text_buffer_delete_mark (buffer, self->end_boundary);
+ IdeBuffer *buffer = ide_editor_view_get_buffer (self->view);
+
+ /*
+ * We could be in disposal here, so its possible the buffer has
+ * already been cleared and released.
+ */
+
+ if (buffer != NULL)
+ {
+ gtk_text_buffer_delete_mark (GTK_TEXT_BUFFER (buffer), self->word_begin);
+ gtk_text_buffer_delete_mark (GTK_TEXT_BUFFER (buffer), self->word_end);
+ gtk_text_buffer_delete_mark (GTK_TEXT_BUFFER (buffer), self->start_boundary);
+ gtk_text_buffer_delete_mark (GTK_TEXT_BUFFER (buffer), self->end_boundary);
+ }
}
self->word_begin = NULL;
self->word_end = NULL;
self->start_boundary = NULL;
self->end_boundary = NULL;
+
+ g_clear_object (&self->navigator);
}
}
@@ -612,3 +321,34 @@ gbp_spell_editor_view_addin_get_checker (GbpSpellEditorViewAddin *self)
return NULL;
}
+
+/**
+ * gbp_spell_editor_view_addin_get_navigator:
+ * @self: a #GbpSpellEditorViewAddin
+ *
+ * This function may return %NULL before
+ * gbp_spell_editor_view_addin_begin_checking() has been called.
+ *
+ * Returns: (nullable) (transfer none): A #GspellNavigator or %NULL
+ *
+ * Since: 3.26
+ */
+GspellNavigator *
+gbp_spell_editor_view_addin_get_navigator (GbpSpellEditorViewAddin *self)
+{
+ g_return_val_if_fail (GBP_IS_SPELL_EDITOR_VIEW_ADDIN (self), NULL);
+
+ if (self->navigator == NULL)
+ {
+ if (self->view != NULL)
+ {
+ IdeSourceView *view = ide_editor_view_get_view (self->view);
+
+ self->navigator = gbp_spell_navigator_new (GTK_TEXT_VIEW (view));
+ if (self->navigator)
+ g_object_ref_sink (self->navigator);
+ }
+ }
+
+ return self->navigator;
+}
diff --git a/plugins/spellcheck/gbp-spell-editor-view-addin.h
b/plugins/spellcheck/gbp-spell-editor-view-addin.h
index e4c59ec..8f67e15 100644
--- a/plugins/spellcheck/gbp-spell-editor-view-addin.h
+++ b/plugins/spellcheck/gbp-spell-editor-view-addin.h
@@ -27,8 +27,12 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GbpSpellEditorViewAddin, gbp_spell_editor_view_addin, GBP, SPELL_EDITOR_VIEW_ADDIN,
GObject)
-void gbp_spell_editor_view_addin_begin_checking (GbpSpellEditorViewAddin *self);
-void gbp_spell_editor_view_addin_end_checking (GbpSpellEditorViewAddin *self);
-GspellChecker *gbp_spell_editor_view_addin_get_checker (GbpSpellEditorViewAddin *self);
+void gbp_spell_editor_view_addin_begin_checking (GbpSpellEditorViewAddin *self);
+void gbp_spell_editor_view_addin_end_checking (GbpSpellEditorViewAddin *self);
+GspellChecker *gbp_spell_editor_view_addin_get_checker (GbpSpellEditorViewAddin *self);
+GspellNavigator *gbp_spell_editor_view_addin_get_navigator (GbpSpellEditorViewAddin *self);
+guint gbp_spell_editor_view_addin_get_count (GbpSpellEditorViewAddin *self,
+ const gchar *word);
+gboolean gbp_spell_editor_view_addin_move_to_word_start (GbpSpellEditorViewAddin *self);
G_END_DECLS
diff --git a/plugins/spellcheck/gbp-spell-language-popover.c b/plugins/spellcheck/gbp-spell-language-popover.c
index 0138c13..0a18980 100644
--- a/plugins/spellcheck/gbp-spell-language-popover.c
+++ b/plugins/spellcheck/gbp-spell-language-popover.c
@@ -34,7 +34,7 @@ struct _GbpSpellLanguagePopover
GtkPopover *popover;
GtkTreeView *treeview;
GtkTreeSelection *selection;
- GtkTreeStore *store;
+ GtkTreeModel *store;
GtkScrolledWindow *scrolled_window;
const GspellLanguage *language;
@@ -142,7 +142,7 @@ create_popover (GbpSpellLanguagePopover *self)
self->selection = gtk_tree_view_get_selection (self->treeview);
gtk_tree_selection_set_mode (self->selection, GTK_SELECTION_BROWSE);
- self->store = GTK_TREE_STORE (gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, GSPELL_TYPE_LANGUAGE));
+ self->store = GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, GSPELL_TYPE_LANGUAGE));
gtk_tree_view_set_model (self->treeview, GTK_TREE_MODEL (self->store));
gtk_tree_view_insert_column_with_attributes (self->treeview, -1, NULL,
gtk_cell_renderer_text_new (),
diff --git a/plugins/spellcheck/gbp-spell-navigator.c b/plugins/spellcheck/gbp-spell-navigator.c
index 66daaf7..1c7f45b 100644
--- a/plugins/spellcheck/gbp-spell-navigator.c
+++ b/plugins/spellcheck/gbp-spell-navigator.c
@@ -22,6 +22,7 @@
#include <glib/gi18n.h>
#include <ide.h>
+#include "gbp-spell-buffer-addin.h"
#include "gbp-spell-navigator.h"
#include "gbp-spell-utils.h"
@@ -74,6 +75,51 @@ words_count_state_free (gpointer user_data)
g_slice_free (WordsCountState, state);
}
+static GtkTextTag *
+get_misspelled_tag (GbpSpellNavigator *self)
+{
+ IdeBufferAddin *buffer_addin;
+
+ g_assert (GBP_IS_SPELL_NAVIGATOR (self));
+ g_assert (self->buffer != NULL);
+ g_assert (IDE_IS_BUFFER (self->buffer));
+
+ buffer_addin = ide_buffer_addin_find_by_module_name (IDE_BUFFER (self->buffer), "spellcheck-plugin");
+ if (buffer_addin != NULL)
+ return gbp_spell_buffer_addin_get_misspelled_tag (GBP_SPELL_BUFFER_ADDIN (buffer_addin));
+
+ return NULL;
+}
+
+static void
+gbp_spell_navigator_select_misspelled_word (GbpSpellNavigator *self)
+{
+ GtkTextTag *tag;
+ GtkTextIter begin;
+ GtkTextIter end;
+
+ g_assert (GBP_IS_SPELL_NAVIGATOR (self));
+
+ if (self->view == NULL)
+ return;
+
+ if (self->buffer != NULL && NULL != (tag = get_misspelled_tag (self)))
+ {
+ gtk_text_buffer_get_iter_at_mark (self->buffer, &begin, self->start_boundary);
+ gtk_text_buffer_get_iter_at_mark (self->buffer, &end, self->end_boundary);
+ gtk_text_buffer_remove_tag (self->buffer, tag, &begin, &end);
+
+ gtk_text_buffer_get_iter_at_mark (self->buffer, &begin, self->word_start);
+ gtk_text_buffer_get_iter_at_mark (self->buffer, &end, self->word_end);
+ gtk_text_buffer_apply_tag (self->buffer, tag, &begin, &end);
+
+ gtk_widget_queue_draw (GTK_WIDGET (self->view));
+
+ ide_source_view_scroll_to_mark (IDE_SOURCE_VIEW (self->view), self->word_start,
+ 0.25, TRUE, 1.0, 0.0, TRUE);
+ }
+}
+
static gboolean
gbp_spell_navigator_words_count_cb (WordsCountState *state)
{
@@ -238,9 +284,6 @@ gbp_spell_navigator_dispose (GObject *object)
{
GbpSpellNavigator *self = (GbpSpellNavigator *)object;
- ide_source_view_set_misspelled_word (IDE_SOURCE_VIEW (self->view), NULL, NULL);
- gtk_widget_queue_resize (GTK_WIDGET (self->view));
-
g_clear_object (&self->view);
g_clear_pointer (&self->words_count, g_hash_table_unref);
@@ -302,7 +345,7 @@ set_view (GbpSpellNavigator *self,
gtk_text_buffer_get_iter_at_mark (self->buffer, &end, self->end_boundary);
self->words_count = gbp_spell_navigator_count_words (self, &start, &end);
- g_object_notify (G_OBJECT (self), "view");
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_VIEW]);
}
}
@@ -359,12 +402,12 @@ gbp_spell_navigator_class_init (GbpSpellNavigatorClass *klass)
properties [PROP_VIEW] =
g_param_spec_object ("view",
- "View",
- "the view",
- GTK_TYPE_TEXT_VIEW,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
+ "View",
+ "the view",
+ GTK_TYPE_TEXT_VIEW,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
properties [PROP_WORDS_COUNTED] =
g_param_spec_boolean ("words-counted",
@@ -381,30 +424,6 @@ gbp_spell_navigator_init (GbpSpellNavigator *self)
{
}
-static void
-select_misspelled_word (GbpSpellNavigator *self)
-{
- GtkTextIter word_start;
- GtkTextIter word_end;
-
- g_assert (GBP_IS_SPELL_NAVIGATOR (self));
-
- gtk_text_buffer_get_iter_at_mark (self->buffer, &word_start, self->word_start);
- gtk_text_buffer_get_iter_at_mark (self->buffer, &word_end, self->word_end);
-
- ide_source_view_set_misspelled_word (IDE_SOURCE_VIEW (self->view), &word_start, &word_end);
- gtk_widget_queue_draw (GTK_WIDGET (self->view));
-
- g_return_if_fail (gtk_text_view_get_buffer (self->view) == self->buffer);
-
- gtk_text_view_scroll_to_mark (self->view,
- self->word_start,
- 0.25,
- FALSE,
- 0.0,
- 0.0);
-}
-
/* Go to the start of the current checked word so that
* we can re-check it again, change of language for example
*/
@@ -535,7 +554,7 @@ gbp_spell_navigator_goto_next (GspellNavigator *navigator,
/* Found! */
gtk_text_buffer_move_mark (self->buffer, self->word_start, &word_start);
gtk_text_buffer_move_mark (self->buffer, self->word_end, &word_end);
- select_misspelled_word (self);
+ gbp_spell_navigator_select_misspelled_word (self);
if (spell_checker_p != NULL)
*spell_checker_p = g_object_ref (spell_checker);
diff --git a/plugins/spellcheck/gbp-spell-private.h b/plugins/spellcheck/gbp-spell-private.h
new file mode 100644
index 0000000..595ba96
--- /dev/null
+++ b/plugins/spellcheck/gbp-spell-private.h
@@ -0,0 +1,97 @@
+/* gbp-spell-widget-private.h
+ *
+ * Copyright (C) 2016 Sebastien Lafargue <slafargue gnome org>
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <gspell/gspell.h>
+#include <ide.h>
+
+#include "gbp-spell-dict.h"
+#include "gbp-spell-widget.h"
+#include "gbp-spell-editor-addin.h"
+#include "gbp-spell-editor-view-addin.h"
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ CHECK_WORD_NONE,
+ CHECK_WORD_CHECKING,
+ CHECK_WORD_IDLE
+} CheckWordState;
+
+struct _GbpSpellWidget
+{
+ GtkBin parent_instance;
+
+ /* Owned references */
+ IdeEditorView *editor;
+ GbpSpellEditorViewAddin *editor_view_addin;
+ DzlSignalGroup *editor_view_addin_signals;
+ GPtrArray *words_array;
+ GbpSpellDict *dict;
+
+ /* Borrowed references */
+ const GspellLanguage *language;
+
+ /* Template references */
+ GtkLabel *word_label;
+ GtkLabel *count_label;
+ GtkEntry *word_entry;
+ GtkListBox *suggestions_box;
+ GtkBox *count_box;
+ GtkWidget *dict_word_entry;
+ GtkWidget *dict_add_button;
+ GtkWidget *dict_words_list;
+ GtkButton *language_chooser_button;
+ GtkWidget *placeholder;
+
+ /* GSource identifiers */
+ guint check_word_timeout_id;
+ guint dict_check_word_timeout_id;
+
+ guint current_word_count;
+ CheckWordState check_word_state;
+ CheckWordState dict_check_word_state;
+
+ guint is_checking_word : 1;
+ guint is_check_word_invalid : 1;
+ guint is_check_word_idle : 1;
+ guint is_word_entry_valid : 1;
+
+ guint is_dict_checking_word : 1;
+ guint is_dict_check_word_invalid : 1;
+ guint is_dict_check_word_idle : 1;
+
+ guint spellchecking_status : 1;
+};
+
+void _gbp_spell_widget_init_actions (GbpSpellWidget *self);
+void _gbp_spell_widget_update_actions (GbpSpellWidget *self);
+gboolean _gbp_spell_widget_move_next_word (GbpSpellWidget *self);
+GtkWidget *_gbp_spell_widget_get_entry (GbpSpellWidget *self);
+void _gbp_spell_widget_change (GbpSpellWidget *self,
+ gboolean change_all);
+
+void _gbp_spell_editor_addin_begin (GbpSpellEditorAddin *self,
+ IdeEditorView *view);
+void _gbp_spell_editor_addin_cancel (GbpSpellEditorAddin *self,
+ IdeEditorView *view);
+
+G_END_DECLS
diff --git a/plugins/spellcheck/gbp-spell-widget-actions.c b/plugins/spellcheck/gbp-spell-widget-actions.c
new file mode 100644
index 0000000..b51cb15
--- /dev/null
+++ b/plugins/spellcheck/gbp-spell-widget-actions.c
@@ -0,0 +1,163 @@
+/* gbp-spell-widget-actions.c
+ *
+ * Copyright (C) 2016 Sebastien Lafargue <slafargue gnome org>
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gbp-spell-widget-actions"
+
+#include "gbp-spell-dict.h"
+#include "gbp-spell-private.h"
+
+static void
+gbp_spell_widget_actions_change (GSimpleAction *action,
+ GVariant *param,
+ gpointer user_data)
+{
+ GbpSpellWidget *self = user_data;
+
+ g_assert (G_IS_SIMPLE_ACTION (action));
+ g_assert (GBP_IS_SPELL_WIDGET (self));
+
+ _gbp_spell_widget_change (self, FALSE);
+}
+
+static void
+gbp_spell_widget_actions_change_all (GSimpleAction *action,
+ GVariant *param,
+ gpointer user_data)
+{
+ GbpSpellWidget *self = user_data;
+
+ g_assert (G_IS_SIMPLE_ACTION (action));
+ g_assert (GBP_IS_SPELL_WIDGET (self));
+
+ _gbp_spell_widget_change (self, TRUE);
+}
+
+static void
+gbp_spell_widget_actions_ignore (GSimpleAction *action,
+ GVariant *param,
+ gpointer user_data)
+{
+ GbpSpellWidget *self = user_data;
+
+ g_assert (G_IS_SIMPLE_ACTION (action));
+ g_assert (GBP_IS_SPELL_WIDGET (self));
+
+ _gbp_spell_widget_move_next_word (self);
+}
+
+static void
+gbp_spell_widget_actions_ignore_all (GSimpleAction *action,
+ GVariant *param,
+ gpointer user_data)
+{
+ GbpSpellWidget *self = user_data;
+
+ g_assert (G_IS_SIMPLE_ACTION (action));
+ g_assert (GBP_IS_SPELL_WIDGET (self));
+
+ if (self->editor_view_addin != NULL)
+ {
+ GspellChecker *checker;
+ const gchar *word;
+
+ checker = gbp_spell_editor_view_addin_get_checker (self->editor_view_addin);
+ word = gtk_label_get_text (self->word_label);
+
+ if (!ide_str_empty0 (word))
+ {
+ gspell_checker_add_word_to_session (checker, word, -1);
+ _gbp_spell_widget_move_next_word (self);
+ }
+ }
+}
+
+static void
+gbp_spell_widget_actions_move_next_word (GSimpleAction *action,
+ GVariant *param,
+ gpointer user_data)
+{
+ GbpSpellWidget *self = user_data;
+
+ g_assert (G_IS_SIMPLE_ACTION (action));
+ g_assert (GBP_IS_SPELL_WIDGET (self));
+
+ _gbp_spell_widget_move_next_word (self);
+}
+
+static const GActionEntry actions[] = {
+ { "change", gbp_spell_widget_actions_change },
+ { "change-all", gbp_spell_widget_actions_change_all },
+ { "ignore", gbp_spell_widget_actions_ignore },
+ { "ignore-all", gbp_spell_widget_actions_ignore_all },
+ { "move-next-word", gbp_spell_widget_actions_move_next_word },
+};
+
+void
+_gbp_spell_widget_init_actions (GbpSpellWidget *self)
+{
+ g_autoptr(GSimpleActionGroup) group = NULL;
+
+ g_return_if_fail (GBP_IS_SPELL_WIDGET (self));
+
+ group = g_simple_action_group_new ();
+ g_action_map_add_action_entries (G_ACTION_MAP (group), actions, G_N_ELEMENTS (actions), self);
+ gtk_widget_insert_action_group (GTK_WIDGET (self), "spell-widget", G_ACTION_GROUP (group));
+}
+
+void
+_gbp_spell_widget_update_actions (GbpSpellWidget *self)
+{
+ gboolean can_change = FALSE;
+ gboolean can_change_all = FALSE;
+ gboolean can_ignore = FALSE;
+ gboolean can_ignore_all = FALSE;
+ gboolean can_move_next_word = FALSE;
+
+ g_return_if_fail (GBP_IS_SPELL_WIDGET (self));
+
+ if (IDE_IS_EDITOR_VIEW (self->editor) &&
+ GBP_IS_SPELL_EDITOR_VIEW_ADDIN (self->editor_view_addin) &&
+ self->spellchecking_status == TRUE)
+ {
+ g_assert (IDE_IS_EDITOR_VIEW_ADDIN (self->editor_view_addin));
+
+ can_change = TRUE;
+ can_change_all = TRUE;
+ can_move_next_word = TRUE;
+
+ can_ignore = self->current_word_count > 0;
+ can_ignore_all = self->current_word_count > 1;
+ }
+
+ dzl_gtk_widget_action_set (GTK_WIDGET (self), "spell-widget", "change",
+ "enabled", can_change,
+ NULL);
+ dzl_gtk_widget_action_set (GTK_WIDGET (self), "spell-widget", "change-all",
+ "enabled", can_change_all,
+ NULL);
+ dzl_gtk_widget_action_set (GTK_WIDGET (self), "spell-widget", "ignore",
+ "enabled", can_ignore,
+ NULL);
+ dzl_gtk_widget_action_set (GTK_WIDGET (self), "spell-widget", "ignore-all",
+ "enabled", can_ignore_all,
+ NULL);
+ dzl_gtk_widget_action_set (GTK_WIDGET (self), "spell-widget", "move-next-word",
+ "enabled", can_move_next_word,
+ NULL);
+}
diff --git a/plugins/spellcheck/gbp-spell-widget.c b/plugins/spellcheck/gbp-spell-widget.c
index b33688b..6a1d3b8 100644
--- a/plugins/spellcheck/gbp-spell-widget.c
+++ b/plugins/spellcheck/gbp-spell-widget.c
@@ -26,67 +26,9 @@
#include "gbp-spell-dict.h"
#include "gbp-spell-language-popover.h"
#include "gbp-spell-navigator.h"
+#include "gbp-spell-private.h"
#include "gbp-spell-widget.h"
-typedef enum
-{
- CHECK_WORD_NONE,
- CHECK_WORD_CHECKING,
- CHECK_WORD_IDLE
-} CheckWordState;
-
-struct _GbpSpellWidget
-{
- GtkBin parent_instance;
-
- GspellNavigator *navigator;
- IdeSourceView *view;
- IdeBuffer *buffer;
- GspellChecker *checker;
- GbpSpellDict *dict;
- GPtrArray *words_array;
- const GspellLanguage *spellchecker_language;
-
- GtkLabel *word_label;
- GtkLabel *count_label;
- GtkEntry *word_entry;
- GtkButton *ignore_button;
- GtkButton *ignore_all_button;
- GtkButton *change_button;
- GtkButton *change_all_button;
- GtkListBox *suggestions_box;
- GtkBox *count_box;
-
- GtkWidget *dict_word_entry;
- GtkWidget *dict_add_button;
- GtkWidget *dict_words_list;
-
- GtkButton *highlight_switch;
- GtkButton *language_chooser_button;
-
- GtkWidget *placeholder;
- GAction *view_spellchecking_action;
-
- guint current_word_count;
- guint check_word_timeout_id;
- guint dict_check_word_timeout_id;
- CheckWordState check_word_state;
- CheckWordState dict_check_word_state;
-
- guint view_spellchecker_set : 1;
-
- guint is_checking_word : 1;
- guint is_check_word_invalid : 1;
- guint is_check_word_idle : 1;
- guint is_word_entry_valid : 1;
-
- guint is_dict_checking_word : 1;
- guint is_dict_check_word_invalid : 1;
- guint is_dict_check_word_idle : 1;
-
- guint spellchecking_status : 1;
-};
-
G_DEFINE_TYPE (GbpSpellWidget, gbp_spell_widget, GTK_TYPE_BIN)
#define CHECK_WORD_INTERVAL_MIN 100
@@ -95,7 +37,7 @@ G_DEFINE_TYPE (GbpSpellWidget, gbp_spell_widget, GTK_TYPE_BIN)
enum {
PROP_0,
- PROP_VIEW,
+ PROP_EDITOR,
N_PROPS
};
@@ -104,14 +46,11 @@ static GParamSpec *properties [N_PROPS];
static void
clear_suggestions_box (GbpSpellWidget *self)
{
- GList *children;
-
g_assert (GBP_IS_SPELL_WIDGET (self));
- children = gtk_container_get_children (GTK_CONTAINER (self->suggestions_box));
-
- for (GList *l = children; l != NULL; l = g_list_next (l))
- gtk_widget_destroy (GTK_WIDGET (l->data));
+ gtk_container_foreach (GTK_CONTAINER (self->suggestions_box),
+ (GtkCallback)gtk_widget_destroy,
+ NULL);
}
static void
@@ -122,35 +61,11 @@ update_global_sensiblility (GbpSpellWidget *self,
gtk_entry_set_text (self->word_entry, "");
clear_suggestions_box (self);
-
- gtk_widget_set_sensitive (GTK_WIDGET (self->word_entry), sensibility);
- gtk_widget_set_sensitive (GTK_WIDGET (self->ignore_button), sensibility);
- gtk_widget_set_sensitive (GTK_WIDGET (self->ignore_all_button), sensibility);
- gtk_widget_set_sensitive (GTK_WIDGET (self->change_button), sensibility);
- gtk_widget_set_sensitive (GTK_WIDGET (self->change_all_button), sensibility);
- gtk_widget_set_sensitive (GTK_WIDGET (self->suggestions_box), sensibility);
-}
-
-static void
-update_change_ignore_sensibility (GbpSpellWidget *self)
-{
- gboolean entry_sensitivity;
-
- g_assert (GBP_IS_SPELL_WIDGET (self));
-
- entry_sensitivity = (gtk_entry_get_text_length (self->word_entry) > 0);
-
- gtk_widget_set_sensitive (GTK_WIDGET (self->change_button),
- entry_sensitivity);
- gtk_widget_set_sensitive (GTK_WIDGET (self->change_all_button),
- entry_sensitivity && (self->current_word_count > 1));
-
- gtk_widget_set_sensitive (GTK_WIDGET (self->ignore_all_button),
- self->current_word_count > 1);
+ _gbp_spell_widget_update_actions (self);
}
GtkWidget *
-gbp_spell_widget_get_entry (GbpSpellWidget *self)
+_gbp_spell_widget_get_entry (GbpSpellWidget *self)
{
g_return_val_if_fail (GBP_IS_SPELL_WIDGET (self), NULL);
@@ -161,18 +76,14 @@ static GtkWidget *
create_suggestion_row (GbpSpellWidget *self,
const gchar *word)
{
- GtkWidget *row;
-
g_assert (GBP_IS_SPELL_WIDGET (self));
g_assert (!ide_str_empty0 (word));
- row = g_object_new (GTK_TYPE_LABEL,
- "label", word,
- "visible", TRUE,
- "halign", GTK_ALIGN_START,
- NULL);
-
- return row;
+ return g_object_new (GTK_TYPE_LABEL,
+ "label", word,
+ "visible", TRUE,
+ "xalign", 0.0f,
+ NULL);
}
static void
@@ -180,6 +91,7 @@ fill_suggestions_box (GbpSpellWidget *self,
const gchar *word,
gchar **first_result)
{
+ GspellChecker *checker;
GSList *suggestions = NULL;
GtkWidget *item;
@@ -189,13 +101,20 @@ fill_suggestions_box (GbpSpellWidget *self,
*first_result = NULL;
clear_suggestions_box (self);
+
if (ide_str_empty0 (word))
{
gtk_widget_set_sensitive (GTK_WIDGET (self->suggestions_box), FALSE);
return;
}
- if (NULL == (suggestions = gspell_checker_get_suggestions (self->checker, word, -1)))
+ if (self->editor_view_addin != NULL)
+ {
+ checker = gbp_spell_editor_view_addin_get_checker (self->editor_view_addin);
+ suggestions = gspell_checker_get_suggestions (checker, word, -1);
+ }
+
+ if (suggestions == NULL)
{
gtk_label_set_text (GTK_LABEL (self->placeholder), _("No suggestions"));
gtk_widget_set_sensitive (GTK_WIDGET (self->suggestions_box), FALSE);
@@ -203,10 +122,13 @@ fill_suggestions_box (GbpSpellWidget *self,
else
{
*first_result = g_strdup (suggestions->data);
+
gtk_widget_set_sensitive (GTK_WIDGET (self->suggestions_box), TRUE);
- for (GSList *l = (GSList *)suggestions; l != NULL; l = l->next)
+
+ for (const GSList *iter = suggestions; iter; iter = iter->next)
{
- item = create_suggestion_row (self, l->data);
+ const gchar *iter_word = iter->data;
+ item = create_suggestion_row (self, iter_word);
gtk_list_box_insert (self->suggestions_box, item, -1);
}
@@ -217,13 +139,20 @@ fill_suggestions_box (GbpSpellWidget *self,
static void
update_count_label (GbpSpellWidget *self)
{
+ GspellNavigator *navigator;
const gchar *word;
guint count;
g_assert (GBP_IS_SPELL_WIDGET (self));
+ if (self->editor_view_addin == NULL)
+ return;
+
+ navigator = gbp_spell_editor_view_addin_get_navigator (self->editor_view_addin);
word = gtk_label_get_text (self->word_label);
- if (0 != (count = gbp_spell_navigator_get_count (GBP_SPELL_NAVIGATOR (self->navigator), word)))
+ count = gbp_spell_navigator_get_count (GBP_SPELL_NAVIGATOR (navigator), word);
+
+ if (count > 0)
{
g_autofree gchar *count_text = NULL;
@@ -239,28 +168,34 @@ update_count_label (GbpSpellWidget *self)
gtk_widget_set_visible (GTK_WIDGET (self->count_box), TRUE);
self->current_word_count = count;
- update_change_ignore_sensibility (self);
+
+ _gbp_spell_widget_update_actions (self);
}
-static gboolean
-jump_to_next_misspelled_word (GbpSpellWidget *self)
+gboolean
+_gbp_spell_widget_move_next_word (GbpSpellWidget *self)
{
- GspellChecker *checker = NULL;
g_autofree gchar *word = NULL;
g_autofree gchar *first_result = NULL;
- GtkListBoxRow *row;
g_autoptr(GError) error = NULL;
+ GspellNavigator *navigator;
+ GtkListBoxRow *row;
gboolean ret = FALSE;
g_assert (GBP_IS_SPELL_WIDGET (self));
- gtk_widget_grab_focus (GTK_WIDGET (self->word_entry));
- if ((ret = gspell_navigator_goto_next (self->navigator, &word, &checker, &error)))
+ if (self->editor_view_addin == NULL)
+ return FALSE;
+
+ navigator = gbp_spell_editor_view_addin_get_navigator (self->editor_view_addin);
+
+ if ((ret = gspell_navigator_goto_next (navigator, &word, NULL, &error)))
{
gtk_label_set_text (self->word_label, word);
update_count_label (self);
fill_suggestions_box (self, word, &first_result);
+
if (!ide_str_empty0 (first_result))
{
row = gtk_list_box_get_row_at_index (self->suggestions_box, 0);
@@ -275,71 +210,46 @@ jump_to_next_misspelled_word (GbpSpellWidget *self)
self->spellchecking_status = FALSE;
gtk_label_set_text (GTK_LABEL (self->placeholder), _("Completed spell checking"));
- gtk_widget_grab_focus (self->dict_word_entry);
update_global_sensiblility (self, FALSE);
}
- return ret;
-}
+ _gbp_spell_widget_update_actions (self);
-GtkWidget *
-gbp_spell_widget_new (IdeSourceView *source_view)
-{
- return g_object_new (GBP_TYPE_SPELL_WIDGET,
- "view", source_view,
- NULL);
-}
-
-static IdeSourceView *
-gbp_spell_widget_get_view (GbpSpellWidget *self)
-{
- g_return_val_if_fail (GBP_IS_SPELL_WIDGET (self), NULL);
-
- return self->view;
-}
-
-static void
-gbp_spell_widget_set_view (GbpSpellWidget *self,
- IdeSourceView *view)
-{
- g_return_if_fail (GBP_IS_SPELL_WIDGET (self));
- g_return_if_fail (IDE_IS_SOURCE_VIEW (view));
-
- ide_set_weak_pointer (&self->view, view);
- if (GSPELL_IS_NAVIGATOR (self->navigator))
- g_clear_object (&self->navigator);
-
- self->navigator = gbp_spell_navigator_new (GTK_TEXT_VIEW (view));
+ return ret;
}
static gboolean
check_word_timeout_cb (GbpSpellWidget *self)
{
- const gchar *word;
g_autoptr(GError) error = NULL;
- gchar *icon_name;
+ GspellChecker *checker;
+ const gchar *icon_name = "";
+ const gchar *word;
gboolean ret = TRUE;
g_assert (GBP_IS_SPELL_WIDGET (self));
+ g_assert (self->editor_view_addin != NULL);
+
+ checker = gbp_spell_editor_view_addin_get_checker (self->editor_view_addin);
self->check_word_state = CHECK_WORD_CHECKING;
word = gtk_entry_get_text (self->word_entry);
+
if (!ide_str_empty0 (word))
{
/* FIXME: suggestions can give a multiple-words suggestion
* that failed to the checkword test, ex: auto tools
*/
- ret = gspell_checker_check_word (self->checker, word, -1, &error);
+ ret = gspell_checker_check_word (checker, word, -1, &error);
if (error != NULL)
{
g_message ("check error:%s\n", error->message);
}
- icon_name = ret ? "" : "dialog-warning-symbolic";
+ if (!ret)
+ icon_name = "dialog-warning-symbolic";
}
- else
- icon_name = "";
gtk_entry_set_icon_from_icon_name (self->word_entry,
GTK_ENTRY_ICON_SECONDARY,
@@ -349,13 +259,14 @@ check_word_timeout_cb (GbpSpellWidget *self)
self->is_word_entry_valid = ret;
self->check_word_timeout_id = 0;
+
if (self->is_check_word_invalid == TRUE)
{
- self->check_word_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
+ self->check_word_timeout_id = g_timeout_add_full (G_PRIORITY_LOW,
CHECK_WORD_INTERVAL_MIN,
(GSourceFunc)check_word_timeout_cb,
- self,
- NULL);
+ g_object_ref (self),
+ g_object_unref);
self->check_word_state = CHECK_WORD_IDLE;
self->is_check_word_invalid = FALSE;
}
@@ -372,7 +283,7 @@ gbp_spell_widget__word_entry_changed_cb (GbpSpellWidget *self,
g_assert (GBP_IS_SPELL_WIDGET (self));
g_assert (GTK_IS_ENTRY (entry));
- update_change_ignore_sensibility (self);
+ _gbp_spell_widget_update_actions (self);
word = gtk_entry_get_text (self->word_entry);
if (ide_str_empty0 (word) && self->spellchecking_status == TRUE)
@@ -389,89 +300,17 @@ gbp_spell_widget__word_entry_changed_cb (GbpSpellWidget *self,
return;
}
- if (self->check_word_state == CHECK_WORD_IDLE)
+ ide_clear_source (&self->check_word_timeout_id);
+
+ if (self->editor_view_addin != NULL)
{
- g_source_remove (self->check_word_timeout_id);
- self->check_word_timeout_id = 0;
+ self->check_word_timeout_id = g_timeout_add_full (G_PRIORITY_LOW,
+ CHECK_WORD_INTERVAL_MIN,
+ (GSourceFunc)check_word_timeout_cb,
+ g_object_ref (self),
+ g_object_unref);
+ self->check_word_state = CHECK_WORD_IDLE;
}
-
- self->check_word_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
- CHECK_WORD_INTERVAL_MIN,
- (GSourceFunc)check_word_timeout_cb,
- self,
- NULL);
- self->check_word_state = CHECK_WORD_IDLE;
-}
-
-static void
-gbp_spell_widget__ignore_button_clicked_cb (GbpSpellWidget *self,
- GtkButton *button)
-{
- g_assert (GBP_IS_SPELL_WIDGET (self));
- g_assert (GTK_IS_BUTTON (button));
-
- jump_to_next_misspelled_word (self);
-}
-
-static void
-gbp_spell_widget__ignore_all_button_clicked_cb (GbpSpellWidget *self,
- GtkButton *button)
-{
- const gchar *word;
-
- g_assert (GBP_IS_SPELL_WIDGET (self));
- g_assert (GTK_IS_BUTTON (button));
-
- word = gtk_label_get_text (self->word_label);
- g_assert (!ide_str_empty0 (word));
-
- gspell_checker_add_word_to_session (self->checker, word, -1);
- jump_to_next_misspelled_word (self);
-}
-
-static void
-change_misspelled_word (GbpSpellWidget *self,
- gboolean change_all)
-{
- const gchar *word;
- g_autofree gchar *change_to = NULL;
-
- g_assert (GBP_IS_SPELL_WIDGET (self));
-
- word = gtk_label_get_text (self->word_label);
- g_assert (!ide_str_empty0 (word));
-
- change_to = g_strdup (gtk_entry_get_text (self->word_entry));
- g_assert (!ide_str_empty0 (change_to));
-
- gspell_checker_set_correction (self->checker, word, -1, change_to, -1);
-
- if (change_all)
- gspell_navigator_change_all (self->navigator, word, change_to);
- else
- gspell_navigator_change (self->navigator, word, change_to);
-
- jump_to_next_misspelled_word (self);
-}
-
-static void
-gbp_spell_widget__change_button_clicked_cb (GbpSpellWidget *self,
- GtkButton *button)
-{
- g_assert (GBP_IS_SPELL_WIDGET (self));
- g_assert (GTK_IS_BUTTON (button));
-
- change_misspelled_word (self, FALSE);
-}
-
-static void
-gbp_spell_widget__change_all_button_clicked_cb (GbpSpellWidget *self,
- GtkButton *button)
-{
- g_assert (GBP_IS_SPELL_WIDGET (self));
- g_assert (GTK_IS_BUTTON (button));
-
- change_misspelled_word (self, TRUE);
}
static void
@@ -495,7 +334,7 @@ gbp_spell_widget__row_selected_cb (GbpSpellWidget *self,
gtk_entry_set_text (self->word_entry, word);
gtk_editable_set_position (GTK_EDITABLE (self->word_entry), -1);
- update_change_ignore_sensibility (self);
+ _gbp_spell_widget_update_actions (self);
g_signal_handlers_unblock_by_func (self->word_entry, gbp_spell_widget__word_entry_changed_cb, self);
}
@@ -511,71 +350,7 @@ gbp_spell_widget__row_activated_cb (GbpSpellWidget *self,
g_assert (GTK_IS_LIST_BOX (listbox));
if (row != NULL)
- change_misspelled_word (self, FALSE);
-}
-
-static gboolean
-gbp_spell_widget__key_press_event_cb (GbpSpellWidget *self,
- GdkEventKey *event)
-{
- g_assert (IDE_IS_SOURCE_VIEW (self->view));
- g_assert (event != NULL);
-
- switch (event->keyval)
- {
- case GDK_KEY_Escape:
- dzl_gtk_widget_action (GTK_WIDGET (self->view),
- "frame", "show-spellcheck",
- g_variant_new_int32 (0));
- return GDK_EVENT_STOP;
-
- default:
- break;
- }
-
- return GDK_EVENT_PROPAGATE;
-}
-
-static void
-gbp_spell__widget_mapped_cb (GbpSpellWidget *self)
-{
- GActionGroup *group = NULL;
- GtkWidget *widget = GTK_WIDGET (self->view);
- g_autoptr (GVariant) value = NULL;
-
- g_assert (GBP_IS_SPELL_WIDGET (self));
-
- while ((group == NULL) && (widget != NULL))
- {
- group = gtk_widget_get_action_group (widget, "view");
- widget = gtk_widget_get_parent (widget);
- }
-
- if (group != NULL &&
- NULL != (self->view_spellchecking_action = g_action_map_lookup_action (G_ACTION_MAP (group),
- "spellchecking")))
- {
- value = g_action_get_state (self->view_spellchecking_action);
- self->view_spellchecker_set = g_variant_get_boolean (value);
- gtk_switch_set_active (GTK_SWITCH (self->highlight_switch), self->view_spellchecker_set);
- }
-
- jump_to_next_misspelled_word (self);
-}
-
-static void
-gbp_spell_widget__highlight_switch_toggled_cb (GbpSpellWidget *self,
- gboolean state,
- GtkSwitch *switch_button)
-{
- GspellTextView *spell_text_view;
-
- g_assert (GBP_IS_SPELL_WIDGET (self));
- g_assert (GTK_IS_SWITCH (switch_button));
-
- gtk_switch_set_state (switch_button, state);
- spell_text_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (self->view));
- gspell_text_view_set_inline_spell_checking (spell_text_view, state);
+ _gbp_spell_widget_change (self, FALSE);
}
static void
@@ -619,13 +394,23 @@ get_next_row_to_focus (GtkListBox *listbox,
static gboolean
dict_check_word_timeout_cb (GbpSpellWidget *self)
{
- const gchar *word;
g_autofree gchar *tooltip = NULL;
- gchar *icon_name;
+ GspellChecker *checker;
+ const gchar *icon_name = "";
+ const gchar *word;
gboolean valid = FALSE;
g_assert (GBP_IS_SPELL_WIDGET (self));
+ if (self->editor_view_addin == NULL)
+ {
+ /* lost our chance */
+ self->dict_check_word_timeout_id = 0;
+ return G_SOURCE_REMOVE;
+ }
+
+ checker = gbp_spell_editor_view_addin_get_checker (self->editor_view_addin);
+
self->dict_check_word_state = CHECK_WORD_CHECKING;
word = gtk_entry_get_text (GTK_ENTRY (self->dict_word_entry));
@@ -633,9 +418,9 @@ dict_check_word_timeout_cb (GbpSpellWidget *self)
{
if (gbp_spell_dict_personal_contains (self->dict, word))
gtk_widget_set_tooltip_text (self->dict_word_entry, _("This word is already in the personal
dictionary"));
- else if (gspell_checker_check_word (self->checker, word, -1, NULL))
+ else if (gspell_checker_check_word (checker, word, -1, NULL))
{
- tooltip = g_strdup_printf (_("This word is already in the %s dictionary"),
gspell_language_get_name (self->spellchecker_language));
+ tooltip = g_strdup_printf (_("This word is already in the %s dictionary"),
gspell_language_get_name (self->language));
gtk_widget_set_tooltip_text (self->dict_word_entry, tooltip);
}
else
@@ -644,10 +429,9 @@ dict_check_word_timeout_cb (GbpSpellWidget *self)
gtk_widget_set_tooltip_text (self->dict_word_entry, NULL);
}
- icon_name = valid ? "" : "dialog-warning-symbolic";
+ if (!valid)
+ icon_name = "dialog-warning-symbolic";
}
- else
- icon_name = "";
gtk_widget_set_sensitive (GTK_WIDGET (self->dict_add_button), valid);
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (self->dict_word_entry),
@@ -755,8 +539,8 @@ dict_row_key_pressed_event_cb (GbpSpellWidget *self,
g_assert (event != NULL);
g_assert (GTK_IS_LIST_BOX (listbox));
- if (NULL != (row = gtk_list_box_get_selected_row (listbox)) &&
- event->keyval == GDK_KEY_Delete)
+ if (event->keyval == GDK_KEY_Delete &&
+ NULL != (row = gtk_list_box_get_selected_row (listbox)))
{
remove_dict_row (self, GTK_LIST_BOX (self->dict_words_list), GTK_LIST_BOX_ROW (row));
return GDK_EVENT_STOP;
@@ -810,7 +594,7 @@ check_dict_available (GbpSpellWidget *self)
{
g_assert (GBP_IS_SPELL_WIDGET (self));
- return (self->checker != NULL && self->spellchecker_language != NULL);
+ return (self->editor_view_addin != NULL && self->language != NULL);
}
static void
@@ -826,6 +610,7 @@ gbp_spell_widget__add_button_clicked_cb (GbpSpellWidget *self,
g_assert (GTK_IS_BUTTON (button));
word = gtk_entry_get_text (GTK_ENTRY (self->dict_word_entry));
+
/* TODO: check if word already in dict */
if (check_dict_available (self) && !ide_str_empty0 (word))
{
@@ -845,7 +630,6 @@ gbp_spell_widget__add_button_clicked_cb (GbpSpellWidget *self,
}
gtk_entry_set_text (GTK_ENTRY (self->dict_word_entry), "");
-
}
}
@@ -892,16 +676,24 @@ gbp_spell_widget__language_notify_cb (GbpSpellWidget *self,
const GspellLanguage *spell_language;
g_autofree gchar *word = NULL;
g_autofree gchar *first_result = NULL;
+ GspellNavigator *navigator;
+ GspellChecker *checker;
GtkListBoxRow *row;
g_assert (GBP_IS_SPELL_WIDGET (self));
g_assert (GTK_IS_BUTTON (language_chooser_button));
- current_language = gspell_checker_get_language (self->checker);
+ if (self->editor_view_addin == NULL)
+ return;
+
+ checker = gbp_spell_editor_view_addin_get_checker (self->editor_view_addin);
+ navigator = gbp_spell_editor_view_addin_get_navigator (self->editor_view_addin);
+
+ current_language = gspell_checker_get_language (checker);
spell_language = gspell_language_chooser_get_language (GSPELL_LANGUAGE_CHOOSER (language_chooser_button));
if (gspell_language_compare (current_language, spell_language) != 0)
{
- gspell_checker_set_language (self->checker, spell_language);
+ gspell_checker_set_language (checker, spell_language);
fill_suggestions_box (self, word, &first_result);
if (!ide_str_empty0 (first_result))
{
@@ -910,6 +702,7 @@ gbp_spell_widget__language_notify_cb (GbpSpellWidget *self,
}
g_clear_pointer (&self->words_array, g_ptr_array_unref);
+
if (current_language == NULL)
{
dict_clean_listbox (self);
@@ -922,8 +715,9 @@ gbp_spell_widget__language_notify_cb (GbpSpellWidget *self,
gbp_spell_widget__dict_word_entry_changed_cb (self, GTK_ENTRY (self->dict_word_entry));
gtk_widget_set_sensitive (GTK_WIDGET (self->dict_words_list), TRUE);
- gbp_spell_navigator_goto_word_start (GBP_SPELL_NAVIGATOR (self->navigator));
- jump_to_next_misspelled_word (self);
+ gbp_spell_navigator_goto_word_start (GBP_SPELL_NAVIGATOR (navigator));
+
+ _gbp_spell_widget_move_next_word (self);
}
}
@@ -942,7 +736,7 @@ gbp_spell_widget__word_entry_suggestion_activate (GbpSpellWidget *self,
gtk_entry_set_text (self->word_entry, word);
gtk_editable_set_position (GTK_EDITABLE (self->word_entry), -1);
- update_change_ignore_sensibility (self);
+ _gbp_spell_widget_update_actions (self);
g_signal_handlers_unblock_by_func (self->word_entry, gbp_spell_widget__word_entry_changed_cb, self);
}
@@ -953,18 +747,25 @@ gbp_spell_widget__populate_popup_cb (GbpSpellWidget *self,
GtkEntry *entry)
{
GSList *suggestions = NULL;
+ GspellChecker *checker;
const gchar *text;
GtkWidget *item;
- gint count = 0;
+ guint count = 0;
g_assert (GBP_IS_SPELL_WIDGET (self));
g_assert (GTK_IS_WIDGET (popup));
g_assert (GTK_IS_ENTRY (entry));
+ if (self->editor_view_addin == NULL)
+ return;
+
+ checker = gbp_spell_editor_view_addin_get_checker (self->editor_view_addin);
text = gtk_entry_get_text (entry);
- if (self->is_word_entry_valid ||
- ide_str_empty0 (text) ||
- NULL == (suggestions = gspell_checker_get_suggestions (self->checker, text, -1)))
+
+ if (self->is_word_entry_valid || ide_str_empty0 (text))
+ suggestions = gspell_checker_get_suggestions (checker, text, -1);
+
+ if (suggestions == NULL)
return;
item = g_object_new (GTK_TYPE_SEPARATOR_MENU_ITEM,
@@ -973,13 +774,16 @@ gbp_spell_widget__populate_popup_cb (GbpSpellWidget *self,
gtk_menu_shell_prepend (GTK_MENU_SHELL (popup), item);
suggestions = g_slist_reverse (suggestions);
- for (GSList *l = (GSList *)suggestions; l != NULL; l = l->next)
+
+ for (const GSList *iter = suggestions; iter; iter = iter->next)
{
+ const gchar *word = iter->data;
+
item = g_object_new (GTK_TYPE_MENU_ITEM,
- "label", l->data,
+ "label", word,
"visible", TRUE,
NULL);
- g_object_set_data (G_OBJECT (item), "word", g_strdup (l->data));
+ g_object_set_data (G_OBJECT (item), "word", g_strdup (word));
gtk_menu_shell_prepend (GTK_MENU_SHELL (popup), item);
g_signal_connect_object (item,
"activate",
@@ -1028,27 +832,8 @@ static void
gbp_spell_widget_constructed (GObject *object)
{
GbpSpellWidget *self = (GbpSpellWidget *)object;
- GspellTextBuffer *spell_buffer;
-
- g_assert (IDE_IS_SOURCE_VIEW (self->view));
-
- self->buffer = IDE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->view)));
- ide_buffer_set_spell_checking (self->buffer, TRUE);
-
- self->spellchecking_status = TRUE;
-
- spell_buffer = gspell_text_buffer_get_from_gtk_text_buffer (GTK_TEXT_BUFFER (self->buffer));
- self->checker = gspell_text_buffer_get_spell_checker (spell_buffer);
- gbp_spell_dict_set_checker (self->dict, self->checker);
- self->spellchecker_language = gspell_checker_get_language (self->checker);
- gspell_language_chooser_set_language (GSPELL_LANGUAGE_CHOOSER (self->language_chooser_button),
- self->spellchecker_language);
-
- g_signal_connect_swapped (self->navigator,
- "notify::words-counted",
- G_CALLBACK (gbp_spell_widget__words_counted_cb),
- self);
+ _gbp_spell_widget_init_actions (self);
g_signal_connect_swapped (self->word_entry,
"changed",
@@ -1060,26 +845,6 @@ gbp_spell_widget_constructed (GObject *object)
G_CALLBACK (gbp_spell_widget__populate_popup_cb),
self);
- g_signal_connect_swapped (self->ignore_button,
- "clicked",
- G_CALLBACK (gbp_spell_widget__ignore_button_clicked_cb),
- self);
-
- g_signal_connect_swapped (self->ignore_all_button,
- "clicked",
- G_CALLBACK (gbp_spell_widget__ignore_all_button_clicked_cb),
- self);
-
- g_signal_connect_swapped (self->change_button,
- "clicked",
- G_CALLBACK (gbp_spell_widget__change_button_clicked_cb),
- self);
-
- g_signal_connect_swapped (self->change_all_button,
- "clicked",
- G_CALLBACK (gbp_spell_widget__change_all_button_clicked_cb),
- self);
-
g_signal_connect_swapped (self->suggestions_box,
"row-selected",
G_CALLBACK (gbp_spell_widget__row_selected_cb),
@@ -1090,16 +855,6 @@ gbp_spell_widget_constructed (GObject *object)
G_CALLBACK (gbp_spell_widget__row_activated_cb),
self);
- g_signal_connect_swapped (self,
- "key-press-event",
- G_CALLBACK (gbp_spell_widget__key_press_event_cb),
- self);
-
- g_signal_connect_swapped (self->highlight_switch,
- "state-set",
- G_CALLBACK (gbp_spell_widget__highlight_switch_toggled_cb),
- self);
-
g_signal_connect_object (self->language_chooser_button,
"notify::language",
G_CALLBACK (gbp_spell_widget__language_notify_cb),
@@ -1120,16 +875,6 @@ gbp_spell_widget_constructed (GObject *object)
gtk_widget_set_visible (self->placeholder, TRUE);
gtk_list_box_set_placeholder (self->suggestions_box, self->placeholder);
- /* Due to the change of focus between the view and the spellchecker widget,
- * we need to start checking only when the widget is mapped,
- * so the view can keep the selection on the first word.
- */
- g_signal_connect_object (self,
- "map",
- G_CALLBACK (gbp_spell__widget_mapped_cb),
- NULL,
- G_CONNECT_AFTER);
-
g_signal_connect_swapped (self->dict,
"loaded",
G_CALLBACK (gbp_spell_widget__dict__loaded_cb),
@@ -1143,42 +888,73 @@ gbp_spell_widget_constructed (GObject *object)
}
static void
-gbp_spell_widget_finalize (GObject *object)
+gbp_spell_widget_bind_addin (GbpSpellWidget *self,
+ GbpSpellEditorViewAddin *editor_view_addin,
+ DzlSignalGroup *editor_view_addin_signals)
{
- GbpSpellWidget *self = (GbpSpellWidget *)object;
- GspellTextView *spell_text_view;
- const GspellLanguage *spell_language;
- GtkTextBuffer *buffer;
+ GspellChecker *checker;
- ide_clear_source (&self->check_word_timeout_id);
+ g_assert (GBP_IS_SPELL_WIDGET (self));
+ g_assert (GBP_IS_SPELL_EDITOR_VIEW_ADDIN (editor_view_addin));
+ g_assert (DZL_IS_SIGNAL_GROUP (editor_view_addin_signals));
+ g_assert (self->editor_view_addin == NULL);
- /* Set back the view spellchecking previous state */
- if (self->view != NULL)
- {
- spell_text_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (self->view));
+ self->editor_view_addin = g_object_ref (editor_view_addin);
- if (self->view_spellchecker_set)
- {
- gspell_text_view_set_inline_spell_checking (spell_text_view, TRUE);
- spell_language = gspell_checker_get_language (self->checker);
- if (gspell_language_compare (self->spellchecker_language, spell_language) != 0)
- gspell_checker_set_language (self->checker, self->spellchecker_language);
- }
- else
- {
- gspell_text_view_set_inline_spell_checking (spell_text_view, FALSE);
- gspell_text_view_set_enable_language_menu (spell_text_view, FALSE);
+ gbp_spell_editor_view_addin_begin_checking (editor_view_addin);
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->view));
- ide_buffer_set_spell_checking (IDE_BUFFER (buffer), FALSE);
- }
+ checker = gbp_spell_editor_view_addin_get_checker (editor_view_addin);
+ gbp_spell_dict_set_checker (self->dict, checker);
- ide_clear_weak_pointer (&self->view);
- }
+ self->language = gspell_checker_get_language (checker);
+ gspell_language_chooser_set_language (GSPELL_LANGUAGE_CHOOSER (self->language_chooser_button),
self->language);
+
+ self->spellchecking_status = TRUE;
+
+ _gbp_spell_widget_move_next_word (self);
+}
+
+static void
+gbp_spell_widget_unbind_addin (GbpSpellWidget *self,
+ DzlSignalGroup *editor_view_addin_signals)
+{
+ g_assert (GBP_IS_SPELL_WIDGET (self));
+ g_assert (DZL_IS_SIGNAL_GROUP (editor_view_addin_signals));
+ g_assert (self->editor_view_addin != NULL);
+
+ gbp_spell_editor_view_addin_end_checking (self->editor_view_addin);
+ gbp_spell_dict_set_checker (self->dict, NULL);
+ self->language = NULL;
+ gspell_language_chooser_set_language (GSPELL_LANGUAGE_CHOOSER (self->language_chooser_button), NULL);
- g_clear_object (&self->navigator);
+ g_clear_object (&self->editor_view_addin);
- G_OBJECT_CLASS (gbp_spell_widget_parent_class)->finalize (object);
+ _gbp_spell_widget_update_actions (self);
+}
+
+static void
+gbp_spell_widget_destroy (GtkWidget *widget)
+{
+ GbpSpellWidget *self = (GbpSpellWidget *)widget;
+
+ g_assert (GBP_IS_SPELL_WIDGET (self));
+
+ ide_clear_source (&self->check_word_timeout_id);
+ ide_clear_source (&self->dict_check_word_timeout_id);
+
+ if (self->editor != NULL)
+ gbp_spell_widget_set_editor (self, NULL);
+
+ self->language = NULL;
+
+ /* Ensure reference holding things are released */
+ g_clear_object (&self->editor);
+ g_clear_object (&self->editor_view_addin);
+ g_clear_object (&self->editor_view_addin_signals);
+ g_clear_object (&self->dict);
+ g_clear_pointer (&self->words_array, g_ptr_array_unref);
+
+ GTK_WIDGET_CLASS (gbp_spell_widget_parent_class)->destroy (widget);
}
static void
@@ -1191,8 +967,8 @@ gbp_spell_widget_get_property (GObject *object,
switch (prop_id)
{
- case PROP_VIEW:
- g_value_set_object (value, gbp_spell_widget_get_view (self));
+ case PROP_EDITOR:
+ g_value_set_object (value, gbp_spell_widget_get_editor (self));
break;
default:
@@ -1210,8 +986,8 @@ gbp_spell_widget_set_property (GObject *object,
switch (prop_id)
{
- case PROP_VIEW:
- gbp_spell_widget_set_view (self, g_value_get_object (value));
+ case PROP_EDITOR:
+ gbp_spell_widget_set_editor (self, g_value_get_object (value));
break;
default:
@@ -1226,16 +1002,15 @@ gbp_spell_widget_class_init (GbpSpellWidgetClass *klass)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->constructed = gbp_spell_widget_constructed;
- object_class->finalize = gbp_spell_widget_finalize;
object_class->get_property = gbp_spell_widget_get_property;
object_class->set_property = gbp_spell_widget_set_property;
- properties [PROP_VIEW] =
- g_param_spec_object ("view",
- "View",
- "The source view.",
- IDE_TYPE_SOURCE_VIEW,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+ widget_class->destroy = gbp_spell_widget_destroy;
+
+ properties [PROP_EDITOR] =
+ g_param_spec_object ("editor", NULL, NULL,
+ IDE_TYPE_EDITOR_VIEW,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
@@ -1244,26 +1019,23 @@ gbp_spell_widget_class_init (GbpSpellWidgetClass *klass)
gtk_widget_class_bind_template_child (widget_class, GbpSpellWidget, word_label);
gtk_widget_class_bind_template_child (widget_class, GbpSpellWidget, count_label);
gtk_widget_class_bind_template_child (widget_class, GbpSpellWidget, word_entry);
- gtk_widget_class_bind_template_child (widget_class, GbpSpellWidget, ignore_button);
- gtk_widget_class_bind_template_child (widget_class, GbpSpellWidget, ignore_all_button);
- gtk_widget_class_bind_template_child (widget_class, GbpSpellWidget, change_button);
- gtk_widget_class_bind_template_child (widget_class, GbpSpellWidget, change_all_button);
- gtk_widget_class_bind_template_child (widget_class, GbpSpellWidget, highlight_switch);
gtk_widget_class_bind_template_child (widget_class, GbpSpellWidget, language_chooser_button);
gtk_widget_class_bind_template_child (widget_class, GbpSpellWidget, suggestions_box);
gtk_widget_class_bind_template_child (widget_class, GbpSpellWidget, dict_word_entry);
gtk_widget_class_bind_template_child (widget_class, GbpSpellWidget, dict_add_button);
gtk_widget_class_bind_template_child (widget_class, GbpSpellWidget, dict_words_list);
gtk_widget_class_bind_template_child (widget_class, GbpSpellWidget, count_box);
+
+ g_type_ensure (GBP_TYPE_SPELL_LANGUAGE_POPOVER);
}
static void
gbp_spell_widget_init (GbpSpellWidget *self)
{
- gtk_widget_init_template (GTK_WIDGET (self));
self->dict = gbp_spell_dict_new (NULL);
- self->view_spellchecker_set = FALSE;
+ gtk_widget_init_template (GTK_WIDGET (self));
+
/* FIXME: do not work, Gtk+ bug */
gtk_entry_set_icon_tooltip_text (self->word_entry,
GTK_ENTRY_ICON_SECONDARY,
@@ -1273,4 +1045,105 @@ gbp_spell_widget_init (GbpSpellWidget *self)
"key-press-event",
G_CALLBACK (dict_row_key_pressed_event_cb),
self);
+
+ self->editor_view_addin_signals = dzl_signal_group_new (GBP_TYPE_SPELL_EDITOR_VIEW_ADDIN);
+
+ dzl_signal_group_connect_swapped (self->editor_view_addin_signals,
+ "notify::words-counted",
+ G_CALLBACK (gbp_spell_widget__words_counted_cb),
+ self);
+
+ g_signal_connect_swapped (self->editor_view_addin_signals,
+ "bind",
+ G_CALLBACK (gbp_spell_widget_bind_addin),
+ self);
+
+ g_signal_connect_swapped (self->editor_view_addin_signals,
+ "unbind",
+ G_CALLBACK (gbp_spell_widget_unbind_addin),
+ self);
+}
+
+/**
+ * gbp_spell_widget_get_editor:
+ * @self: a #GbpSpellWidget
+ *
+ * Gets the editor that is currently being spellchecked.
+ *
+ * Returns: (nullable) (transfer none): An #IdeEditorView or %NULL
+ *
+ * Since: 3.26
+ */
+IdeEditorView *
+gbp_spell_widget_get_editor (GbpSpellWidget *self)
+{
+ g_return_val_if_fail (GBP_IS_SPELL_WIDGET (self), NULL);
+
+ return self->editor;
+}
+
+void
+gbp_spell_widget_set_editor (GbpSpellWidget *self,
+ IdeEditorView *editor)
+{
+ g_return_if_fail (GBP_IS_SPELL_WIDGET (self));
+ g_return_if_fail (!editor || IDE_IS_EDITOR_VIEW (editor));
+
+ if (g_set_object (&self->editor, editor))
+ {
+ IdeEditorViewAddin *addin = NULL;
+
+ if (editor != NULL)
+ addin = ide_editor_view_addin_find_by_module_name (editor, "spellcheck-plugin");
+
+ dzl_signal_group_set_target (self->editor_view_addin_signals, addin);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_EDITOR]);
+ }
}
+
+GtkWidget *
+gbp_spell_widget_new (IdeEditorView *editor)
+{
+ g_return_val_if_fail (!editor || IDE_IS_EDITOR_VIEW (editor), NULL);
+
+ return g_object_new (GBP_TYPE_SPELL_WIDGET,
+ "editor", editor,
+ NULL);
+}
+
+void
+_gbp_spell_widget_change (GbpSpellWidget *self,
+ gboolean change_all)
+{
+ g_autofree gchar *change_to = NULL;
+ GspellNavigator *navigator;
+ GspellChecker *checker;
+ const gchar *word;
+
+ g_assert (GBP_IS_SPELL_WIDGET (self));
+ g_assert (IDE_IS_EDITOR_VIEW (self->editor));
+ g_assert (GBP_IS_SPELL_EDITOR_VIEW_ADDIN (self->editor_view_addin));
+
+ checker = gbp_spell_editor_view_addin_get_checker (self->editor_view_addin);
+ g_assert (GSPELL_IS_CHECKER (checker));
+
+ word = gtk_label_get_text (self->word_label);
+ g_assert (!ide_str_empty0 (word));
+
+ change_to = g_strdup (gtk_entry_get_text (self->word_entry));
+ g_assert (!ide_str_empty0 (change_to));
+
+ navigator = gbp_spell_editor_view_addin_get_navigator (self->editor_view_addin);
+ g_assert (navigator != NULL);
+
+ gspell_checker_set_correction (checker, word, -1, change_to, -1);
+
+ if (change_all)
+ gspell_navigator_change_all (navigator, word, change_to);
+ else
+ gspell_navigator_change (navigator, word, change_to);
+
+ _gbp_spell_widget_move_next_word (self);
+}
+
diff --git a/plugins/spellcheck/gbp-spell-widget.h b/plugins/spellcheck/gbp-spell-widget.h
index 7249aff..b555c0b 100644
--- a/plugins/spellcheck/gbp-spell-widget.h
+++ b/plugins/spellcheck/gbp-spell-widget.h
@@ -16,13 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef GBP_SPELL_WIDGET_H
-#define GBP_SPELL_WIDGET_H
+#pragma once
-#include <glib-object.h>
-#include <gtk/gtk.h>
-
-#include "sourceview/ide-source-view.h"
+#include <ide.h>
G_BEGIN_DECLS
@@ -30,9 +26,9 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GbpSpellWidget, gbp_spell_widget, GBP, SPELL_WIDGET, GtkBin)
-GtkWidget *gbp_spell_widget_new (IdeSourceView *source_view);
-GtkWidget *gbp_spell_widget_get_entry (GbpSpellWidget *self);
+GtkWidget *gbp_spell_widget_new (IdeEditorView *editor);
+IdeEditorView *gbp_spell_widget_get_editor (GbpSpellWidget *self);
+void gbp_spell_widget_set_editor (GbpSpellWidget *self,
+ IdeEditorView *editor);
G_END_DECLS
-
-#endif /* GBP_SPELL_WIDGET_H */
diff --git a/plugins/spellcheck/gbp-spell-widget.ui b/plugins/spellcheck/gbp-spell-widget.ui
index 02ec8cf..f000721 100644
--- a/plugins/spellcheck/gbp-spell-widget.ui
+++ b/plugins/spellcheck/gbp-spell-widget.ui
@@ -8,6 +8,9 @@
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<property name="margin">6</property>
+ <style>
+ <class name="gb-spellchecker"/>
+ </style>
<child>
<object class="GtkLabel">
<property name="visible">true</property>
@@ -61,19 +64,21 @@
<property name="hexpand">true</property>
<property name="homogeneous">true</property>
<child>
- <object class="GtkButton" id="ignore_button">
+ <object class="GtkButton">
+ <property name="action-name">spell-widget.ignore</property>
<property name="label" translatable="yes">_Ignore</property>
<property name="visible">true</property>
- <property name="can_focus">true</property>
- <property name="use_underline">True</property>
+ <property name="can-focus">true</property>
+ <property name="use-underline">True</property>
</object>
</child>
<child>
- <object class="GtkButton" id="ignore_all_button">
+ <object class="GtkButton">
+ <property name="action-name">spell-widget.ignore-all</property>
<property name="label" translatable="yes">Ignore _All</property>
<property name="visible">true</property>
- <property name="can_focus">true</property>
- <property name="use_underline">True</property>
+ <property name="can-focus">true</property>
+ <property name="use-underline">True</property>
</object>
</child>
<style>
@@ -91,8 +96,8 @@
<property name="visible">true</property>
<property name="label" translatable="yes">Change _to</property>
<property name="xalign">0</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">word_entry</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">word_entry</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -103,7 +108,7 @@
<object class="GtkEntry" id="word_entry">
<property name="visible">true</property>
<property name="can_default">true</property>
- <property name="can_focus">true</property>
+ <property name="can-focus">true</property>
<property name="width-chars">20</property>
<property name="max-width-chars">30</property>
</object>
@@ -120,19 +125,21 @@
<property name="hexpand">true</property>
<property name="homogeneous">true</property>
<child>
- <object class="GtkButton" id="change_button">
+ <object class="GtkButton">
+ <property name="action-name">spell-widget.change</property>
<property name="label" translatable="yes">Cha_nge</property>
<property name="visible">true</property>
- <property name="can_focus">true</property>
- <property name="use_underline">True</property>
+ <property name="can-focus">true</property>
+ <property name="use-underline">True</property>
</object>
</child>
<child>
- <object class="GtkButton" id="change_all_button">
+ <object class="GtkButton">
+ <property name="action-name">spell-widget.change-all</property>
<property name="label" translatable="yes">Change A_ll</property>
<property name="visible">true</property>
- <property name="can_focus">true</property>
- <property name="use_underline">True</property>
+ <property name="can-focus">true</property>
+ <property name="use-underline">True</property>
</object>
</child>
<style>
@@ -152,8 +159,8 @@
<property name="margin-top">6</property>
<property name="xalign">0</property>
<property name="valign">start</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">suggestions_box</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">suggestions_box</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -171,7 +178,7 @@
<child>
<object class="GtkListBox" id="suggestions_box">
<property name="visible">true</property>
- <property name="can_focus">true</property>
+ <property name="can-focus">true</property>
<property name="activate-on-single-click">false</property>
</object>
</child>
@@ -187,8 +194,8 @@
<property name="visible">true</property>
<property name="label" translatable="yes">Add Word</property>
<property name="xalign">0</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">word_entry</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">word_entry</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -203,7 +210,7 @@
<object class="GtkEntry" id="dict_word_entry">
<property name="visible">true</property>
<property name="hexpand">true</property>
- <property name="can_focus">true</property>
+ <property name="can-focus">true</property>
<property name="width-chars">20</property>
<property name="max-width-chars">20</property>
</object>
@@ -212,8 +219,8 @@
<object class="GtkButton" id="dict_add_button">
<property name="label" translatable="yes">A_dd</property>
<property name="visible">true</property>
- <property name="can_focus">true</property>
- <property name="use_underline">True</property>
+ <property name="can-focus">true</property>
+ <property name="use-underline">True</property>
</object>
</child>
</object>
@@ -250,7 +257,7 @@
<object class="GtkListBox" id="dict_words_list">
<property name="visible">true</property>
<property name="can_default">true</property>
- <property name="can_focus">true</property>
+ <property name="can-focus">true</property>
<property name="activate-on-single-click">false</property>
</object>
</child>
@@ -262,19 +269,6 @@
</packing>
</child>
<child>
- <object class="GtkLabel">
- <property name="visible">true</property>
- <property name="label" translatable="yes">Options</property>
- <property name="xalign">0</property>
- <property name="expand">false</property>
- <property name="use_underline">True</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">7</property>
- </packing>
- </child>
- <child>
<object class="GtkSeparator">
<property name="visible">true</property>
<property name="hexpand">true</property>
@@ -292,8 +286,8 @@
<property name="label" translatable="yes">_Language</property>
<property name="xalign">0</property>
<property name="expand">false</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">language_chooser_button</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">language_chooser_button</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -303,7 +297,7 @@
<child>
<object class="GbpSpellLanguagePopover" id="language_chooser_button">
<property name="visible">true</property>
- <property name="can_focus">true</property>
+ <property name="can-focus">true</property>
<property name="hexpand">true</property>
<property name="valign">fill</property>
</object>
@@ -313,35 +307,6 @@
<property name="width">2</property>
</packing>
</child>
- <child>
- <object class="GtkLabel">
- <property name="visible">true</property>
- <property name="label" translatable="yes">_Highlight</property>
- <property name="xalign">0</property>
- <property name="expand">false</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">highlight_switch</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">10</property>
- </packing>
- </child>
- <child>
- <object class="GtkSwitch" id="highlight_switch">
- <property name="visible">true</property>
- <property name="can_focus">true</property>
- <property name="halign">start</property>
- <property name="expand">false</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">10</property>
- </packing>
- </child>
- <style>
- <class name="gb-spellchecker"/>
- </style>
</object>
</child>
</template>
diff --git a/plugins/spellcheck/gtk/menus.ui b/plugins/spellcheck/gtk/menus.ui
index a2e703f..18a0a0a 100644
--- a/plugins/spellcheck/gtk/menus.ui
+++ b/plugins/spellcheck/gtk/menus.ui
@@ -1,6 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="ide-source-view-popup-menu">
+ <section id="ide-source-view-popup-menu-spellcheck-section">
+ <item>
+ <attribute name="label" translatable="yes">Check _Spelling</attribute>
+ <attribute name="action">spellcheck.spellcheck</attribute>
+ </item>
+ </section>
<section id="ide-source-view-popup-menu-highlighting-section">
<submenu id="ide-source-view-popup-menu-highlighting-submenu">
<attribute name="label" translatable="yes">Highlighting</attribute>
diff --git a/plugins/spellcheck/meson.build b/plugins/spellcheck/meson.build
index de94684..a8dc003 100644
--- a/plugins/spellcheck/meson.build
+++ b/plugins/spellcheck/meson.build
@@ -24,6 +24,7 @@ spellcheck_sources = [
'gbp-spell-utils.h',
'gbp-spell-widget.c',
'gbp-spell-widget.h',
+ 'gbp-spell-widget-actions.c',
spellcheck_resources[0],
]
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]