[gtksourceview/wip/search] search: wrap around flag



commit a7b3118918aa6e13eaec58e4d2de5d034fe60a6e
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Sat Jun 29 16:01:25 2013 +0200

    search: wrap around flag

 gtksourceview/gtksourcebuffer.h |    6 ++-
 gtksourceview/gtksourcesearch.c |   96 +++++++++++++++++++++++++++++++++------
 tests/test-search-ui.c          |   25 ++++++++++
 tests/test-search-ui.ui         |   16 +++++++
 4 files changed, 128 insertions(+), 15 deletions(-)
---
diff --git a/gtksourceview/gtksourcebuffer.h b/gtksourceview/gtksourcebuffer.h
index 3cba252..41b2579 100644
--- a/gtksourceview/gtksourcebuffer.h
+++ b/gtksourceview/gtksourcebuffer.h
@@ -61,6 +61,9 @@ typedef enum
  * @GTK_SOURCE_SEARCH_CASE_SENSITIVE: Case sensitive search.
  * @GTK_SOURCE_SEARCH_AT_WORD_BOUNDARIES: A search match must start and end a
  * word. The match can span multiple words.
+ * @GTK_SOURCE_SEARCH_WRAP_AROUND: For a forward search, continue at the
+ * beginning of the buffer if no search occurrence is found at the end of the
+ * buffer. For a backward search, continue at the end of the buffer.
  *
  * Flags affecting how the search is done. Internally, GtkSourceView always
  * enables #GTK_TEXT_SEARCH_VISIBLE_ONLY and #GTK_TEXT_SEARCH_TEXT_ONLY.
@@ -70,7 +73,8 @@ typedef enum
 typedef enum
 {
        GTK_SOURCE_SEARCH_CASE_SENSITIVE        = 1 << 0,
-       GTK_SOURCE_SEARCH_AT_WORD_BOUNDARIES    = 1 << 1
+       GTK_SOURCE_SEARCH_AT_WORD_BOUNDARIES    = 1 << 1,
+       GTK_SOURCE_SEARCH_WRAP_AROUND           = 1 << 2
 } GtkSourceSearchFlags;
 
 struct _GtkSourceBuffer
diff --git a/gtksourceview/gtksourcesearch.c b/gtksourceview/gtksourcesearch.c
index 52ea71d..69cf757 100644
--- a/gtksourceview/gtksourcesearch.c
+++ b/gtksourceview/gtksourcesearch.c
@@ -143,6 +143,7 @@ struct _GtkSourceSearchPrivate
        GtkTextTag *found_tag;
 
        guint at_word_boundaries : 1;
+       guint wrap_around : 1;
 };
 
 typedef struct
@@ -151,6 +152,7 @@ typedef struct
        GtkTextIter match_start;
        GtkTextIter match_end;
        guint found : 1;
+       guint wrapped_around : 1;
 
        /* forward or backward */
        guint is_forward : 1;
