[gnome-builder/wip/slaf/spellcheck] spellchecking: inital commit



commit 45374f77616a34bba0de7735ec0e0112812e4131
Author: Sebastien Lafargue <slafargue gnome org>
Date:   Wed Dec 7 21:31:32 2016 +0100

    spellchecking: inital commit
    
    contextual menu: Highlighting->spellchecking
    
    Then incorrect words are underlined,
    contextual menu on them to show proposals and
    options (standard Gspell contextual menu)

 configure.ac                            |    2 +
 data/gtk/menus.ui                       |    4 ++
 libide/buffers/ide-buffer.c             |   45 ++++++++++++++++++
 libide/buffers/ide-buffer.h             |    3 +
 libide/editor/ide-editor-view-actions.c |   77 +++++++++++++++++++++++++++++++
 libide/editor/ide-editor-view.c         |   24 ++++++++++
 libide/sourceview/ide-source-view.c     |   53 +++++++++++++++++++++
 libide/sourceview/ide-source-view.h     |    3 +
 8 files changed, 211 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 1bb4c67..05bafe7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -191,6 +191,7 @@ m4_define([libxml_required_version], [2.9.0])
 m4_define([pangoft2_required_version], [1.38.0])
 m4_define([peas_required_version], [1.18.0])
 m4_define([json_glib_required_version], [1.2.0])
