1 /*
2  * Copyright (C) 2007  Ignacio Casal Quinteiro <nacho.resa@gmail.com>
3  *		 1998, 1999 Alex Roberts, Evan Lawrence
4  * 		 2000  2002 Chema Celorio, Paolo Maggi
5  * 		 2003  2005 Paolo Maggi
6  *
7  * Some funcs based in gedit-view.c file.
8  *
9  *     This program is free software: you can redistribute it and/or modify
10  *     it under the terms of the GNU General Public License as published by
11  *     the Free Software Foundation, either version 3 of the License, or
12  *     (at your option) any later version.
13  *
14  *     This program is distributed in the hope that it will be useful,
15  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *     GNU General Public License for more details.
18  *
19  *     You should have received a copy of the GNU General Public License
20  *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <string.h>
29 
30 #include "gtr-dirs.h"
31 #include "gtr-settings.h"
32 #include "gtr-utils.h"
33 #include "gtr-view.h"
34 #include "gtr-application.h"
35 #include "gtr-debug.h"
36 
37 #include <glib.h>
38 #include <glib/gi18n.h>
39 #include <glib-object.h>
40 #include <gtk/gtk.h>
41 
42 #include <gtksourceview/gtksource.h>
43 #include <dazzle.h>
44 
45 #include <gspell/gspell.h>
46 
47 /**
48  * Converts the language code to a complete language code with the country
49  * If the language contains the country code this returns a new allocated
50  * string copied from *lang*.
51  *
52  * In other case the code is duplicated by default:
53  *
54  * es -> es_ES
55  * pt -> pt_PT
56  */
57 static gchar*
get_default_lang(const gchar * lang)58 get_default_lang (const gchar *lang) {
59   gchar *up;
60   gchar *ret;
61 
62   if (g_strrstr (lang, "_"))
63     {
64       return g_strdup (lang);
65     }
66 
67   up = g_ascii_strup (lang, -1);
68   ret = g_strdup_printf ("%s_%s", lang, up);
69   g_free (up);
70 
71   return ret;
72 }
73 
74 static void
inline_spellcheck(GObject * object,GParamSpec * param,GtrView * view)75 inline_spellcheck (GObject *object,
76                    GParamSpec *param,
77                    GtrView *view)
78 {
79   GspellTextView *gspell_view;
80   gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (view));
81   gspell_text_view_set_inline_spell_checking (gspell_view, TRUE);
82 }
83 
84 typedef struct
85 {
86   GSettings *editor_settings;
87   GSettings *ui_settings;
88 
89   GtkSourceBuffer *buffer;
90 
91   guint search_flags;
92   gchar *search_text;
93 
94   GspellChecker *spell;
95   GtkCssProvider *provider;
96 } GtrViewPrivate;
97 
G_DEFINE_TYPE_WITH_PRIVATE(GtrView,gtr_view,GTK_SOURCE_TYPE_VIEW)98 G_DEFINE_TYPE_WITH_PRIVATE (GtrView, gtr_view, GTK_SOURCE_TYPE_VIEW)
99 
100 static void
101 gtr_view_init (GtrView * view)
102 {
103   GtkSourceLanguageManager *lm;
104   GtkSourceLanguage *lang;
105   GPtrArray *dirs;
106   gchar **langs;
107   const gchar *const *temp;
108   gchar *ui_dir;
109   GtrViewPrivate *priv;
110 
111   g_autofree char *font = NULL;
112 
113   priv = gtr_view_get_instance_private (view);
114 
115   priv->provider = gtk_css_provider_new ();
116   gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (view)),
117                                   GTK_STYLE_PROVIDER (priv->provider),
118                                   GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
119 
120   priv->spell = NULL;
121   priv->editor_settings = g_settings_new ("org.gnome.gtranslator.preferences.editor");
122   priv->ui_settings = g_settings_new ("org.gnome.gtranslator.preferences.ui");
123 
124   lm = gtk_source_language_manager_new ();
125   dirs = g_ptr_array_new ();
126 
127   for (temp = gtk_source_language_manager_get_search_path (lm);
128        temp != NULL && *temp != NULL; ++temp)
129     g_ptr_array_add (dirs, g_strdup (*temp));
130 
131   ui_dir = g_build_filename (gtr_dirs_get_gtr_data_dir (), "ui", NULL);
132   g_ptr_array_add (dirs, ui_dir);
133   g_ptr_array_add (dirs, NULL);
134   langs = (gchar **) g_ptr_array_free (dirs, FALSE);
135 
136   gtk_source_language_manager_set_search_path (lm, langs);
137   lang = gtk_source_language_manager_get_language (lm, "gtranslator");
138   g_strfreev (langs);
139 
140   priv->buffer = gtk_source_buffer_new_with_language (lang);
141 
142   gtk_text_view_set_buffer (GTK_TEXT_VIEW (view),
143                             GTK_TEXT_BUFFER (priv->buffer));
144   gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view), GTK_WRAP_WORD);
145 
146   /* Set syntax highlight according to preferences */
147   gtk_source_buffer_set_highlight_syntax (priv->buffer,
148                                           g_settings_get_boolean (priv->editor_settings,
149                                                                   GTR_SETTINGS_HIGHLIGHT_SYNTAX));
150 
151   /* Set dot char according to preferences */
152   gtr_view_enable_visible_whitespace (view,
153                                       g_settings_get_boolean (priv->editor_settings,
154                                                               GTR_SETTINGS_VISIBLE_WHITESPACE));
155 
156   font = g_settings_get_string (priv->editor_settings, GTR_SETTINGS_FONT);
157   gtr_view_set_font (view, font);
158 
159   /* Set scheme color according to preferences */
160   gtr_view_reload_scheme_color (view);
161   gtk_text_view_set_monospace (GTK_TEXT_VIEW (view), TRUE);
162 }
163 
164 static void
gtr_view_dispose(GObject * object)165 gtr_view_dispose (GObject * object)
166 {
167   GtrView *view = GTR_VIEW (object);
168   GtrViewPrivate *priv;
169 
170   priv = gtr_view_get_instance_private (view);
171 
172   g_clear_object (&priv->editor_settings);
173   g_clear_object (&priv->ui_settings);
174   g_clear_object (&priv->spell);
175   g_object_unref (&priv->provider);
176 
177   G_OBJECT_CLASS (gtr_view_parent_class)->dispose (object);
178 }
179 
180 static void
gtr_view_class_init(GtrViewClass * klass)181 gtr_view_class_init (GtrViewClass * klass)
182 {
183   GObjectClass *object_class = G_OBJECT_CLASS (klass);
184 
185   object_class->dispose = gtr_view_dispose;
186 }
187 
188 /**
189  * gtr_view_new:
190  *
191  * Creates a new #GtrView. An empty default buffer will be created for you.
192  *
193  * Returns: a new #GtrView
194  */
195 GtkWidget *
gtr_view_new(void)196 gtr_view_new (void)
197 {
198   GtkWidget *view;
199 
200   view = GTK_WIDGET (g_object_new (GTR_TYPE_VIEW, NULL));
201   return view;
202 }
203 
204 /**
205  * gtr_view_get_selected_text:
206  * @view: a #GtrView
207  * @selected_text: it stores the text selected in the #GtrView
208  * @len: it stores the length of the @selected_text
209  *
210  * Gets the selected text region of the #GtrView
211  *
212  * Returns: TRUE if the @selected_text was got correctly.
213  */
214 gboolean
gtr_view_get_selected_text(GtrView * view,gchar ** selected_text,gint * len)215 gtr_view_get_selected_text (GtrView * view,
216                             gchar ** selected_text, gint * len)
217 {
218   GtkTextIter start, end;
219   GtkTextBuffer *doc;
220 
221   g_return_val_if_fail (selected_text != NULL, FALSE);
222   g_return_val_if_fail (*selected_text == NULL, FALSE);
223   g_return_val_if_fail (GTR_IS_VIEW (view), FALSE);
224 
225   doc = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
226 
227   if (!gtk_text_buffer_get_selection_bounds (doc, &start, &end))
228     {
229       if (len != NULL)
230         len = 0;
231 
232       return FALSE;
233     }
234 
235   *selected_text = gtk_text_buffer_get_slice (doc, &start, &end, TRUE);
236 
237   if (len != NULL)
238     *len = g_utf8_strlen (*selected_text, -1);
239 
240   return TRUE;
241 }
242 
243 void
gtr_view_set_language(GtrView * view,const gchar * lang)244 gtr_view_set_language (GtrView *view,
245                        const gchar *lang)
246 {
247   GtrViewPrivate *priv = gtr_view_get_instance_private (view);
248   GList *langs = (GList *)gspell_language_get_available ();
249   gchar **lang_parts = NULL;
250   gboolean found = FALSE;
251   gchar *def_lang;
252 
253   if (!lang || *lang == '\0')
254     return;
255 
256   def_lang = get_default_lang (lang);
257 
258   while (langs)
259     {
260       GspellLanguage *l = (GspellLanguage*) langs->data;
261       const gchar *code = gspell_language_get_code (l);
262       if (g_strcmp0 (def_lang, code) == 0)
263         {
264           gspell_checker_set_language (priv->spell, l);
265           // If we found the language exacly, we're finished
266           found = TRUE;
267           break;
268         }
269 
270       langs = g_list_next (langs);
271     }
272 
273   g_free (def_lang);
274 
275   if (found)
276     return;
277 
278   // Not found, trying again, but this time only with the first part of
279   // the language code
280 
281   langs = (GList *)gspell_language_get_available ();
282   lang_parts = g_strsplit (lang, "_", 2);
283   while (langs)
284     {
285       GspellLanguage *l = (GspellLanguage*) langs->data;
286       const gchar *code = gspell_language_get_code (l);
287       gchar **parts = g_strsplit (code, "_", 2);
288       if (parts[0] && g_strcmp0 (parts[0], lang_parts[0]) == 0)
289         {
290           gspell_checker_set_language (priv->spell, l);
291           g_strfreev (parts);
292           found = TRUE;
293           break;
294         }
295       g_strfreev (parts);
296 
297       langs = g_list_next (langs);
298     }
299   g_strfreev (lang_parts);
300 
301   if (!found)
302     {
303       GspellTextView *gspell_view;
304       gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (view));
305       gspell_text_view_set_inline_spell_checking (gspell_view, FALSE);
306     }
307 }
308 
309 /**
310  * gtr_view_enable_spellcheck:
311  * @view: a #GtrView
312  * @enable: TRUE if you want enable the spellcheck
313  *
314  * Enables the spellcheck
315  **/
316 void
gtr_view_enable_spellcheck(GtrView * view,gboolean enable)317 gtr_view_enable_spellcheck (GtrView * view, gboolean enable)
318 {
319   GtrViewPrivate *priv;
320   GspellTextView *gspell_view;
321   GtkTextBuffer *gtk_buffer;
322   GspellTextBuffer *gspell_buffer;
323 
324   priv = gtr_view_get_instance_private (view);
325 
326   priv->spell = gspell_checker_new (NULL);
327   gtk_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
328   gspell_buffer = gspell_text_buffer_get_from_gtk_text_buffer (gtk_buffer);
329   gspell_text_buffer_set_spell_checker (gspell_buffer, priv->spell);
330 
331   gspell_view = gspell_text_view_get_from_gtk_text_view (GTK_TEXT_VIEW (view));
332   gspell_text_view_set_inline_spell_checking (gspell_view, enable);
333   gspell_text_view_set_enable_language_menu (gspell_view, TRUE);
334 
335   g_signal_connect (G_OBJECT (priv->spell), "notify::language",
336                     G_CALLBACK (inline_spellcheck), view);
337 }
338 
339 /**
340  * gtr_view_enable_visible_whitespace:
341  * @view: a #GtrView
342  * @enable: TRUE if you want to enable special chars for white spaces
343  *
344  * Enables special chars for white spaces including \n and \t
345 **/
346 void
gtr_view_enable_visible_whitespace(GtrView * view,gboolean enable)347 gtr_view_enable_visible_whitespace (GtrView * view, gboolean enable)
348 {
349   GtkSourceView *source;
350   GtkSourceSpaceDrawer *drawer;
351   GtkSourceBuffer *buffer;
352   GtkSourceLanguageManager *manager;
353   GtkSourceLanguage *lang;
354   const gchar * const * deflangs = NULL;
355   const gchar *langs[20] = {NULL};
356   gint i = 0;
357 
358   g_return_if_fail (GTR_IS_VIEW (view));
359 
360   manager = gtk_source_language_manager_get_default ();
361   deflangs = gtk_source_language_manager_get_search_path (manager);
362   langs[1] = deflangs[0];
363 
364   while (deflangs[i] && i < 18) {
365     langs[i] = deflangs[i];
366     i++;
367   }
368   langs[i] = gtr_dirs_get_gtr_sourceview_dir ();
369 
370   manager = gtk_source_language_manager_new ();
371   gtk_source_language_manager_set_search_path (manager, (gchar **)langs);
372   lang = gtk_source_language_manager_get_language (manager, "gtranslator");
373 
374   source = GTK_SOURCE_VIEW (view);
375   drawer = gtk_source_view_get_space_drawer (source);
376   gtk_source_space_drawer_set_enable_matrix (drawer, TRUE);
377   buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
378   gtk_source_buffer_set_implicit_trailing_newline (buffer, FALSE);
379   gtk_source_buffer_set_language (buffer, lang);
380 
381   gtk_source_buffer_set_highlight_syntax (buffer, TRUE);
382 
383   if (enable)
384     gtk_source_space_drawer_set_types_for_locations (drawer,
385                                                      GTK_SOURCE_SPACE_LOCATION_ALL,
386                                                      GTK_SOURCE_SPACE_TYPE_ALL);
387   else
388     gtk_source_space_drawer_set_types_for_locations (drawer,
389                                                      GTK_SOURCE_SPACE_LOCATION_NONE,
390                                                      GTK_SOURCE_SPACE_TYPE_NONE);
391 }
392 
393 /**
394  * gtr_view_cut_clipboard:
395  * @view: a #GtrView
396  *
397  * Copies the currently-selected text to a clipboard,
398  * then deletes said text if it's editable.
399  */
400 void
gtr_view_cut_clipboard(GtrView * view)401 gtr_view_cut_clipboard (GtrView * view)
402 {
403   GtkTextBuffer *buffer;
404   GtkClipboard *clipboard;
405 
406   g_return_if_fail (GTR_IS_VIEW (view));
407 
408   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
409   g_return_if_fail (buffer != NULL);
410 
411   clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
412                                         GDK_SELECTION_CLIPBOARD);
413 
414   /* FIXME: what is default editability of a buffer? */
415   gtk_text_buffer_cut_clipboard (buffer,
416                                  clipboard,
417                                  gtk_text_view_get_editable (GTK_TEXT_VIEW
418                                                              (view)));
419 
420   gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
421                                 gtk_text_buffer_get_insert (buffer),
422                                 0.0, FALSE, 0.0, 0.0);
423 }
424 
425 /**
426  * gtr_view_copy_clipboard:
427  * @view: a #GtrView
428  *
429  * Copies the currently-selected text to a clipboard.
430  */
431 void
gtr_view_copy_clipboard(GtrView * view)432 gtr_view_copy_clipboard (GtrView * view)
433 {
434   GtkTextBuffer *buffer;
435   GtkClipboard *clipboard;
436 
437   g_return_if_fail (GTR_IS_VIEW (view));
438 
439   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
440   g_return_if_fail (buffer != NULL);
441 
442   clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
443                                         GDK_SELECTION_CLIPBOARD);
444 
445   gtk_text_buffer_copy_clipboard (buffer, clipboard);
446 
447   /* on copy do not scroll, we are already on screen */
448 }
449 
450 /**
451  * gtr_view_paste_clipboard:
452  * @view: a #GtrView
453  *
454  * Pastes the contents of a clipboard at the insertion point,
455  * or at override_location.
456  */
457 void
gtr_view_paste_clipboard(GtrView * view)458 gtr_view_paste_clipboard (GtrView * view)
459 {
460   GtkTextBuffer *buffer;
461   GtkClipboard *clipboard;
462 
463   g_return_if_fail (GTR_IS_VIEW (view));
464 
465   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
466   g_return_if_fail (buffer != NULL);
467 
468   clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
469                                         GDK_SELECTION_CLIPBOARD);
470 
471   /* FIXME: what is default editability of a buffer? */
472   gtk_text_buffer_paste_clipboard (buffer,
473                                    clipboard,
474                                    NULL,
475                                    gtk_text_view_get_editable (GTK_TEXT_VIEW
476                                                                (view)));
477 
478   gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
479                                 gtk_text_buffer_get_insert (buffer),
480                                 0.0, FALSE, 0.0, 0.0);
481 }
482 
483 
484 /**
485  * gtr_view_set_search_text:
486  * @view: a #GtrView
487  * @text: the text to set for searching
488  * @flags: a #GtrSearchFlags
489  *
490  * Stores the text to search for in the @view with some specific @flags.
491  */
492 void
gtr_view_set_search_text(GtrView * view,const gchar * text,guint flags)493 gtr_view_set_search_text (GtrView * view, const gchar * text, guint flags)
494 {
495   GtrViewPrivate *priv;
496   gchar *converted_text;
497 
498   g_return_if_fail (GTR_IS_VIEW (view));
499 
500   priv = gtr_view_get_instance_private (view);
501   g_return_if_fail ((text == NULL) || (priv->search_text != text));
502   g_return_if_fail ((text == NULL) || g_utf8_validate (text, -1, NULL));
503 
504   //gedit_debug_message (DEBUG_DOCUMENT, "text = %s", text);
505 
506   if (text != NULL)
507     {
508       if (*text != '\0')
509         {
510           converted_text = gtr_utils_unescape_search_text (text);
511         }
512       else
513         {
514           converted_text = g_strdup ("");
515         }
516 
517       g_free (priv->search_text);
518 
519       priv->search_text = converted_text;
520       //priv->num_of_lines_search_text = compute_num_of_lines (priv->search_text);
521       //update_to_search_region = TRUE;
522     }
523 
524   if (!GTR_SEARCH_IS_DONT_SET_FLAGS (flags))
525     {
526       /*if (priv->search_flags != flags)
527          update_to_search_region = TRUE; */
528 
529       priv->search_flags = flags;
530 
531     }
532 
533   /*if (update_to_search_region)
534      {
535      GtkTextIter begin;
536      GtkTextIter end;
537 
538      gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc),
539      &begin,
540      &end);
541 
542      to_search_region_range (doc,
543      &begin,
544      &end);
545      } */
546 }
547 
548 /**
549  * gtr_view_get_search_text:
550  * @view: a #GtrView
551  * @flags: the #GtrSearchFlags of the stored text.
552  *
553  * Returns the text to search for it and the #GtrSearchFlags of that
554  * text.
555  *
556  * Returns: the text to search for it.
557  */
558 gchar *
gtr_view_get_search_text(GtrView * view,guint * flags)559 gtr_view_get_search_text (GtrView * view, guint * flags)
560 {
561   GtrViewPrivate *priv;
562 
563   g_return_val_if_fail (GTR_IS_VIEW (view), NULL);
564 
565   priv = gtr_view_get_instance_private (view);
566 
567   if (flags != NULL)
568     *flags = priv->search_flags;
569 
570   return gtr_utils_escape_search_text (priv->search_text);
571 }
572 
573 /**
574  * gtr_view_get_can_search_again:
575  * @view: a #GtrView
576  *
577  * Returns: TRUE if it can search again
578  */
579 gboolean
gtr_view_get_can_search_again(GtrView * view)580 gtr_view_get_can_search_again (GtrView * view)
581 {
582   GtrViewPrivate *priv;
583 
584   g_return_val_if_fail (GTR_IS_VIEW (view), FALSE);
585 
586   priv = gtr_view_get_instance_private (view);
587   return ((priv->search_text != NULL) &&
588           (*priv->search_text != '\0'));
589 }
590 
591 /**
592  * gtr_view_search_forward:
593  * @view: a #GtrView
594  * @start: start of search
595  * @end: bound for the search, or %NULL for the end of the buffer
596  * @match_start: return location for start of match, or %NULL
597  * @match_end: return location for end of match, or %NULL
598  *
599  * Searches forward for str. Any match is returned by setting match_start to the
600  * first character of the match and match_end to the first character after the match.
601  * The search will not continue past limit.
602  * Note that a search is a linear or O(n) operation, so you may wish to use limit
603  * to avoid locking up your UI on large buffers.
604  *
605  * Returns: whether a match was found
606  */
607 gboolean
gtr_view_search_forward(GtrView * view,const GtkTextIter * start,const GtkTextIter * end,GtkTextIter * match_start,GtkTextIter * match_end)608 gtr_view_search_forward (GtrView * view,
609                          const GtkTextIter * start,
610                          const GtkTextIter * end,
611                          GtkTextIter * match_start, GtkTextIter * match_end)
612 {
613   GtkSourceBuffer *doc;
614   GtkTextIter iter;
615   GtkTextSearchFlags search_flags;
616   gboolean found = FALSE;
617   GtkTextIter m_start;
618   GtkTextIter m_end;
619   GtrViewPrivate *priv;
620 
621   g_return_val_if_fail (GTR_IS_VIEW (view), FALSE);
622 
623   doc = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
624 
625   g_return_val_if_fail ((start == NULL) ||
626                         (gtk_text_iter_get_buffer (start) ==
627                          GTK_TEXT_BUFFER (doc)), FALSE);
628   g_return_val_if_fail ((end == NULL)
629                         || (gtk_text_iter_get_buffer (end) ==
630                             GTK_TEXT_BUFFER (doc)), FALSE);
631 
632   priv = gtr_view_get_instance_private (view);
633 
634   if (priv->search_text == NULL)
635     {
636       //gedit_debug_message (DEBUG_DOCUMENT, "doc->priv->search_text == NULL\n");
637       return FALSE;
638     }
639   /*else
640      gedit_debug_message (DEBUG_DOCUMENT, "doc->priv->search_text == \"%s\"\n", doc->priv->search_text); */
641 
642   if (start == NULL)
643     gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (doc), &iter);
644   else
645     iter = *start;
646 
647   search_flags = GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY;
648 
649   if (!GTR_SEARCH_IS_CASE_SENSITIVE (priv->search_flags))
650     {
651       search_flags = search_flags | GTK_TEXT_SEARCH_CASE_INSENSITIVE;
652     }
653 
654   while (!found)
655     {
656       found = gtk_text_iter_forward_search (&iter,
657                                             priv->search_text,
658                                             search_flags,
659                                             &m_start, &m_end, end);
660 
661       if (found && GTR_SEARCH_IS_ENTIRE_WORD (priv->search_flags))
662         {
663           found = gtk_text_iter_starts_word (&m_start) &&
664             gtk_text_iter_ends_word (&m_end);
665 
666           if (!found)
667             iter = m_end;
668         }
669       else
670         break;
671     }
672 
673   if (found && (match_start != NULL))
674     *match_start = m_start;
675 
676   if (found && (match_end != NULL))
677     *match_end = m_end;
678 
679   return found;
680 }
681 
682 /**
683  * gtr_view_search_backward:
684  * @view: a #GtrView
685  * @start: start of search
686  * @end: bound for the search, or %NULL for the end of the buffer
687  * @match_start: return location for start of match, or %NULL
688  * @match_end: return location for end of match, or %NULL
689  *
690  * Searches backward for str. Any match is returned by setting match_start to the
691  * first character of the match and match_end to the first character after the match.
692  * The search will not continue past limit.
693  * Note that a search is a linear or O(n) operation, so you may wish to use limit
694  * to avoid locking up your UI on large buffers.
695  *
696  * Returns: whether a match was found
697  */
698 gboolean
gtr_view_search_backward(GtrView * view,const GtkTextIter * start,const GtkTextIter * end,GtkTextIter * match_start,GtkTextIter * match_end)699 gtr_view_search_backward (GtrView * view,
700                           const GtkTextIter * start,
701                           const GtkTextIter * end,
702                           GtkTextIter * match_start, GtkTextIter * match_end)
703 {
704   GtkSourceBuffer *doc;
705   GtkTextIter iter;
706   GtkTextSearchFlags search_flags;
707   gboolean found = FALSE;
708   GtkTextIter m_start;
709   GtkTextIter m_end;
710   GtrViewPrivate *priv;
711 
712   g_return_val_if_fail (GTR_IS_VIEW (view), FALSE);
713 
714   doc = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
715 
716   g_return_val_if_fail ((start == NULL) ||
717                         (gtk_text_iter_get_buffer (start) ==
718                          GTK_TEXT_BUFFER (doc)), FALSE);
719   g_return_val_if_fail ((end == NULL)
720                         || (gtk_text_iter_get_buffer (end) ==
721                             GTK_TEXT_BUFFER (doc)), FALSE);
722 
723   priv = gtr_view_get_instance_private (view);
724 
725   if (priv->search_text == NULL)
726     {
727       //gedit_debug_message (DEBUG_DOCUMENT, "doc->priv->search_text == NULL\n");
728       return FALSE;
729     }
730   /*else
731      gedit_debug_message (DEBUG_DOCUMENT, "doc->priv->search_text == \"%s\"\n", doc->priv->search_text); */
732 
733   if (end == NULL)
734     gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &iter);
735   else
736     iter = *end;
737 
738   search_flags = GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY;
739 
740   if (!GTR_SEARCH_IS_CASE_SENSITIVE (priv->search_flags))
741     {
742       search_flags = search_flags | GTK_TEXT_SEARCH_CASE_INSENSITIVE;
743     }
744 
745   while (!found)
746     {
747       found = gtk_text_iter_backward_search (&iter,
748                                              priv->search_text,
749                                              search_flags,
750                                              &m_start, &m_end, start);
751 
752       if (found && GTR_SEARCH_IS_ENTIRE_WORD (priv->search_flags))
753         {
754           found = gtk_text_iter_starts_word (&m_start) &&
755             gtk_text_iter_ends_word (&m_end);
756 
757           if (!found)
758             iter = m_start;
759         }
760       else
761         break;
762     }
763 
764   if (found && (match_start != NULL))
765     *match_start = m_start;
766 
767   if (found && (match_end != NULL))
768     *match_end = m_end;
769 
770   return found;
771 }
772 
773 /**
774  * gtr_view_replace_all:
775  * @view: a #GtrView
776  * @find: the text to find
777  * @replace: the text to replace @find
778  * @flags: a #GtrSearchFlags
779  *
780  * Replaces all matches of @find with @replace and returns the number of
781  * replacements.
782  *
783  * Returns: the number of replacements made it.
784  */
785 gint
gtr_view_replace_all(GtrView * view,const gchar * find,const gchar * replace,guint flags)786 gtr_view_replace_all (GtrView * view,
787                       const gchar * find, const gchar * replace, guint flags)
788 {
789   GtkTextIter iter;
790   GtkTextIter m_start;
791   GtkTextIter m_end;
792   GtkTextSearchFlags search_flags = 0;
793   GtrViewPrivate *priv;
794   gboolean found = TRUE;
795   gint cont = 0;
796   gchar *search_text;
797   gchar *replace_text;
798   gint replace_text_len;
799   GtkTextBuffer *buffer;
800 
801   g_return_val_if_fail (GTR_IS_VIEW (view), 0);
802 
803   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
804 
805   priv = gtr_view_get_instance_private (view);
806 
807   g_return_val_if_fail (replace != NULL, 0);
808   g_return_val_if_fail ((find != NULL)
809                         || (priv->search_text != NULL), 0);
810 
811   if (find == NULL)
812     search_text = g_strdup (priv->search_text);
813   else
814     search_text = gtr_utils_unescape_search_text (find);
815 
816   replace_text = gtr_utils_unescape_search_text (replace);
817 
818   gtk_text_buffer_get_start_iter (buffer, &iter);
819 
820   search_flags = GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY;
821 
822   if (!GTR_SEARCH_IS_CASE_SENSITIVE (flags))
823     {
824       search_flags = search_flags | GTK_TEXT_SEARCH_CASE_INSENSITIVE;
825     }
826 
827   replace_text_len = strlen (replace_text);
828 
829   /* disable cursor_moved emission until the end of the
830    * replace_all so that we don't spend all the time
831    * updating the position in the statusbar
832    */
833   //priv->stop_cursor_moved_emission = TRUE;
834 
835   gtk_text_buffer_begin_user_action (buffer);
836 
837   do
838     {
839       found = gtk_text_iter_forward_search (&iter,
840                                             search_text,
841                                             search_flags,
842                                             &m_start, &m_end, NULL);
843 
844       if (found && GTR_SEARCH_IS_ENTIRE_WORD (flags))
845         {
846           gboolean word;
847 
848           word = gtk_text_iter_starts_word (&m_start) &&
849             gtk_text_iter_ends_word (&m_end);
850 
851           if (!word)
852             {
853               iter = m_end;
854               continue;
855             }
856         }
857 
858       if (found)
859         {
860           ++cont;
861 
862           gtk_text_buffer_delete (buffer, &m_start, &m_end);
863           gtk_text_buffer_insert (buffer,
864                                   &m_start, replace_text, replace_text_len);
865 
866           iter = m_start;
867         }
868 
869     }
870   while (found);
871 
872   gtk_text_buffer_end_user_action (buffer);
873 
874   /* re-enable cursor_moved emission and notify
875    * the current position
876    */
877   //priv->stop_cursor_moved_emission = FALSE;
878   //emit_cursor_moved (GTK_SOURCE_BUFFER(buffer));
879 
880   g_free (search_text);
881   g_free (replace_text);
882 
883   return cont;
884 }
885 
886 /**
887  * gtr_view_reload_scheme_color:
888  * @view: a #GtrView
889  *
890  * Reloads the gtksourceview scheme color. Neccessary when the scheme color
891  * changes.
892  */
893 void
gtr_view_reload_scheme_color(GtrView * view)894 gtr_view_reload_scheme_color (GtrView * view)
895 {
896   GtkSourceBuffer *buf;
897   GtkSourceStyleScheme *scheme;
898   GtkSourceStyleSchemeManager *manager;
899   GtrViewPrivate *priv;
900   gchar *scheme_id;
901 
902   priv = gtr_view_get_instance_private (view);
903 
904   buf = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
905   manager = gtk_source_style_scheme_manager_get_default ();
906 
907   scheme_id = g_settings_get_string (priv->ui_settings,
908                                      GTR_SETTINGS_COLOR_SCHEME);
909   scheme = gtk_source_style_scheme_manager_get_scheme (manager, scheme_id);
910   g_free (scheme_id);
911 
912   gtk_source_buffer_set_style_scheme (buf, scheme);
913 }
914 
915 void
gtr_view_set_font(GtrView * view,char * font)916 gtr_view_set_font (GtrView *view, char *font)
917 {
918   PangoFontDescription *font_desc = NULL;
919   g_autofree char *str = NULL;
920   g_autofree char *css = NULL;
921   GtrViewPrivate *priv = gtr_view_get_instance_private (view);
922   g_autoptr (GtkWidget) button = gtk_font_button_new ();
923 
924   gtk_font_chooser_set_font (GTK_FONT_CHOOSER (button), font);
925   font_desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (button));
926   str = dzl_pango_font_description_to_css (font_desc);
927   css = g_strdup_printf ("textview { %s }", str ?: "");
928 
929   gtk_css_provider_load_from_data (priv->provider, css, -1, NULL);
930 
931   pango_font_description_free (font_desc);
932 }
933