@@ -460,19 +462,31 @@ forward_backward_data_free (ForwardBackwardData *data)
 static void
 smart_forward_search_async (GtkSourceSearch   *search,
                            const GtkTextIter *start_at,
-                           GTask             *task)
+                           GTask             *task,
+                           gboolean           wrapped_around)
 {
        GtkTextIter iter = *start_at;
        GtkTextIter limit;
        GtkTextRegion *region = NULL;
        ForwardBackwardData *task_data;
 
-       if (gtk_text_iter_is_end (start_at) ||
-           search->priv->text == NULL)
+       if (gtk_text_iter_is_end (start_at))
        {
+               if (search->priv->text != NULL &&
+                   !wrapped_around &&
+                   search->priv->wrap_around)
+               {
+                       GtkTextIter start_iter;
+                       gtk_text_buffer_get_start_iter (search->priv->buffer, &start_iter);
+
+                       smart_forward_search_async (search, &start_iter, task, TRUE);
+                       return;
+               }
+
                task_data = g_slice_new0 (ForwardBackwardData);
                task_data->found = FALSE;
                task_data->is_forward = TRUE;
+               task_data->wrapped_around = wrapped_around;
 
                g_task_return_pointer (task,
                                       task_data,
@@ -520,6 +534,7 @@ smart_forward_search_async (GtkSourceSearch   *search,
                        task_data->match_start = match_start;
                        task_data->match_end = match_end;
                        task_data->is_forward = TRUE;
+                       task_data->wrapped_around = wrapped_around;
 
                        g_task_return_pointer (task,
                                               task_data,
@@ -529,12 +544,13 @@ smart_forward_search_async (GtkSourceSearch   *search,
                        return;
                }
 
-               smart_forward_search_async (search, &limit, task);
+               smart_forward_search_async (search, &limit, task, wrapped_around);
                return;
        }
 
        task_data = g_slice_new0 (ForwardBackwardData);
        task_data->is_forward = TRUE;
+       task_data->wrapped_around = wrapped_around;
        task_data->start_at = gtk_text_buffer_create_mark (search->priv->buffer,
                                                           NULL,
                                                           start_at,
@@ -554,19 +570,31 @@ smart_forward_search_async (GtkSourceSearch   *search,
 static void
 smart_backward_search_async (GtkSourceSearch   *search,
                             const GtkTextIter *start_at,
-                            GTask             *task)
+                            GTask             *task,
+                            gboolean           wrapped_around)
 {
        GtkTextIter iter = *start_at;
        GtkTextIter limit;
        GtkTextRegion *region = NULL;
        ForwardBackwardData *task_data;
 
-       if (gtk_text_iter_is_start (start_at) ||
-           search->priv->text == NULL)
+       if (gtk_text_iter_is_start (start_at))
        {
+               if (search->priv->text != NULL &&
+                   !wrapped_around &&
+                   search->priv->wrap_around)
+               {
+                       GtkTextIter end_iter;
+                       gtk_text_buffer_get_end_iter (search->priv->buffer, &end_iter);
+
+                       smart_backward_search_async (search, &end_iter, task, TRUE);
+                       return;
+               }
+
                task_data = g_slice_new0 (ForwardBackwardData);
                task_data->found = FALSE;
                task_data->is_forward = FALSE;
+               task_data->wrapped_around = wrapped_around;
 
                g_task_return_pointer (task,
                                       task_data,
@@ -616,6 +644,7 @@ smart_backward_search_async (GtkSourceSearch   *search,
                        task_data->match_start = match_start;
                        task_data->match_end = match_end;
                        task_data->is_forward = FALSE;
+                       task_data->wrapped_around = wrapped_around;
 
                        g_task_return_pointer (task,
                                               task_data,
@@ -625,12 +654,13 @@ smart_backward_search_async (GtkSourceSearch   *search,
                        return;
                }
 
-               smart_backward_search_async (search, &limit, task);
+               smart_backward_search_async (search, &limit, task, wrapped_around);
                return;
        }
 
        task_data = g_slice_new0 (ForwardBackwardData);
        task_data->is_forward = FALSE;
+       task_data->wrapped_around = wrapped_around;
        task_data->start_at = gtk_text_buffer_create_mark (search->priv->buffer,
                                                           NULL,
                                                           start_at,
@@ -1066,11 +1096,17 @@ scan_task_region (GtkSourceSearch *search)
 
        if (task_data->is_forward)
        {
-               smart_forward_search_async (search, &start_at, task);
+               smart_forward_search_async (search,
+                                           &start_at,
+                                           task,
+                                           task_data->wrapped_around);
        }
        else
        {
-               smart_backward_search_async (search, &start_at, task);
+               smart_backward_search_async (search,
+                                            &start_at,
+                                            task,
+                                            task_data->wrapped_around);
        }
 }
 
@@ -1125,6 +1161,7 @@ install_idle_scan (GtkSourceSearch *search)
        }
 }
 
+/* Doesn't wrap around. */
 static gboolean
 smart_forward_search (GtkSourceSearch   *search,
                      const GtkTextIter *start_at,
@@ -1182,6 +1219,7 @@ smart_forward_search (GtkSourceSearch   *search,
        return smart_forward_search (search, start_at, match_start, match_end);
 }
 
+/* Doesn't wrap around. */
 static gboolean
 smart_backward_search (GtkSourceSearch   *search,
                       const GtkTextIter *start_at,
@@ -1538,6 +1576,7 @@ _gtk_source_search_set_flags (GtkSourceSearch      *search,
        }
 
        search->priv->at_word_boundaries = (flags & GTK_SOURCE_SEARCH_AT_WORD_BOUNDARIES) != 0;
+       search->priv->wrap_around = (flags & GTK_SOURCE_SEARCH_WRAP_AROUND) != 0;
 
        update (search);
 }
@@ -1559,6 +1598,11 @@ _gtk_source_search_get_flags (GtkSourceSearch *search)
                source_flags |= GTK_SOURCE_SEARCH_AT_WORD_BOUNDARIES;
        }
 
+       if (search->priv->wrap_around)
+       {
+               source_flags |= GTK_SOURCE_SEARCH_WRAP_AROUND;
+       }
+
        return source_flags;
 }
 
@@ -1630,9 +1674,21 @@ _gtk_source_search_forward (GtkSourceSearch   *search,
                            GtkTextIter       *match_start,
                            GtkTextIter       *match_end)
 {
+       gboolean found;
+
        g_return_val_if_fail (GTK_SOURCE_IS_SEARCH (search), FALSE);
 
-       return smart_forward_search (search, iter, match_start, match_end);
+       found = smart_forward_search (search, iter, match_start, match_end);
+
+       if (!found && search->priv->wrap_around)
+       {
+               GtkTextIter start_iter;
+               gtk_text_buffer_get_start_iter (search->priv->buffer, &start_iter);
+
+               found = smart_forward_search (search, &start_iter, match_start, match_end);
+       }
+
+       return found;
 }
 
 void
@@ -1648,7 +1704,7 @@ _gtk_source_search_forward_async (GtkSourceSearch     *search,
 
        task = g_task_new (search->priv->buffer, cancellable, callback, user_data);
 
-       smart_forward_search_async (search, iter, task);
+       smart_forward_search_async (search, iter, task, FALSE);
 }
 
 gboolean
@@ -1696,9 +1752,21 @@ _gtk_source_search_backward (GtkSourceSearch   *search,
                             GtkTextIter       *match_start,
                             GtkTextIter       *match_end)
 {
+       gboolean found;
+
        g_return_val_if_fail (GTK_SOURCE_IS_SEARCH (search), FALSE);
 
-       return smart_backward_search (search, iter, match_start, match_end);
+       found = smart_backward_search (search, iter, match_start, match_end);
+
+       if (!found && search->priv->wrap_around)
+       {
+               GtkTextIter end_iter;
+               gtk_text_buffer_get_end_iter (search->priv->buffer, &end_iter);
+
+               found = smart_backward_search (search, &end_iter, match_start, match_end);
+       }
+
+       return found;
 }
 
 void
@@ -1714,7 +1782,7 @@ _gtk_source_search_backward_async (GtkSourceSearch     *search,
 
        task = g_task_new (search->priv->buffer, cancellable, callback, user_data);
 
-       smart_backward_search_async (search, iter, task);
+       smart_backward_search_async (search, iter, task, FALSE);
 }
 
 gboolean
diff --git a/tests/test-search-ui.c b/tests/test-search-ui.c
index ad4c200..d005fc1 100644
--- a/tests/test-search-ui.c
+++ b/tests/test-search-ui.c
@@ -110,6 +110,24 @@ on_at_word_boundaries_toggled_cb (GtkToggleButton *button,
 }
 
 static void
+on_wrap_around_toggled_cb (GtkToggleButton *button,
+                          GtkSourceBuffer *buffer)
+{
+       GtkSourceSearchFlags flags = gtk_source_buffer_get_search_flags (buffer);
+
+       if (gtk_toggle_button_get_active (button))
+       {
+               flags |= GTK_SOURCE_SEARCH_WRAP_AROUND;
+       }
+       else
+       {
+               flags &= ~GTK_SOURCE_SEARCH_WRAP_AROUND;
+       }
+
+       gtk_source_buffer_set_search_flags (buffer, flags);
+}
+
+static void
 select_search_occurrence (GtkTextView       *view,
                          const GtkTextIter *match_start,
                          const GtkTextIter *match_end)
@@ -202,6 +220,7 @@ create_window (void)
        GtkLabel *label_occurrences_count;
        GtkCheckButton *match_case;
        GtkCheckButton *at_word_boundaries;
+       GtkCheckButton *wrap_around;
        GtkButton *button_previous;
        GtkButton *button_next;
        PangoFontDescription *font;
@@ -223,6 +242,7 @@ create_window (void)
        label_occurrences_count = GTK_LABEL (gtk_builder_get_object (builder, "label_occurrences_count"));
        match_case = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, "checkbutton_match_case"));
        at_word_boundaries = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, 
"checkbutton_at_word_boundaries"));
+       wrap_around = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, "checkbutton_wrap_around"));
        button_previous = GTK_BUTTON (gtk_builder_get_object (builder, "button_previous"));
        button_next = GTK_BUTTON (gtk_builder_get_object (builder, "button_next"));
 
@@ -268,6 +288,11 @@ create_window (void)
                          G_CALLBACK (on_at_word_boundaries_toggled_cb),
                          source_buffer);
 
+       g_signal_connect (wrap_around,
+                         "toggled",
+                         G_CALLBACK (on_wrap_around_toggled_cb),
+                         source_buffer);
+
        g_signal_connect (button_previous,
                          "clicked",
                          G_CALLBACK (on_button_previous_clicked_cb),
diff --git a/tests/test-search-ui.ui b/tests/test-search-ui.ui
index 5de2949..5bfa595 100644
--- a/tests/test-search-ui.ui
+++ b/tests/test-search-ui.ui
@@ -174,6 +174,22 @@
                 <property name="height">1</property>
               </packing>
             </child>
+            <child>
+              <object class="GtkCheckButton" id="checkbutton_wrap_around">
+                <property name="label">Wrap around</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">2</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
           </object>
           <packing>
             <property name="left_attach">0</property>


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