+m4_define([gspell_required_version], [1.2.0])
 
 PKG_CHECK_MODULES(EGG,      [glib-2.0 >= glib_required_version
                              gmodule-2.0 >= glib_required_version
@@ -207,6 +208,7 @@ PKG_CHECK_MODULES(LIBIDE,   [gio-2.0 >= glib_required_version
                              gio-unix-2.0 >= glib_required_version
                              gtk+-3.0 >= gtk_required_version
                              gtksourceview-3.0 >= gtksourceview_required_version
+                             gspell-1 >= gspell_required_version
                              json-glib-1.0 >= json_glib_required_version
                              libpeas-1.0 >= peas_required_version
                              libxml-2.0 >= libxml_required_version
diff --git a/data/gtk/menus.ui b/data/gtk/menus.ui
index 6eefece..f23afd3 100644
--- a/data/gtk/menus.ui
+++ b/data/gtk/menus.ui
@@ -149,6 +149,10 @@
     <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>
+        <item>
+          <attribute name="label" translatable="yes">Spellchecking</attribute>
+          <attribute name="action">view.spellchecking</attribute>
+        </item>
       </submenu>
     </section>
     <section id="ide-source-view-popup-menu-selection-section">
diff --git a/libide/buffers/ide-buffer.c b/libide/buffers/ide-buffer.c
index 15dfd97..bb246d2 100644
--- a/libide/buffers/ide-buffer.c
+++ b/libide/buffers/ide-buffer.c
@@ -21,6 +21,7 @@
 #include <egg-counter.h>
 #include <egg-signal-group.h>
 #include <glib/gi18n.h>
+#include <gspell/gspell.h>
 
 #include "ide-context.h"
 #include "ide-debug.h"
@@ -77,6 +78,7 @@ typedef struct
   IdeHighlightEngine     *highlight_engine;
   IdeExtensionAdapter    *rename_provider_adapter;
   IdeExtensionAdapter    *symbol_resolver_adapter;
+  GspellChecker          *spellchecker;
   gchar                  *title;
 
   EggSignalGroup         *file_signals;
@@ -133,6 +135,48 @@ enum {
 static GParamSpec *properties [LAST_PROP];
 static guint signals [LAST_SIGNAL];
 
+void
+ide_buffer_set_spell_checking (IdeBuffer *self,
+                               gboolean   enable)
+{
+  IdeBufferPrivate *priv = ide_buffer_get_instance_private (self);
+  GspellTextBuffer *spell_text_buffer;
+
+  g_return_if_fail (IDE_IS_BUFFER (self));
+
+  if (enable)
+    {
+      if (!GSPELL_IS_CHECKER (priv->spellchecker))
+        {
+          priv->spellchecker = gspell_checker_new (NULL);
+          spell_text_buffer = gspell_text_buffer_get_from_gtk_text_buffer (GTK_TEXT_BUFFER (self));
+          gspell_text_buffer_set_spell_checker (spell_text_buffer, priv->spellchecker);
+        }
+    }
+  else
+    {
+      if (GSPELL_IS_CHECKER (priv->spellchecker))
+        {
+          spell_text_buffer = gspell_text_buffer_get_from_gtk_text_buffer (GTK_TEXT_BUFFER (self));
+          gspell_text_buffer_set_spell_checker (spell_text_buffer, NULL);
+          g_clear_object (&priv->spellchecker);
+        }
+    }
+}
+
+gboolean
+ide_buffer_get_spell_checking (IdeBuffer *self)
+{
+  IdeBufferPrivate *priv = ide_buffer_get_instance_private (self);
+
+  g_return_val_if_fail (IDE_IS_BUFFER (self), FALSE);
+
+  /* We keep a ref on the spellchecker because using gspell_text_buffer_get_from_gtk_text_buffer
+   * and gspell_text_buffer_get_spell_checker always return a valid spellchecker
+   */
+  return GSPELL_IS_CHECKER (priv->spellchecker);
+}
+
 /**
  * ide_buffer_get_has_diagnostics:
  * @self: A #IdeBuffer.
@@ -1227,6 +1271,7 @@ ide_buffer_dispose (GObject *object)
   g_clear_object (&priv->highlight_engine);
   g_clear_object (&priv->rename_provider_adapter);
   g_clear_object (&priv->symbol_resolver_adapter);
+  g_clear_object (&priv->spellchecker);
 
   if (priv->context != NULL)
     {
diff --git a/libide/buffers/ide-buffer.h b/libide/buffers/ide-buffer.h
index d2c6e07..b596b08 100644
--- a/libide/buffers/ide-buffer.h
+++ b/libide/buffers/ide-buffer.h
@@ -71,6 +71,7 @@ IdeFile            *ide_buffer_get_file                      (IdeBuffer
 IdeBufferLineFlags  ide_buffer_get_line_flags                (IdeBuffer            *self,
                                                               guint                 line);
 gboolean            ide_buffer_get_read_only                 (IdeBuffer            *self);
+gboolean            ide_buffer_get_spell_checking            (IdeBuffer            *self);
 gboolean            ide_buffer_get_highlight_diagnostics     (IdeBuffer            *self);
 const gchar        *ide_buffer_get_style_scheme_name         (IdeBuffer            *self);
 const gchar        *ide_buffer_get_title                     (IdeBuffer            *self);
@@ -79,6 +80,8 @@ void                ide_buffer_set_file                      (IdeBuffer
                                                               IdeFile              *file);
 void                ide_buffer_set_highlight_diagnostics     (IdeBuffer            *self,
                                                               gboolean              highlight_diagnostics);
+void                ide_buffer_set_spell_checking            (IdeBuffer            *self,
+                                                              gboolean              enable);
 void                ide_buffer_set_style_scheme_name         (IdeBuffer            *self,
                                                               const gchar          *style_scheme_name);
 void                ide_buffer_trim_trailing_whitespace      (IdeBuffer            *self);
diff --git a/libide/editor/ide-editor-view-actions.c b/libide/editor/ide-editor-view-actions.c
index f3de1c9..403f308 100644
--- a/libide/editor/ide-editor-view-actions.c
+++ b/libide/editor/ide-editor-view-actions.c
@@ -31,6 +31,7 @@
 #include "editor/ide-editor-view-private.h"
 #include "editor/ide-editor-view.h"
 #include "projects/ide-project.h"
+#include "sourceview/ide-source-view.h"
 #include "util/ide-gtk.h"
 #include "util/ide-progress.h"
 #include "vcs/ide-vcs.h"
@@ -663,6 +664,80 @@ ide_editor_view_actions_print (GSimpleAction *action,
   handle_print_result (self, GTK_PRINT_OPERATION (operation), result);
 }
 
+static void
+activate_spellcheck_cb (GtkWidget     *widget,
+                        IdeEditorView *self)
+{
+  IdeEditorView *editor_view = (IdeEditorView *)widget;
+  IdeSourceView *original_view;
+  IdeSourceView *dst_view;
+  GtkTextBuffer *original_buffer;
+  GtkTextBuffer *dst_buffer;
+  GActionGroup *group;
+  GAction *action;
+  GVariant *state;
+  gboolean spellcheck_state;
+
+  if (editor_view == self)
+    return;
+
+  original_view = self->frame1->source_view;
+  original_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (original_view));
+  dst_view = editor_view->frame1->source_view;
+  dst_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dst_view));
+
+  if (original_buffer == dst_buffer)
+    {
+      spellcheck_state = ide_source_view_get_spell_checking (original_view);
+      state = g_variant_new_boolean (spellcheck_state);
+
+      if (NULL != (group = gtk_widget_get_action_group (GTK_WIDGET (editor_view), "view")) &&
+          NULL != (action = g_action_map_lookup_action (G_ACTION_MAP (group), "spellchecking")))
+        {
+          g_simple_action_set_state (G_SIMPLE_ACTION (action), state);
+          ide_source_view_set_spell_checking (dst_view, spellcheck_state);
+
+          if (editor_view->frame2)
+            {
+              dst_view = ide_editor_frame_get_source_view (editor_view->frame2);
+              ide_source_view_set_spell_checking (dst_view, spellcheck_state);
+            }
+        }
+    }
+}
+
+static void
+ide_editor_view_actions_spellchecking (GSimpleAction *action,
+                                       GVariant      *state,
+                                       gpointer       user_data)
+{
+  IdeEditorView *self = user_data;
+  IdeWorkbench *workbench;
+  IdePerspective *editor;
+  IdeSourceView *source_view;
+  gboolean action_state;
+
+  g_assert (IDE_IS_EDITOR_VIEW (self));
+  g_assert (state != NULL);
+  g_assert (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN));
+
+  g_simple_action_set_state (action, state);
+  action_state = g_variant_get_boolean (state);
+
+  source_view = ide_editor_frame_get_source_view (self->frame1);
+  ide_source_view_set_spell_checking (source_view, action_state);
+
+  if (self->frame2)
+    {
+      source_view = ide_editor_frame_get_source_view (self->frame2);
+      ide_source_view_set_spell_checking (source_view, action_state);
+    }
+
+  workbench = ide_widget_get_workbench (GTK_WIDGET (self));
+  editor = ide_workbench_get_perspective_by_name (workbench, "editor");
+  ide_perspective_views_foreach (IDE_PERSPECTIVE (editor), (GtkCallback)activate_spellcheck_cb, self);
+}
+
 static GActionEntry IdeEditorViewActions[] = {
   { "auto-indent", NULL, NULL, "false", ide_editor_view_actions_auto_indent },
   { "close", ide_editor_view_actions_close },
@@ -676,6 +751,7 @@ static GActionEntry IdeEditorViewActions[] = {
   { "show-line-numbers", NULL, NULL, "false", ide_editor_view_actions_show_line_numbers },
   { "show-right-margin", NULL, NULL, "false", ide_editor_view_actions_show_right_margin },
   { "smart-backspace", NULL, NULL, "false", ide_editor_view_actions_smart_backspace },
+  { "spellchecking", NULL, NULL, "false", ide_editor_view_actions_spellchecking },
   { "tab-width", NULL, "i", "8", ide_editor_view_actions_tab_width },
   { "toggle-split", ide_editor_view_actions_toggle_split },
   { "use-spaces", NULL, "b", "false", ide_editor_view_actions_use_spaces },
@@ -689,6 +765,7 @@ ide_editor_view_actions_init (IdeEditorView *self)
   group = g_simple_action_group_new ();
   g_action_map_add_action_entries (G_ACTION_MAP (group), IdeEditorViewActions,
                                    G_N_ELEMENTS (IdeEditorViewActions), self);
+
   gtk_widget_insert_action_group (GTK_WIDGET (self), "view", G_ACTION_GROUP (group));
 
 #define WATCH_PROPERTY(name) \
diff --git a/libide/editor/ide-editor-view.c b/libide/editor/ide-editor-view.c
index 3bf80b2..ebd5a5f 100644
--- a/libide/editor/ide-editor-view.c
+++ b/libide/editor/ide-editor-view.c
@@ -335,6 +335,12 @@ ide_editor_view_create_split (IdeLayoutView *view,
   IdeBuffer *buffer;
   IdeContext *context;
   IdeBufferManager *buf_mgr;
+  IdeSourceView *source_view;
+  IdeSourceView *split_source_view;
+  GActionGroup *group;
+  GAction *action;
+  GVariant *state = NULL;
+  gboolean spellcheck_state;
 
   g_assert (IDE_IS_EDITOR_VIEW (self));
 
@@ -359,6 +365,19 @@ ide_editor_view_create_split (IdeLayoutView *view,
                       "visible", TRUE,
                       NULL);
 
+  source_view = self->frame1->source_view;
+  spellcheck_state = ide_source_view_get_spell_checking (source_view);
+
+  split_source_view = ((IdeEditorView *)ret)->frame1->source_view;
+  ide_source_view_set_spell_checking (split_source_view, spellcheck_state);
+
+  if (NULL != (group = gtk_widget_get_action_group (GTK_WIDGET (ret), "view")) &&
+      NULL != (action = g_action_map_lookup_action (G_ACTION_MAP (group), "spellchecking")))
+    {
+      state = g_variant_new_boolean (spellcheck_state);
+      g_simple_action_set_state (G_SIMPLE_ACTION (action), state);
+    }
+
   return ret;
 }
 
@@ -467,6 +486,7 @@ ide_editor_view_set_split_view (IdeLayoutView *view,
                                 gboolean       split_view)
 {
   IdeEditorView *self = (IdeEditorView *)view;
+  gboolean spellcheck_state;
 
   g_assert (IDE_IS_EDITOR_VIEW (self));
 
@@ -483,6 +503,10 @@ ide_editor_view_set_split_view (IdeLayoutView *view,
                                    "document", self->document,
                                    "visible", TRUE,
                                    NULL);
+
+      spellcheck_state = ide_source_view_get_spell_checking (self->frame1->source_view);
+      ide_source_view_set_spell_checking (self->frame2->source_view, spellcheck_state);
+
       g_signal_connect_object (self->frame2->source_view,
                                "request-documentation",
                                G_CALLBACK (ide_editor_view_request_documentation),
diff --git a/libide/sourceview/ide-source-view.c b/libide/sourceview/ide-source-view.c
index 9087f91..695c3a5 100644
--- a/libide/sourceview/ide-source-view.c
+++ b/libide/sourceview/ide-source-view.c
@@ -20,6 +20,7 @@
 
 #include <glib/gi18n.h>
 #include <stdlib.h>
+#include <gspell/gspell.h>
 
 #include <egg-animation.h>
 #include <egg-binding-group.h>
@@ -185,6 +186,7 @@ typedef struct
   guint                        show_search_shadow : 1;
   guint                        snippet_completion : 1;
   guint                        waiting_for_capture : 1;
+  guint                        spell_checking : 1;
 } IdeSourceViewPrivate;
 
 typedef struct
@@ -231,6 +233,7 @@ enum {
   PROP_SHOW_SEARCH_BUBBLES,
   PROP_SHOW_SEARCH_SHADOW,
   PROP_SNIPPET_COMPLETION,
+  PROP_SPELL_CHECKING,
   PROP_OVERSCROLL,
   LAST_PROP,
 
@@ -5787,6 +5790,41 @@ ide_source_view_real_begin_rename (IdeSourceView *self)
   IDE_EXIT;
 }
 
+void
+ide_source_view_set_spell_checking (IdeSourceView *self,
+                                    gboolean       enable)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+  GspellTextView *spell_text_view;
+
+  g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
+
+  if (priv->spell_checking != enable)
+    {
+      if (IDE_IS_BUFFER (priv->buffer))
+        {
+          spell_text_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (self));
+          gspell_text_view_set_inline_spell_checking (spell_text_view, enable);
+          gspell_text_view_set_enable_language_menu (spell_text_view, enable);
+
+          ide_buffer_set_spell_checking (priv->buffer, enable);
+
+          priv->spell_checking = enable;
+          g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SPELL_CHECKING]);
+        }
+    }
+}
+
+gboolean
+ide_source_view_get_spell_checking (IdeSourceView *self)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+
+  g_return_val_if_fail (IDE_IS_SOURCE_VIEW (self), FALSE);
+
+  return priv->spell_checking;
+}
+
 static void
 ide_source_view_dispose (GObject *object)
 {
@@ -5950,6 +5988,10 @@ ide_source_view_get_property (GObject    *object,
       g_value_set_boolean (value, ide_source_view_get_snippet_completion (self));
       break;
 
+    case PROP_SPELL_CHECKING:
+      g_value_set_boolean (value, ide_source_view_get_spell_checking (self));
+      break;
+
     case PROP_OVERSCROLL:
       g_value_set_int (value, priv->overscroll_num_lines);
       break;
@@ -6051,6 +6093,10 @@ ide_source_view_set_property (GObject      *object,
       ide_source_view_set_snippet_completion (self, g_value_get_boolean (value));
       break;
 
+    case PROP_SPELL_CHECKING:
+      ide_source_view_set_spell_checking (self, g_value_get_boolean (value));
+      break;
+
     case PROP_OVERSCROLL:
       ide_source_view_set_overscroll_num_lines (self, g_value_get_int (value));
       break;
@@ -6302,6 +6348,13 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
                           FALSE,
                           (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  properties [PROP_SPELL_CHECKING] =
+    g_param_spec_boolean ("spell-checking",
+                          "spell-checking",
+                          "If spell checking is activated",
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
   properties [PROP_OVERSCROLL] =
     g_param_spec_int ("overscroll",
                       "Overscroll",
diff --git a/libide/sourceview/ide-source-view.h b/libide/sourceview/ide-source-view.h
index 08e78b8..7ea83c4 100644
--- a/libide/sourceview/ide-source-view.h
+++ b/libide/sourceview/ide-source-view.h
@@ -351,6 +351,7 @@ gboolean                    ide_source_view_get_show_line_diagnostics (IdeSource
 gboolean                    ide_source_view_get_show_search_bubbles   (IdeSourceView              *self);
 gboolean                    ide_source_view_get_show_search_shadow    (IdeSourceView              *self);
 gboolean                    ide_source_view_get_snippet_completion    (IdeSourceView              *self);
+gboolean                    ide_source_view_get_spell_checking        (IdeSourceView              *self);
 void                        ide_source_view_get_visible_rect          (IdeSourceView              *self,
                                                                        GdkRectangle               
*visible_rect);
 void                        ide_source_view_jump                      (IdeSourceView              *self,
@@ -392,6 +393,8 @@ void                        ide_source_view_set_show_search_shadow    (IdeSource
                                                                        gboolean                    
show_search_bubbles);
 void                        ide_source_view_set_snippet_completion    (IdeSourceView              *self,
                                                                        gboolean                    
snippet_completion);
+void                        ide_source_view_set_spell_checking        (IdeSourceView              *self,
+                                                                       gboolean                    enable);
 void                        ide_source_view_set_back_forward_list     (IdeSourceView              *self,
                                                                        IdeBackForwardList         
*back_forward_list);
 gboolean                    ide_source_view_move_mark_onscreen        (IdeSourceView              *self,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]