anjuta r3845 - in trunk: . plugins/file-loader plugins/search



Author: jhs
Date: Fri Apr 11 00:19:38 2008
New Revision: 3845
URL: http://svn.gnome.org/viewvc/anjuta?rev=3845&view=rev

Log:
2008-04-11  Johannes Schmid  <jhs gnome org>

	Patch from Ignacio Casal Quinteiro:
	* plugins/file-loader/Makefile.am:
	* plugins/file-loader/anjuta-recent-chooser-menu.c
	(gtk_recent_chooser_iface_init),
	(_anjuta_recent_chooser_install_properties),
	(sort_recent_items_mru), (get_is_recent_filtered),
	(_gtk_recent_chooser_get_items),
	(anjuta_recent_chooser_menu_class_init),
	(anjuta_recent_chooser_menu_init),
	(anjuta_recent_chooser_menu_finalize),
	(anjuta_recent_chooser_menu_dispose),
	(anjuta_recent_chooser_menu_constructor),
	(anjuta_recent_chooser_menu_set_property),
	(anjuta_recent_chooser_menu_get_property),
	(anjuta_recent_chooser_menu_set_current_uri),
	(anjuta_recent_chooser_menu_get_current_uri),
	(anjuta_recent_chooser_menu_select_uri),
	(anjuta_recent_chooser_menu_unselect_uri),
	(anjuta_recent_chooser_menu_select_all),
	(anjuta_recent_chooser_menu_unselect_all),
	(anjuta_recent_chooser_menu_set_sort_func),
	(chooser_set_sort_type), (anjuta_recent_chooser_menu_get_items),
	(anjuta_recent_chooser_menu_get_recent_manager),
	(anjuta_recent_chooser_menu_add_filter),
	(anjuta_recent_chooser_menu_remove_filter),
	(anjuta_recent_chooser_menu_list_filters),
	(anjuta_recent_chooser_menu_set_current_filter),
	(escape_underscores), (anjuta_recent_chooser_menu_add_tip),
	(anjuta_recent_chooser_menu_create_item),
	(anjuta_recent_chooser_menu_insert_item),
	(anjuta_recent_chooser_menu_dispose_items), (idle_populate_func),
	(idle_populate_clean_up), (anjuta_recent_chooser_menu_populate),
	(item_activate_cb), (manager_changed_cb), (set_recent_manager),
	(get_icon_size_for_widget), (foreach_set_shot_tips),
	(anjuta_recent_chooser_menu_set_show_tips),
	(anjuta_recent_chooser_menu_new),
	(anjuta_recent_chooser_menu_new_for_manager):
	* plugins/file-loader/anjuta-recent-chooser-menu.h:
	* plugins/file-loader/plugin.c (setup_recent_chooser_menu),
	(activate_plugin), (dispose):
	
	Add separator to recent menu (#526932)

	* plugins/search/Makefile.am:
	* plugins/search/anjuta-search.glade:
	* plugins/search/anjuta-search.ui:
	* plugins/search/plugin.c (on_find1_activate),
	(on_find_and_replace1_activate), (on_find_in_files1_activate),
	(on_findnext1_activate), (on_findprevious1_activate),
	(on_search_again_activate), (on_find_usage), (activate_plugin),
	(deactivate_plugin), (dispose), (search_plugin_class_init):
	* plugins/search/plugin.h:
	* plugins/search/search-replace.c (anj_sr_execute),
	(anj_sr_write_match_message), (on_message_clicked),
	(anj_sr_set_search_string), (anj_sr_select_nearest),
	(anj_sr_select_next), (anj_sr_select_previous),
	(anj_sr_list_all_uses), (anj_sr_activate), (anj_sr_repeat),
	(anj_sr_is_idle), (anj_sr_set_popdown_strings),
	(anj_sr_set_popdown_map), (anj_sr_activate_combo_item),
	(anj_sr_activate_combo_id_item), (anj_sr_set_action),
	(anj_sr_set_target), (anj_sr_set_direction),
	(anj_sr_get_direction), (anj_sr_get_combo_active_value),
	(anj_sr_get_combo_id_active_value),
	(anj_sr_conform_direction_change), (anj_sr_populate_value),
	(anj_sr_reset_flags), (anj_sr_reset_replace_buttons),
	(anj_sr_end_alert), (anj_sr_max_results_alert),
	(anj_sr_total_results_alert), (anj_sr_show_replace),
	(anj_sr_modify_button), (anj_sr_populate_data),
	(anj_sr_show_replace_button), (anj_sr_enable_replace_button),
	(anj_sr_get_default_uidata), (anj_sr_get_best_uidata),
	(anj_sr_get_current_uidata), (anj_sr_set_dialog_searchdata),
	(anj_sr_translate_dialog_strings), (anj_sr_create_dialog),
	(anj_sr_present_dialog), (anj_sr_destroy_ui_data),
	(anj_sr_find_in_list), (anj_sr_trim_list),
	(anj_sr_update_search_combos), (anj_sr_update_replace_combos),
	(anj_sr_populate_dialog), (anj_sr_interrupt_nicely),
	(on_search_dialog_delete_event), (on_search_dialog_key_press),
	(anj_sr_disconnect_set_toggle_connect),
	(on_search_match_whole_word_toggled),
	(on_search_match_whole_line_toggled),
	(on_search_match_word_start_toggled), (on_search_regex_toggled),
	(on_search_actions_no_limit_toggled), (anj_sr_revert_button),
	(on_search_direction_changed), (on_search_action_changed),
	(on_search_target_changed), (on_search_expression_changed),
	(on_search_button_close_clicked), (on_search_button_stop_clicked),
	(on_search_button_start_clicked),
	(on_search_button_replace_clicked),
	(on_search_expression_activate):
	* plugins/search/search-replace.h:
	* plugins/search/search-replace_backend.c (regex_backref),
	(pcre_info_free), (pcre_info_new), (match_substr_free),
	(match_info_free_subs), (editor_new_from_file_buffer),
	(file_buffer_new_from_te), (file_buffer_new_from_uri),
	(file_buffer_free), (file_buffer_get_byte_offset),
	(file_buffer_get_char_offset), (file_buffer_get_char_offset_pair),
	(file_buffer_find_lines), (file_buffer_freshen_lines),
	(file_buffer_freshen_lines_from_pos), (file_buffer_line_for_pos),
	(file_buffer_get_linetext_for_line), (save_file_buffer),
	(replace_in_local_buffer), (get_search_files_list),
	(get_project_files_list), (isawordchar), (extra_match),
	(get_next_match), (create_search_entries), (clear_search_entries),
	(search_get_default_data), (search_replace_data_new),
	(clear_search_replace_instance), (search_replace_data_destroy),
	(search_replace_init):
	* plugins/search/search-replace_backend.h:
	* plugins/search/search_preferences.c (removed):
	* plugins/search/search_preferences.h (removed):
	
	Merged the UI changes from bug #511688 and simplified the search dialog

Added:
   trunk/plugins/file-loader/anjuta-recent-chooser-menu.c
   trunk/plugins/file-loader/anjuta-recent-chooser-menu.h
Removed:
   trunk/plugins/search/search_preferences.c
   trunk/plugins/search/search_preferences.h
Modified:
   trunk/ChangeLog
   trunk/plugins/file-loader/Makefile.am
   trunk/plugins/file-loader/plugin.c
   trunk/plugins/search/Makefile.am
   trunk/plugins/search/anjuta-search.glade
   trunk/plugins/search/anjuta-search.ui
   trunk/plugins/search/plugin.c
   trunk/plugins/search/plugin.h
   trunk/plugins/search/search-replace.c
   trunk/plugins/search/search-replace.h
   trunk/plugins/search/search-replace_backend.c
   trunk/plugins/search/search-replace_backend.h

Modified: trunk/plugins/file-loader/Makefile.am
==============================================================================
--- trunk/plugins/file-loader/Makefile.am	(original)
+++ trunk/plugins/file-loader/Makefile.am	Fri Apr 11 00:19:38 2008
@@ -32,7 +32,9 @@
 	plugin.c \
 	plugin.h \
 	dnd.c \
-	dnd.h
+	dnd.h \
+	anjuta-recent-chooser-menu.c \
+	anjuta-recent-chooser-menu.h
 
 libanjuta_loader_la_LDFLAGS = $(ANJUTA_PLUGIN_LDFLAGS)
 

Added: trunk/plugins/file-loader/anjuta-recent-chooser-menu.c
==============================================================================
--- (empty file)
+++ trunk/plugins/file-loader/anjuta-recent-chooser-menu.c	Fri Apr 11 00:19:38 2008
@@ -0,0 +1,1411 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentchoosermenu.c - Recently used items menu widget
+ * Copyright (C) 2005, Emmanuele Bassi
+ *		 2008, Ignacio Casal Quinteiro
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gdk/gdkscreen.h>
+
+#include "anjuta-recent-chooser-menu.h"
+
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
+struct _AnjutaRecentChooserMenuPrivate
+{
+  /* the recent manager object */
+  GtkRecentManager *manager;
+  
+  /* size of the icons of the menu items */  
+  gint icon_size;
+
+  /* max size of the menu item label */
+  gint label_width;
+
+  gint first_recent_item_pos;
+  GtkWidget *placeholder;
+
+  /* RecentChooser properties */
+  gint limit;  
+  guint show_private : 1;
+  guint show_not_found : 1;
+  guint show_tips : 1;
+  guint show_icons : 1;
+  guint local_only : 1;
+  
+  guint show_numbers : 1;
+  
+  GtkRecentSortType sort_type;
+  GtkRecentSortFunc sort_func;
+  gpointer sort_data;
+  GDestroyNotify sort_data_destroy;
+  
+  GSList *filters;
+  GtkRecentFilter *current_filter;
+ 
+  guint local_manager : 1;
+  gulong manager_changed_id;
+
+  gulong populate_id;
+};
+
+typedef enum {
+  GTK_RECENT_CHOOSER_PROP_FIRST           = 0x3000,
+  GTK_RECENT_CHOOSER_PROP_RECENT_MANAGER,
+  GTK_RECENT_CHOOSER_PROP_SHOW_PRIVATE,
+  GTK_RECENT_CHOOSER_PROP_SHOW_NOT_FOUND,
+  GTK_RECENT_CHOOSER_PROP_SHOW_TIPS,
+  GTK_RECENT_CHOOSER_PROP_SHOW_ICONS,
+  GTK_RECENT_CHOOSER_PROP_SELECT_MULTIPLE,
+  GTK_RECENT_CHOOSER_PROP_LIMIT,
+  GTK_RECENT_CHOOSER_PROP_LOCAL_ONLY,
+  GTK_RECENT_CHOOSER_PROP_SORT_TYPE,
+  GTK_RECENT_CHOOSER_PROP_FILTER,
+  GTK_RECENT_CHOOSER_PROP_LAST
+} GtkRecentChooserProp;
+
+
+#define FALLBACK_ICON_SIZE 	32
+#define FALLBACK_ITEM_LIMIT 	10
+#define DEFAULT_LABEL_WIDTH     30
+
+#define ANJUTA_RECENT_CHOOSER_MENU_GET_PRIVATE(obj)	(G_TYPE_INSTANCE_GET_PRIVATE ((obj), ANJUTA_TYPE_RECENT_CHOOSER_MENU, AnjutaRecentChooserMenuPrivate))
+
+static void     anjuta_recent_chooser_menu_finalize    (GObject                   *object);
+static void     anjuta_recent_chooser_menu_dispose     (GObject                   *object);
+static GObject *anjuta_recent_chooser_menu_constructor (GType                      type,
+						     guint                      n_construct_properties,
+						     GObjectConstructParam     *construct_params);
+						     
+static void
+anjuta_recent_chooser_menu_set_property (GObject      *object,
+				      guint         prop_id,
+				      const GValue *value,
+				      GParamSpec   *pspec);
+				      
+static void
+anjuta_recent_chooser_menu_get_property (GObject    *object,
+				      guint       prop_id,
+				      GValue     *value,
+				      GParamSpec *pspec);
+
+static void gtk_recent_chooser_iface_init      (GtkRecentChooserIface     *iface);
+
+static gboolean          anjuta_recent_chooser_menu_set_current_uri    (GtkRecentChooser  *chooser,
+							             const gchar       *uri,
+							             GError           **error);
+static gchar *           anjuta_recent_chooser_menu_get_current_uri    (GtkRecentChooser  *chooser);
+static gboolean          anjuta_recent_chooser_menu_select_uri         (GtkRecentChooser  *chooser,
+								     const gchar       *uri,
+								     GError           **error);
+static void              anjuta_recent_chooser_menu_unselect_uri       (GtkRecentChooser  *chooser,
+								     const gchar       *uri);
+static void              anjuta_recent_chooser_menu_select_all         (GtkRecentChooser  *chooser);
+static void              anjuta_recent_chooser_menu_unselect_all       (GtkRecentChooser  *chooser);
+static GList *           anjuta_recent_chooser_menu_get_items          (GtkRecentChooser  *chooser);
+static GtkRecentManager *anjuta_recent_chooser_menu_get_recent_manager (GtkRecentChooser  *chooser);
+static void              anjuta_recent_chooser_menu_set_sort_func      (GtkRecentChooser  *chooser,
+								     GtkRecentSortFunc  sort_func,
+								     gpointer           sort_data,
+								     GDestroyNotify     data_destroy);
+static void              anjuta_recent_chooser_menu_add_filter         (GtkRecentChooser  *chooser,
+								     GtkRecentFilter   *filter);
+static void              anjuta_recent_chooser_menu_remove_filter      (GtkRecentChooser  *chooser,
+								     GtkRecentFilter   *filter);
+static GSList *          anjuta_recent_chooser_menu_list_filters       (GtkRecentChooser  *chooser);
+static void              anjuta_recent_chooser_menu_set_current_filter (AnjutaRecentChooserMenu *menu,
+								     GtkRecentFilter      *filter);
+
+static void              anjuta_recent_chooser_menu_populate           (AnjutaRecentChooserMenu *menu);
+static void              anjuta_recent_chooser_menu_set_show_tips      (AnjutaRecentChooserMenu *menu,
+								     gboolean              show_tips);
+
+static void     set_recent_manager (AnjutaRecentChooserMenu *menu,
+				    GtkRecentManager     *manager);
+
+static void     chooser_set_sort_type (AnjutaRecentChooserMenu *menu,
+				       GtkRecentSortType     sort_type);
+
+static gint     get_icon_size_for_widget (GtkWidget *widget);
+
+static void     item_activate_cb   (GtkWidget        *widget,
+			            gpointer          user_data);
+static void     manager_changed_cb (GtkRecentManager *manager,
+				    gpointer          user_data);
+
+G_DEFINE_TYPE_WITH_CODE (AnjutaRecentChooserMenu,
+			 anjuta_recent_chooser_menu,
+			 GTK_TYPE_MENU,
+			 G_IMPLEMENT_INTERFACE (GTK_TYPE_RECENT_CHOOSER,
+				 		gtk_recent_chooser_iface_init))
+
+
+static void
+gtk_recent_chooser_iface_init (GtkRecentChooserIface *iface)
+{
+  iface->set_current_uri = anjuta_recent_chooser_menu_set_current_uri;
+  iface->get_current_uri = anjuta_recent_chooser_menu_get_current_uri;
+  iface->select_uri = anjuta_recent_chooser_menu_select_uri;
+  iface->unselect_uri = anjuta_recent_chooser_menu_unselect_uri;
+  iface->select_all = anjuta_recent_chooser_menu_select_all;
+  iface->unselect_all = anjuta_recent_chooser_menu_unselect_all;
+  iface->get_items = anjuta_recent_chooser_menu_get_items;
+  iface->get_recent_manager = anjuta_recent_chooser_menu_get_recent_manager;
+  iface->set_sort_func = anjuta_recent_chooser_menu_set_sort_func;
+  iface->add_filter = anjuta_recent_chooser_menu_add_filter;
+  iface->remove_filter = anjuta_recent_chooser_menu_remove_filter;
+  iface->list_filters = anjuta_recent_chooser_menu_list_filters;
+}
+
+static void
+_anjuta_recent_chooser_install_properties (GObjectClass *klass)
+{
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_RECENT_MANAGER,
+  				    "recent-manager");  				    
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_SHOW_PRIVATE,
+  				    "show-private");
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_SHOW_TIPS,
+  				    "show-tips");
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_SHOW_ICONS,
+  				    "show-icons");
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_SHOW_NOT_FOUND,
+  				    "show-not-found");
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_SELECT_MULTIPLE,
+  				    "select-multiple");
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_LIMIT,
+  				    "limit");
+  g_object_class_override_property (klass,
+		  		    GTK_RECENT_CHOOSER_PROP_LOCAL_ONLY,
+				    "local-only");
+  g_object_class_override_property (klass,
+		  		    GTK_RECENT_CHOOSER_PROP_SORT_TYPE,
+				    "sort-type");
+  g_object_class_override_property (klass,
+  				    GTK_RECENT_CHOOSER_PROP_FILTER,
+  				    "filter");
+}
+
+static gint
+sort_recent_items_mru (GtkRecentInfo *a,
+		       GtkRecentInfo *b,
+		       gpointer       unused)
+{
+  g_assert (a != NULL && b != NULL);
+  
+  return gtk_recent_info_get_modified (b) - gtk_recent_info_get_modified (a);
+}
+
+static gboolean
+get_is_recent_filtered (GtkRecentFilter *filter,
+			GtkRecentInfo   *info)
+{
+  GtkRecentFilterInfo filter_info;
+  GtkRecentFilterFlags needed;
+  gboolean retval;
+
+  g_assert (info != NULL);
+  
+  needed = gtk_recent_filter_get_needed (filter);
+  
+  filter_info.contains = GTK_RECENT_FILTER_URI | GTK_RECENT_FILTER_MIME_TYPE;
+  
+  filter_info.uri = gtk_recent_info_get_uri (info);
+  filter_info.mime_type = gtk_recent_info_get_mime_type (info);
+  
+  if (needed & GTK_RECENT_FILTER_DISPLAY_NAME)
+    {
+      filter_info.display_name = gtk_recent_info_get_display_name (info);
+      filter_info.contains |= GTK_RECENT_FILTER_DISPLAY_NAME;
+    }
+  else
+    filter_info.uri = NULL;
+  
+  if (needed & GTK_RECENT_FILTER_APPLICATION)
+    {
+      filter_info.applications = (const gchar **) gtk_recent_info_get_applications (info, NULL);
+      filter_info.contains |= GTK_RECENT_FILTER_APPLICATION;
+    }
+  else
+    filter_info.applications = NULL;
+
+  if (needed & GTK_RECENT_FILTER_GROUP)
+    {
+      filter_info.groups = (const gchar **) gtk_recent_info_get_groups (info, NULL);
+      filter_info.contains |= GTK_RECENT_FILTER_GROUP;
+    }
+  else
+    filter_info.groups = NULL;
+
+  if (needed & GTK_RECENT_FILTER_AGE)
+    {
+      filter_info.age = gtk_recent_info_get_age (info);
+      filter_info.contains |= GTK_RECENT_FILTER_AGE;
+    }
+  else
+    filter_info.age = -1;
+  
+  retval = gtk_recent_filter_filter (filter, &filter_info);
+  
+  /* these we own */
+  if (filter_info.applications)
+    g_strfreev ((gchar **) filter_info.applications);
+  if (filter_info.groups)
+    g_strfreev ((gchar **) filter_info.groups);
+  
+  return !retval;
+}
+
+static GList *
+_gtk_recent_chooser_get_items (GtkRecentChooser  *chooser,
+                               GtkRecentFilter   *filter,
+                               GtkRecentManager  *manager,
+                               gpointer           sort_data)
+{
+  gint limit;
+  GtkRecentSortType sort_type;
+  GList *items;
+  GCompareFunc compare_func;
+  gint length;
+
+  g_return_val_if_fail (GTK_IS_RECENT_CHOOSER (chooser), NULL);
+
+  if (!manager)
+    return NULL;
+
+  items = gtk_recent_manager_get_items (manager);
+  if (!items)
+    return NULL;
+
+  limit = gtk_recent_chooser_get_limit (chooser);
+  if (limit == 0)
+    return NULL;
+
+  if (filter)
+    {
+      GList *filter_items, *l;
+      gboolean local_only = FALSE;
+      gboolean show_private = FALSE;
+      gboolean show_not_found = FALSE;
+
+      g_object_get (G_OBJECT (chooser),
+                    "local-only", &local_only,
+                    "show-private", &show_private,
+                    "show-not-found", &show_not_found,
+                    NULL);
+
+      filter_items = NULL;
+      for (l = items; l != NULL; l = l->next)
+        {
+          GtkRecentInfo *info = l->data;
+          gboolean remove_item = FALSE;
+
+          if (get_is_recent_filtered (filter, info))
+            remove_item = TRUE;
+          
+          if (local_only && !gtk_recent_info_is_local (info))
+            remove_item = TRUE;
+
+          if (!show_private && gtk_recent_info_get_private_hint (info))
+            remove_item = TRUE;
+
+          if (!show_not_found && !gtk_recent_info_exists (info))
+            remove_item = TRUE;
+          
+          if (!remove_item)
+            filter_items = g_list_prepend (filter_items, info);
+          else
+            gtk_recent_info_unref (info);
+        }
+      
+      g_list_free (items);
+      items = filter_items;
+    }
+
+  if (!items)
+    return NULL;
+
+  sort_type = gtk_recent_chooser_get_sort_type (chooser);
+  switch (sort_type)
+    {
+    case GTK_RECENT_SORT_NONE:
+      compare_func = NULL;
+      break;
+    case GTK_RECENT_SORT_MRU:
+      compare_func = (GCompareFunc) sort_recent_items_mru;
+      break;
+    case GTK_RECENT_SORT_LRU:
+      compare_func = NULL;
+      break;
+    case GTK_RECENT_SORT_CUSTOM:
+      compare_func = NULL;
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+
+  if (compare_func)
+    {
+
+      items = g_list_sort (items, compare_func);
+    }
+  
+  length = g_list_length (items);
+  if ((limit != -1) && (length > limit))
+    {
+      GList *clamp, *l;
+      
+      clamp = g_list_nth (items, limit - 1);
+      if (!clamp)
+        return items;
+      
+      l = clamp->next;
+      clamp->next = NULL;
+    
+      g_list_foreach (l, (GFunc) gtk_recent_info_unref, NULL);
+      g_list_free (l);
+    }
+
+  return items;
+}
+
+
+static void
+anjuta_recent_chooser_menu_class_init (AnjutaRecentChooserMenuClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->constructor = anjuta_recent_chooser_menu_constructor;
+  gobject_class->dispose = anjuta_recent_chooser_menu_dispose;
+  gobject_class->finalize = anjuta_recent_chooser_menu_finalize;
+  gobject_class->set_property = anjuta_recent_chooser_menu_set_property;
+  gobject_class->get_property = anjuta_recent_chooser_menu_get_property;
+  
+  _anjuta_recent_chooser_install_properties (gobject_class);
+  
+  g_type_class_add_private (klass, sizeof (AnjutaRecentChooserMenuPrivate));
+}
+
+static void
+anjuta_recent_chooser_menu_init (AnjutaRecentChooserMenu *menu)
+{
+  AnjutaRecentChooserMenuPrivate *priv;
+  
+  priv = ANJUTA_RECENT_CHOOSER_MENU_GET_PRIVATE (menu);
+  
+  menu->priv = priv;
+  
+  priv->show_icons= TRUE;
+  priv->show_numbers = FALSE;
+  priv->show_tips = FALSE;
+  priv->show_not_found = TRUE;
+  priv->show_private = FALSE;
+  priv->local_only = TRUE;
+  
+  priv->limit = FALLBACK_ITEM_LIMIT;
+  priv->sort_type = GTK_RECENT_SORT_NONE;
+  priv->icon_size = FALLBACK_ICON_SIZE;
+  priv->label_width = DEFAULT_LABEL_WIDTH;
+  
+  priv->first_recent_item_pos = -1;
+  priv->placeholder = NULL;
+
+  priv->current_filter = NULL;
+}
+
+static void
+anjuta_recent_chooser_menu_finalize (GObject *object)
+{
+  AnjutaRecentChooserMenu *menu = ANJUTA_RECENT_CHOOSER_MENU (object);
+  AnjutaRecentChooserMenuPrivate *priv = menu->priv;
+  
+  priv->manager = NULL;
+  
+  if (priv->sort_data_destroy)
+    {
+      priv->sort_data_destroy (priv->sort_data);
+      priv->sort_data_destroy = NULL;
+    }
+
+  priv->sort_data = NULL;
+  priv->sort_func = NULL;
+  
+  G_OBJECT_CLASS (anjuta_recent_chooser_menu_parent_class)->finalize (object);
+}
+
+static void
+anjuta_recent_chooser_menu_dispose (GObject *object)
+{
+  AnjutaRecentChooserMenu *menu = ANJUTA_RECENT_CHOOSER_MENU (object);
+  AnjutaRecentChooserMenuPrivate *priv = menu->priv;
+
+  if (priv->manager_changed_id)
+    {
+      if (priv->manager)
+        g_signal_handler_disconnect (priv->manager, priv->manager_changed_id);
+
+      priv->manager_changed_id = 0;
+    }
+  
+  if (priv->populate_id)
+    {
+      g_source_remove (priv->populate_id);
+      priv->populate_id = 0;
+    }
+
+  if (priv->current_filter)
+    {
+      g_object_unref (priv->current_filter);
+      priv->current_filter = NULL;
+    }
+  
+  G_OBJECT_CLASS (anjuta_recent_chooser_menu_parent_class)->dispose (object);
+}
+
+static GObject *
+anjuta_recent_chooser_menu_constructor (GType                  type,
+				     guint                  n_params,
+				     GObjectConstructParam *params)
+{
+  AnjutaRecentChooserMenu *menu;
+  AnjutaRecentChooserMenuPrivate *priv;
+  GObjectClass *parent_class;
+  GObject *object;
+  
+  parent_class = G_OBJECT_CLASS (anjuta_recent_chooser_menu_parent_class);
+  object = parent_class->constructor (type, n_params, params);
+  menu = ANJUTA_RECENT_CHOOSER_MENU (object);
+  priv = menu->priv;
+  
+  g_assert (priv->manager);
+
+  /* we create a placeholder menuitem, to be used in case
+   * the menu is empty. this placeholder will stay around
+   * for the entire lifetime of the menu, and we just hide it
+   * when it's not used. we have to do this, and do it here,
+   * because we need a marker for the beginning of the recent
+   * items list, so that we can insert the new items at the
+   * right place when idly populating the menu in case the
+   * user appended or prepended custom menu items to the
+   * recent chooser menu widget.
+   */
+  priv->placeholder = gtk_menu_item_new_with_label (_("No items found"));
+  gtk_widget_set_sensitive (priv->placeholder, FALSE);
+  g_object_set_data (G_OBJECT (priv->placeholder),
+                     "gtk-recent-menu-placeholder",
+                     GINT_TO_POINTER (TRUE));
+
+  gtk_menu_shell_insert (GTK_MENU_SHELL (menu), priv->placeholder, 0);
+  gtk_widget_set_no_show_all (priv->placeholder, TRUE);
+  gtk_widget_show (priv->placeholder);
+
+  /* (re)populate the menu */
+  anjuta_recent_chooser_menu_populate (menu);
+
+  return object;
+}
+
+static void
+anjuta_recent_chooser_menu_set_property (GObject      *object,
+				      guint         prop_id,
+				      const GValue *value,
+				      GParamSpec   *pspec)
+{
+  AnjutaRecentChooserMenu *menu = ANJUTA_RECENT_CHOOSER_MENU (object);
+  AnjutaRecentChooserMenuPrivate *priv = menu->priv;
+  
+  switch (prop_id)
+    {
+    case GTK_RECENT_CHOOSER_PROP_RECENT_MANAGER:
+      set_recent_manager (menu, g_value_get_object (value));
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_PRIVATE:
+      priv->show_private = g_value_get_boolean (value);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_NOT_FOUND:
+      priv->show_not_found = g_value_get_boolean (value);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_TIPS:
+      anjuta_recent_chooser_menu_set_show_tips (menu, g_value_get_boolean (value));
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_ICONS:
+      priv->show_icons = g_value_get_boolean (value);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SELECT_MULTIPLE:
+      g_warning ("%s: Choosers of type `%s' do not support selecting multiple items.",
+                 G_STRFUNC,
+                 G_OBJECT_TYPE_NAME (object));
+      break;
+    case GTK_RECENT_CHOOSER_PROP_LOCAL_ONLY:
+      priv->local_only = g_value_get_boolean (value);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_LIMIT:
+      priv->limit = g_value_get_int (value);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SORT_TYPE:
+      chooser_set_sort_type (menu, g_value_get_enum (value));
+      break;
+    case GTK_RECENT_CHOOSER_PROP_FILTER:
+      anjuta_recent_chooser_menu_set_current_filter (menu, g_value_get_object (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+anjuta_recent_chooser_menu_get_property (GObject    *object,
+				      guint       prop_id,
+				      GValue     *value,
+				      GParamSpec *pspec)
+{
+  AnjutaRecentChooserMenu *menu = ANJUTA_RECENT_CHOOSER_MENU (object);
+  AnjutaRecentChooserMenuPrivate *priv = menu->priv;
+  
+  switch (prop_id)
+    {
+    case GTK_RECENT_CHOOSER_PROP_SHOW_TIPS:
+      g_value_set_boolean (value, priv->show_tips);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_LIMIT:
+      g_value_set_int (value, priv->limit);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_LOCAL_ONLY:
+      g_value_set_boolean (value, priv->local_only);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SORT_TYPE:
+      g_value_set_enum (value, priv->sort_type);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_PRIVATE:
+      g_value_set_boolean (value, priv->show_private);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_NOT_FOUND:
+      g_value_set_boolean (value, priv->show_not_found);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SHOW_ICONS:
+      g_value_set_boolean (value, priv->show_icons);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_SELECT_MULTIPLE:
+      g_value_set_boolean (value, FALSE);
+      break;
+    case GTK_RECENT_CHOOSER_PROP_FILTER:
+      g_value_set_object (value, priv->current_filter);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static gboolean
+anjuta_recent_chooser_menu_set_current_uri (GtkRecentChooser  *chooser,
+					 const gchar       *uri,
+					 GError           **error)
+{
+  AnjutaRecentChooserMenu *menu = ANJUTA_RECENT_CHOOSER_MENU (chooser);
+  GList *children, *l;
+  GtkWidget *menu_item = NULL;
+  gboolean found = FALSE;
+  
+  children = gtk_container_get_children (GTK_CONTAINER (menu));
+  
+  for (l = children; l != NULL; l = l->next)
+    {
+      GtkRecentInfo *info;
+      
+      menu_item = GTK_WIDGET (l->data);
+      
+      info = g_object_get_data (G_OBJECT (menu_item), "gtk-recent-info");
+      if (!info)
+        continue;
+      
+      if (strcmp (uri, gtk_recent_info_get_uri (info)) == 0)
+        {
+          gtk_menu_shell_activate_item (GTK_MENU_SHELL (menu),
+	                                menu_item,
+					TRUE);
+	  found = TRUE;
+
+	  break;
+	}
+    }
+
+  g_list_free (children);
+  
+  if (!found)  
+    {
+      g_set_error (error, GTK_RECENT_CHOOSER_ERROR,
+      		   GTK_RECENT_CHOOSER_ERROR_NOT_FOUND,
+      		   _("No recently used resource found with URI `%s'"),
+      		   uri);
+    }
+  
+  return found;
+}
+
+static gchar *
+anjuta_recent_chooser_menu_get_current_uri (GtkRecentChooser  *chooser)
+{
+  AnjutaRecentChooserMenu *menu = ANJUTA_RECENT_CHOOSER_MENU (chooser);
+  GtkWidget *menu_item;
+  GtkRecentInfo *info;
+  
+  menu_item = gtk_menu_get_active (GTK_MENU (menu));
+  if (!menu_item)
+    return NULL;
+  
+  info = g_object_get_data (G_OBJECT (menu_item), "gtk-recent-info");
+  if (!info)
+    return NULL;
+  
+  return g_strdup (gtk_recent_info_get_uri (info));
+}
+
+static gboolean
+anjuta_recent_chooser_menu_select_uri (GtkRecentChooser  *chooser,
+				    const gchar       *uri,
+				    GError           **error)
+{
+  AnjutaRecentChooserMenu *menu = ANJUTA_RECENT_CHOOSER_MENU (chooser);
+  GList *children, *l;
+  GtkWidget *menu_item = NULL;
+  gboolean found = FALSE;
+  
+  children = gtk_container_get_children (GTK_CONTAINER (menu));
+  for (l = children; l != NULL; l = l->next)
+    {
+      GtkRecentInfo *info;
+      
+      menu_item = GTK_WIDGET (l->data);
+      
+      info = g_object_get_data (G_OBJECT (menu_item), "gtk-recent-info");
+      if (!info)
+        continue;
+      
+      if (0 == strcmp (uri, gtk_recent_info_get_uri (info)))
+        found = TRUE;
+    }
+
+  g_list_free (children);
+  
+  if (!found)  
+    {
+      g_set_error (error, GTK_RECENT_CHOOSER_ERROR,
+      		   GTK_RECENT_CHOOSER_ERROR_NOT_FOUND,
+      		   _("No recently used resource found with URI `%s'"),
+      		   uri);
+      return FALSE;
+    }
+  else
+    {
+      gtk_menu_shell_select_item (GTK_MENU_SHELL (menu), menu_item);
+
+      return TRUE;
+    }
+}
+
+static void
+anjuta_recent_chooser_menu_unselect_uri (GtkRecentChooser *chooser,
+				       const gchar     *uri)
+{
+  AnjutaRecentChooserMenu *menu = ANJUTA_RECENT_CHOOSER_MENU (chooser);
+  
+  gtk_menu_shell_deselect (GTK_MENU_SHELL (menu));
+}
+
+static void
+anjuta_recent_chooser_menu_select_all (GtkRecentChooser *chooser)
+{
+  g_warning (_("This function is not implemented for "
+               "widgets of class '%s'"),
+             g_type_name (G_OBJECT_TYPE (chooser)));
+}
+
+static void
+anjuta_recent_chooser_menu_unselect_all (GtkRecentChooser *chooser)
+{
+  g_warning (_("This function is not implemented for "
+               "widgets of class '%s'"),
+             g_type_name (G_OBJECT_TYPE (chooser)));
+}
+
+static void
+anjuta_recent_chooser_menu_set_sort_func (GtkRecentChooser  *chooser,
+				       GtkRecentSortFunc  sort_func,
+				       gpointer           sort_data,
+				       GDestroyNotify     data_destroy)
+{
+  AnjutaRecentChooserMenu *menu = ANJUTA_RECENT_CHOOSER_MENU (chooser);
+  AnjutaRecentChooserMenuPrivate *priv = menu->priv;
+  
+  if (priv->sort_data_destroy)
+    {
+      priv->sort_data_destroy (priv->sort_data);
+      priv->sort_data_destroy = NULL;
+    }
+      
+  priv->sort_func = NULL;
+  priv->sort_data = NULL;
+  priv->sort_data_destroy = NULL;
+  
+  if (sort_func)
+    {
+      priv->sort_func = sort_func;
+      priv->sort_data = sort_data;
+      priv->sort_data_destroy = data_destroy;
+    }
+}
+
+static void
+chooser_set_sort_type (AnjutaRecentChooserMenu *menu,
+		       GtkRecentSortType     sort_type)
+{
+  if (menu->priv->sort_type == sort_type)
+    return;
+
+  menu->priv->sort_type = sort_type;
+}
+
+
+static GList *
+anjuta_recent_chooser_menu_get_items (GtkRecentChooser *chooser)
+{
+  AnjutaRecentChooserMenu *menu = ANJUTA_RECENT_CHOOSER_MENU (chooser);
+  AnjutaRecentChooserMenuPrivate *priv = menu->priv;
+
+  return _gtk_recent_chooser_get_items (chooser,
+                                        priv->current_filter,
+                                        priv->manager,
+                                        priv->sort_data);
+}
+
+static GtkRecentManager *
+anjuta_recent_chooser_menu_get_recent_manager (GtkRecentChooser *chooser)
+{
+  AnjutaRecentChooserMenuPrivate *priv;
+ 
+  priv = ANJUTA_RECENT_CHOOSER_MENU (chooser)->priv;
+  
+  return priv->manager;
+}
+
+static void
+anjuta_recent_chooser_menu_add_filter (GtkRecentChooser *chooser,
+				    GtkRecentFilter  *filter)
+{
+  AnjutaRecentChooserMenu *menu;
+
+  menu = ANJUTA_RECENT_CHOOSER_MENU (chooser);
+  
+  anjuta_recent_chooser_menu_set_current_filter (menu, filter);
+}
+
+static void
+anjuta_recent_chooser_menu_remove_filter (GtkRecentChooser *chooser,
+				       GtkRecentFilter  *filter)
+{
+  AnjutaRecentChooserMenu *menu;
+
+  menu = ANJUTA_RECENT_CHOOSER_MENU (chooser);
+  
+  if (filter == menu->priv->current_filter)
+    {
+      g_object_unref (menu->priv->current_filter);
+      menu->priv->current_filter = NULL;
+
+      g_object_notify (G_OBJECT (menu), "filter");
+    }
+}
+
+static GSList *
+anjuta_recent_chooser_menu_list_filters (GtkRecentChooser *chooser)
+{
+  AnjutaRecentChooserMenu *menu;
+  GSList *retval = NULL;
+
+  menu = ANJUTA_RECENT_CHOOSER_MENU (chooser);
+ 
+  if (menu->priv->current_filter)
+    retval = g_slist_prepend (retval, menu->priv->current_filter);
+
+  return retval;
+}
+
+static void
+anjuta_recent_chooser_menu_set_current_filter (AnjutaRecentChooserMenu *menu,
+					    GtkRecentFilter      *filter)
+{
+  AnjutaRecentChooserMenuPrivate *priv;
+
+  priv = menu->priv;
+  
+  if (priv->current_filter)
+    g_object_unref (G_OBJECT (priv->current_filter));
+  
+  if (filter)
+    {
+      priv->current_filter = filter;
+      g_object_ref_sink (priv->current_filter);
+    }
+
+  anjuta_recent_chooser_menu_populate (menu);
+  
+  g_object_notify (G_OBJECT (menu), "filter");
+}
+
+/* taken from libeel/eel-strings.c */
+static gchar *
+escape_underscores (const gchar *string)
+{
+  gint underscores;
+  const gchar *p;
+  gchar *q;
+  gchar *escaped;
+
+  if (!string)
+    return NULL;
+	
+  underscores = 0;
+  for (p = string; *p != '\0'; p++)
+    underscores += (*p == '_');
+
+  if (underscores == 0)
+    return g_strdup (string);
+
+  escaped = g_new (char, strlen (string) + underscores + 1);
+  for (p = string, q = escaped; *p != '\0'; p++, q++)
+    {
+      /* Add an extra underscore. */
+      if (*p == '_')
+        *q++ = '_';
+      
+      *q = *p;
+    }
+  
+  *q = '\0';
+	
+  return escaped;
+}
+
+static void
+anjuta_recent_chooser_menu_add_tip (AnjutaRecentChooserMenu *menu,
+				 GtkRecentInfo        *info,
+				 GtkWidget            *item)
+{
+  AnjutaRecentChooserMenuPrivate *priv;
+  gchar *path;
+
+  g_assert (info != NULL);
+  g_assert (item != NULL);
+
+  priv = menu->priv;
+  
+  path = gtk_recent_info_get_uri_display (info);
+  if (path)
+    {
+      gchar *tip_text = g_strdup_printf (_("Open '%s'"), path);
+
+      gtk_widget_set_tooltip_text (item, tip_text);
+      gtk_widget_set_has_tooltip (item, priv->show_tips);
+
+      g_free (path);
+      g_free (tip_text);
+    }
+}
+
+static GtkWidget *
+anjuta_recent_chooser_menu_create_item (AnjutaRecentChooserMenu *menu,
+				     GtkRecentInfo        *info,
+				     gint                  count)
+{
+  AnjutaRecentChooserMenuPrivate *priv;
+  gchar *text;
+  GtkWidget *item, *image, *label;
+  GdkPixbuf *icon;
+
+  g_assert (info != NULL);
+
+  priv = menu->priv;
+
+  if (priv->show_numbers)
+    {
+      gchar *name, *escaped;
+      
+      name = g_strdup (gtk_recent_info_get_display_name (info));
+      if (!name)
+        name = g_strdup (_("Unknown item"));
+      
+      escaped = escape_underscores (name);
+      
+      /* avoid clashing mnemonics */
+      if (count <= 10)
+        /* This is the label format that is used for the first 10 items 
+         * in a recent files menu. The %d is the number of the item,
+         * the %s is the name of the item. Please keep the _ in front
+         * of the number to give these menu items a mnemonic.
+         *
+         * Don't include the prefix "recent menu label|" in the translation.
+         */
+        text = g_strdup_printf (Q_("recent menu label|_%d. %s"), count, escaped);
+      else
+        /* This is the format that is used for items in a recent files menu. 
+         * The %d is the number of the item, the %s is the name of the item. 
+         *
+         * Don't include the prefix "recent menu label|" in the translation.
+         */
+        text = g_strdup_printf (Q_("recent menu label|%d. %s"), count, escaped);
+      
+      item = gtk_image_menu_item_new_with_mnemonic (text);
+      
+      g_free (escaped);
+      g_free (name);
+    }
+  else
+    {
+      text = g_strdup (gtk_recent_info_get_display_name (info));
+      item = gtk_image_menu_item_new_with_label (text);
+    }
+
+  g_free (text);
+
+  /* ellipsize the menu item label, in case the recent document
+   * display name is huge.
+   */
+  label = GTK_BIN (item)->child;
+  if (GTK_IS_LABEL (label))
+    {
+      gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+      gtk_label_set_max_width_chars (GTK_LABEL (label), priv->label_width);
+    }
+  
+  if (priv->show_icons)
+    {
+      icon = gtk_recent_info_get_icon (info, priv->icon_size);
+        
+      image = gtk_image_new_from_pixbuf (icon);
+      gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+      g_object_unref (icon);
+    }
+
+  g_signal_connect (item, "activate",
+  		    G_CALLBACK (item_activate_cb),
+  		    menu);
+
+  return item;
+}
+
+static void
+anjuta_recent_chooser_menu_insert_item (AnjutaRecentChooserMenu *menu,
+                                     GtkWidget            *menuitem,
+                                     gint                  position,
+                                     gboolean              anjuta_project)
+{
+  AnjutaRecentChooserMenuPrivate *priv = menu->priv;
+  gint real_position;
+  static gint anjuta_pos = 0;
+
+  if (priv->first_recent_item_pos == -1)
+    {
+      GList *children, *l;
+
+      children = gtk_container_get_children (GTK_CONTAINER (menu));
+
+      for (real_position = 0, l = children;
+           l != NULL;
+           real_position += 1, l = l->next)
+        {
+          GObject *child = l->data;
+          gboolean is_placeholder = FALSE;
+
+          is_placeholder =
+            GPOINTER_TO_INT (g_object_get_data (child, "gtk-recent-menu-placeholder"));
+
+          if (is_placeholder)
+            break;
+        }
+
+      g_list_free (children);
+      priv->first_recent_item_pos = real_position;
+      anjuta_pos = 0;
+    }
+  else
+    real_position = priv->first_recent_item_pos;
+
+  if (anjuta_project)
+  {
+    gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem,
+                         anjuta_pos);
+    anjuta_pos++;
+  } 
+  else gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+  
+  gtk_widget_show (menuitem);
+}
+
+/* removes the items we own from the menu */
+static void
+anjuta_recent_chooser_menu_dispose_items (AnjutaRecentChooserMenu *menu)
+{
+  GList *children, *l;
+ 
+  children = gtk_container_get_children (GTK_CONTAINER (menu));
+  for (l = children; l != NULL; l = l->next)
+    {
+      GtkWidget *menu_item = GTK_WIDGET (l->data);
+      gboolean has_mark = FALSE;
+      
+      /* check for our mark, in order to remove just the items we own */
+      has_mark =
+        GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item), "gtk-recent-menu-mark"));
+
+      if (has_mark)
+        {
+          GtkRecentInfo *info;
+          
+          /* destroy the attached RecentInfo struct, if found */
+          info = g_object_get_data (G_OBJECT (menu_item), "gtk-recent-info");
+          if (info)
+            g_object_set_data_full (G_OBJECT (menu_item), "gtk-recent-info",
+            			    NULL, NULL);
+          
+          /* and finally remove the item from the menu */
+          gtk_container_remove (GTK_CONTAINER (menu), menu_item);
+        }
+    }
+
+  /* recalculate the position of the first recent item */
+  menu->priv->first_recent_item_pos = -1;
+
+  g_list_free (children);
+}
+
+typedef struct
+{
+  GList *items;
+  gint n_items;
+  gint loaded_items;
+  gint displayed_items;
+  AnjutaRecentChooserMenu *menu;
+  GtkWidget *placeholder;
+} MenuPopulateData;
+
+static gboolean
+idle_populate_func (gpointer data)
+{
+  MenuPopulateData *pdata;
+  AnjutaRecentChooserMenuPrivate *priv;
+  GtkRecentInfo *info;
+  gboolean retval;
+  GtkWidget *item;
+
+  pdata = (MenuPopulateData *) data;
+  priv = pdata->menu->priv;
+
+  if (!pdata->items)
+    {
+      pdata->items = gtk_recent_chooser_get_items (GTK_RECENT_CHOOSER (pdata->menu));
+      if (!pdata->items)
+        {
+          /* show the placeholder here */
+          gtk_widget_show (pdata->placeholder);
+          pdata->displayed_items = 1;
+          priv->populate_id = 0;
+
+	  return FALSE;
+	}
+      
+      /* We add the separator */
+      GtkWidget *menuitem;
+      menuitem = gtk_separator_menu_item_new ();
+      anjuta_recent_chooser_menu_insert_item (pdata->menu, menuitem,
+                                       pdata->displayed_items, FALSE);
+	  g_object_set_data (G_OBJECT (menuitem),
+                     "gtk-recent-menu-mark",
+      		     GINT_TO_POINTER (TRUE));
+      
+      pdata->n_items = g_list_length (pdata->items);
+      pdata->loaded_items = 0;
+    }
+
+  info = g_list_nth_data (pdata->items, pdata->loaded_items);
+  item = anjuta_recent_chooser_menu_create_item (pdata->menu,
+                                              info,
+					      pdata->displayed_items);
+  if (!item)
+    goto check_and_return;
+      
+  anjuta_recent_chooser_menu_add_tip (pdata->menu, info, item);
+  if (strcmp (gtk_recent_info_get_mime_type (info), "application/x-anjuta") == 0)
+    anjuta_recent_chooser_menu_insert_item (pdata->menu, item,
+                                       pdata->displayed_items, TRUE);
+  else anjuta_recent_chooser_menu_insert_item (pdata->menu, item,
+                                       pdata->displayed_items, FALSE);
+  
+  pdata->displayed_items += 1;
+      
+  /* mark the menu item as one of our own */
+  g_object_set_data (G_OBJECT (item),
+                     "gtk-recent-menu-mark",
+      		     GINT_TO_POINTER (TRUE));
+      
+  /* attach the RecentInfo object to the menu item, and own a reference
+   * to it, so that it will be destroyed with the menu item when it's
+   * not needed anymore.
+   */
+  g_object_set_data_full (G_OBJECT (item), "gtk-recent-info",
+      			  gtk_recent_info_ref (info),
+      			  (GDestroyNotify) gtk_recent_info_unref);
+  
+check_and_return:
+  pdata->loaded_items += 1;
+
+  if (pdata->loaded_items == pdata->n_items)
+    {
+      g_list_foreach (pdata->items, (GFunc) gtk_recent_info_unref, NULL);
+      g_list_free (pdata->items);
+
+      priv->populate_id = 0;
+
+      retval = FALSE;
+    }
+  else
+    retval = TRUE;
+
+  return retval;
+}
+
+static void
+idle_populate_clean_up (gpointer data)
+{
+  MenuPopulateData *pdata = data;
+
+  if (pdata->menu->priv->populate_id == 0)
+    {
+      /* show the placeholder in case no item survived
+       * the filtering process in the idle loop
+       */
+      if (!pdata->displayed_items)
+        gtk_widget_show (pdata->placeholder);
+      g_object_unref (pdata->placeholder);
+
+      g_slice_free (MenuPopulateData, data);
+    }
+}
+
+static void
+anjuta_recent_chooser_menu_populate (AnjutaRecentChooserMenu *menu)
+{
+  MenuPopulateData *pdata;
+  AnjutaRecentChooserMenuPrivate *priv = menu->priv;
+
+  if (menu->priv->populate_id)
+    return;
+
+  pdata = g_slice_new (MenuPopulateData);
+  pdata->items = NULL;
+  pdata->n_items = 0;
+  pdata->loaded_items = 0;
+  pdata->displayed_items = 0;
+  pdata->menu = menu;
+  pdata->placeholder = g_object_ref (priv->placeholder);
+
+  priv->icon_size = get_icon_size_for_widget (GTK_WIDGET (menu));
+  
+  /* remove our menu items first and hide the placeholder */
+  anjuta_recent_chooser_menu_dispose_items (menu);
+  gtk_widget_hide (priv->placeholder);
+  
+  priv->populate_id = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE + 30,
+  					         idle_populate_func,
+					         pdata,
+                                                 idle_populate_clean_up);
+}
+
+/* bounce activate signal from the recent menu item widget 
+ * to the recent menu widget
+ */
+static void
+item_activate_cb (GtkWidget *widget,
+		  gpointer   user_data)
+{
+  GtkRecentChooser *chooser = GTK_RECENT_CHOOSER (user_data);
+  
+  g_signal_emit_by_name (chooser, "item_activated");
+}
+
+/* we force a redraw if the manager changes when we are showing */
+static void
+manager_changed_cb (GtkRecentManager *manager,
+		    gpointer          user_data)
+{
+  AnjutaRecentChooserMenu *menu = ANJUTA_RECENT_CHOOSER_MENU (user_data);
+
+  anjuta_recent_chooser_menu_populate (menu);
+}
+
+static void
+set_recent_manager (AnjutaRecentChooserMenu *menu,
+		    GtkRecentManager     *manager)
+{
+  AnjutaRecentChooserMenuPrivate *priv = menu->priv;
+
+  if (priv->manager)
+    {
+      if (priv->manager_changed_id)
+        {
+          g_signal_handler_disconnect (priv->manager, priv->manager_changed_id);
+          priv->manager_changed_id = 0;
+        }
+
+      if (priv->populate_id)
+        {
+          g_source_remove (priv->populate_id);
+          priv->populate_id = 0;
+        }
+
+      priv->manager = NULL;
+    }
+  
+  if (manager)
+    priv->manager = manager;
+  else
+    priv->manager = gtk_recent_manager_get_default ();
+  
+  if (priv->manager)
+    priv->manager_changed_id = g_signal_connect (priv->manager, "changed",
+                                                 G_CALLBACK (manager_changed_cb),
+                                                 menu);
+}
+
+static gint
+get_icon_size_for_widget (GtkWidget *widget)
+{
+  GtkSettings *settings;
+  gint width, height;
+
+  if (gtk_widget_has_screen (widget))
+    settings = gtk_settings_get_for_screen (gtk_widget_get_screen (widget));
+  else
+    settings = gtk_settings_get_default ();
+
+  if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
+                                         &width, &height))
+    return MAX (width, height);
+
+  return FALLBACK_ICON_SIZE;
+}
+
+static void
+foreach_set_shot_tips (GtkWidget *widget,
+                       gpointer   user_data)
+{
+  AnjutaRecentChooserMenu *menu = user_data;
+  AnjutaRecentChooserMenuPrivate *priv = menu->priv;
+  gboolean has_mark;
+
+  /* toggle the tooltip only on the items we create */
+  has_mark =
+    GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "gtk-recent-menu-mark"));
+
+  if (has_mark)
+    gtk_widget_set_has_tooltip (widget, priv->show_tips);
+}
+
+static void
+anjuta_recent_chooser_menu_set_show_tips (AnjutaRecentChooserMenu *menu,
+				       gboolean              show_tips)
+{
+  AnjutaRecentChooserMenuPrivate *priv = menu->priv;
+
+  if (priv->show_tips == show_tips)
+    return;
+  
+  priv->show_tips = show_tips;
+  gtk_container_foreach (GTK_CONTAINER (menu), foreach_set_shot_tips, menu);
+}
+
+/*
+ * Public API
+ */
+
+/**
+ * anjuta_recent_chooser_menu_new:
+ *
+ * Creates a new #AnjutaRecentChooserMenu widget.
+ *
+ * This kind of widget shows the list of recently used resources as
+ * a menu, each item as a menu item.  Each item inside the menu might
+ * have an icon, representing its MIME type, and a number, for mnemonic
+ * access.
+ *
+ * This widget implements the #GtkRecentChooser interface.
+ *
+ * This widget creates its own #GtkRecentManager object.  See the
+ * anjuta_recent_chooser_menu_new_for_manager() function to know how to create
+ * a #AnjutaRecentChooserMenu widget bound to another #GtkRecentManager object.
+ *
+ * Return value: a new #AnjutaRecentChooserMenu
+ *
+ * Since: 2.10
+ */
+GtkWidget *
+anjuta_recent_chooser_menu_new (void)
+{
+  return g_object_new (ANJUTA_TYPE_RECENT_CHOOSER_MENU,
+  		       "recent-manager", NULL,
+  		       NULL);
+}
+
+/**
+ * anjuta_recent_chooser_menu_new_for_manager:
+ * @manager: a #GtkRecentManager
+ *
+ * Creates a new #AnjutaRecentChooserMenu widget using @manager as
+ * the underlying recently used resources manager.
+ *
+ * This is useful if you have implemented your own recent manager,
+ * or if you have a customized instance of a #GtkRecentManager
+ * object or if you wish to share a common #GtkRecentManager object
+ * among multiple #GtkRecentChooser widgets.
+ *
+ * Return value: a new #AnjutaRecentChooserMenu, bound to @manager.
+ *
+ * Since: 2.10
+ */
+GtkWidget *
+anjuta_recent_chooser_menu_new_for_manager (GtkRecentManager *manager)
+{
+  g_return_val_if_fail (manager == NULL || GTK_IS_RECENT_MANAGER (manager), NULL);
+  
+  return g_object_new (ANJUTA_TYPE_RECENT_CHOOSER_MENU,
+  		       "recent-manager", manager,
+  		       NULL);
+}

Added: trunk/plugins/file-loader/anjuta-recent-chooser-menu.h
==============================================================================
--- (empty file)
+++ trunk/plugins/file-loader/anjuta-recent-chooser-menu.h	Fri Apr 11 00:19:38 2008
@@ -0,0 +1,71 @@
+/* GTK - The GIMP Toolkit
+ * gtkrecentchoosermenu.h - Recently used items menu widget
+ * Copyright (C) 2006, Emmanuele Bassi
+ *		 2008, Ignacio Casal Quinteiro
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ANJUTA_RECENT_CHOOSER_MENU_H__
+#define __ANJUTA_RECENT_CHOOSER_MENU_H__
+
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkrecentchooser.h>
+
+G_BEGIN_DECLS
+
+#define ANJUTA_TYPE_RECENT_CHOOSER_MENU		(anjuta_recent_chooser_menu_get_type ())
+#define ANJUTA_RECENT_CHOOSER_MENU(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), ANJUTA_TYPE_RECENT_CHOOSER_MENU, AnjutaRecentChooserMenu))
+#define ANJUTA_IS_RECENT_CHOOSER_MENU(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), ANJUTA_TYPE_RECENT_CHOOSER_MENU))
+#define ANJUTA_RECENT_CHOOSER_MENU_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), ANJUTA_TYPE_RECENT_CHOOSER_MENU, AnjutaRecentChooserMenuClass))
+#define ANJUTA_IS_RECENT_CHOOSER_MENU_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), ANJUTA_TYPE_RECENT_CHOOSER_MENU))
+#define ANJUTA_RECENT_CHOOSER_MENU_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), ANJUTA_TYPE_RECENT_CHOOSER_MENU, AnjutaRecentChooserMenuClass))
+
+typedef struct _AnjutaRecentChooserMenu		AnjutaRecentChooserMenu;
+typedef struct _AnjutaRecentChooserMenuClass	AnjutaRecentChooserMenuClass;
+typedef struct _AnjutaRecentChooserMenuPrivate	AnjutaRecentChooserMenuPrivate;
+
+struct _AnjutaRecentChooserMenu
+{
+  /*< private >*/
+  GtkMenu parent_instance;
+
+  AnjutaRecentChooserMenuPrivate *priv;
+};
+
+struct _AnjutaRecentChooserMenuClass
+{
+  GtkMenuClass parent_class;
+  
+  /* padding for future expansion */
+  void (* gtk_recent1) (void);
+  void (* gtk_recent2) (void);
+  void (* gtk_recent3) (void);
+  void (* gtk_recent4) (void);
+};
+
+GType      anjuta_recent_chooser_menu_get_type         (void) G_GNUC_CONST;
+
+GtkWidget *anjuta_recent_chooser_menu_new              (void);
+GtkWidget *anjuta_recent_chooser_menu_new_for_manager  (GtkRecentManager     *manager);
+
+gboolean   anjuta_recent_chooser_menu_get_show_numbers (AnjutaRecentChooserMenu *menu);
+void       anjuta_recent_chooser_menu_set_show_numbers (AnjutaRecentChooserMenu *menu,
+						     gboolean              show_numbers);
+
+G_END_DECLS
+
+#endif /* ! __ANJUTA_RECENT_CHOOSER_MENU_H__ */

Modified: trunk/plugins/file-loader/plugin.c
==============================================================================
--- trunk/plugins/file-loader/plugin.c	(original)
+++ trunk/plugins/file-loader/plugin.c	Fri Apr 11 00:19:38 2008
@@ -37,6 +37,7 @@
 
 #include "plugin.h"
 #include "dnd.h"
+#include "anjuta-recent-chooser-menu.h"
 
 #define UI_FILE PACKAGE_DATA_DIR"/ui/anjuta-loader-plugin.ui"
 
@@ -1117,25 +1118,6 @@
 	}
 }
 
-static gint
-sort_recent_menu (GtkRecentInfo *a, GtkRecentInfo *b, gpointer useless)
-{
-	const gchar *mime_a;
-	const gchar *mime_b;
-
-	mime_a = gtk_recent_info_get_mime_type (a);
-	mime_b = gtk_recent_info_get_mime_type (b);
-	
-	if (strcmp(mime_a, mime_b) == 0)
-		return 1;
-	else if (strcmp (mime_a, "application/x-anjuta") == 0)
-		return -1;
-	else if (strcmp (mime_b, "application/x-anjuta") == 0)
-		return 1;
-		
-	return 0;
-}
-
 static void
 setup_recent_chooser_menu (GtkRecentChooser* recent_menu, AnjutaFileLoaderPlugin* plugin)
 {
@@ -1143,9 +1125,7 @@
 
 	gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (recent_menu), TRUE);
 	gtk_recent_chooser_set_show_icons (GTK_RECENT_CHOOSER (recent_menu), TRUE);
-	gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (recent_menu), GTK_RECENT_SORT_CUSTOM);
-	gtk_recent_chooser_set_sort_func (GTK_RECENT_CHOOSER (recent_menu), sort_recent_menu, NULL, NULL);
-	g_object_set (recent_menu, "show-numbers", TRUE, NULL);
+	gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (recent_menu), GTK_RECENT_SORT_MRU);
 	gtk_recent_chooser_set_limit (GTK_RECENT_CHOOSER (recent_menu), 20);
 
 	filter = gtk_recent_filter_new ();
@@ -1217,7 +1197,7 @@
 	loader_plugin->uiid = anjuta_ui_merge (ui, UI_FILE);
 	
 	/* Adding submenus */
-	recent_menu = gtk_recent_chooser_menu_new_for_manager (loader_plugin->recent_manager);
+	recent_menu = anjuta_recent_chooser_menu_new_for_manager (loader_plugin->recent_manager);
 	setup_recent_chooser_menu (GTK_RECENT_CHOOSER (recent_menu), loader_plugin);
 	widget = gtk_ui_manager_get_widget (GTK_UI_MANAGER(ui),
 					"/MenuMain/MenuFile/PlaceholderFileMenus/OpenRecent");
@@ -1285,7 +1265,6 @@
 static void
 dispose (GObject *obj)
 {
-	AnjutaFileLoaderPlugin *plugin = ANJUTA_PLUGIN_FILE_LOADER (obj);
 	G_OBJECT_CLASS (parent_class)->dispose (obj);
 }
 

Modified: trunk/plugins/search/Makefile.am
==============================================================================
--- trunk/plugins/search/Makefile.am	(original)
+++ trunk/plugins/search/Makefile.am	Fri Apr 11 00:19:38 2008
@@ -50,9 +50,7 @@
 	search-replace.c \
 	search-replace.h \
 	search-replace_backend.c \
-	search-replace_backend.h \
-	search_preferences.c \
-	search_preferences.h
+	search-replace_backend.h
 
 EXTRA_DIST = \
 	$(plugin_in_files) \

Modified: trunk/plugins/search/anjuta-search.glade
==============================================================================
--- trunk/plugins/search/anjuta-search.glade	(original)
+++ trunk/plugins/search/anjuta-search.glade	Fri Apr 11 00:19:38 2008
@@ -3,1040 +3,608 @@
 <!--*- mode: xml -*-->
 <glade-interface>
   <widget class="GtkWindow" id="dialog.search.replace">
-    <property name="title" translatable="yes">Find &amp; Replace</property>
-    <signal name="key_press_event" handler="on_search_dialog_key_press_event" after="yes" object="dialog.search.replace"/>
-    <signal name="delete_event" handler="on_search_replace_delete_event"/>
+    <property name="title" translatable="yes">Anjuta - Find &amp; Replace</property>
+    <property name="window_position">GTK_WIN_POS_CENTER</property>
+    <property name="destroy_with_parent">True</property>
+    <signal name="delete_event" handler="on_search_dialog_delete_event"/>
     <child>
-      <widget class="GtkFrame" id="frame9">
+      <widget class="GtkFrame" id="frame.search">
         <property name="visible">True</property>
+        <property name="border_width">5</property>
         <property name="label_xalign">0</property>
         <property name="shadow_type">GTK_SHADOW_NONE</property>
         <child>
-          <widget class="GtkVBox" id="vbox10">
+          <widget class="GtkVBox" id="vbox100">
             <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
             <child>
-              <widget class="GtkFrame" id="frame10">
+              <widget class="GtkFrame" id="frame.sr.actions">
                 <property name="visible">True</property>
                 <property name="label_xalign">0</property>
                 <property name="shadow_type">GTK_SHADOW_NONE</property>
                 <child>
-                  <widget class="GtkNotebook" id="search.notebook">
+                  <widget class="GtkHBox" id="hbox2">
                     <property name="visible">True</property>
-                    <property name="can_focus">True</property>
+                    <property name="spacing">5</property>
                     <child>
-                      <widget class="GtkFrame" id="frame.search.expression">
+                      <widget class="GtkComboBox" id="search.action.combo">
                         <property name="visible">True</property>
-                        <property name="border_width">5</property>
-                        <property name="label_xalign">0</property>
-                        <property name="shadow_type">GTK_SHADOW_NONE</property>
+                        <property name="has_frame">False</property>
+                        <signal name="changed" handler="on_search_action_changed"/>
+                      </widget>
+                      <packing>
+                        <property name="padding">5</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label20">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Action:&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="type">label_item</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="padding">5</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkFrame" id="frame.sr.expr">
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">GTK_SHADOW_NONE</property>
+                <child>
+                  <widget class="GtkVBox" id="vbox3">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="spacing">5</property>
+                    <child>
+                      <widget class="GtkTable" id="table.sr.params">
+                        <property name="visible">True</property>
+                        <property name="border_width">3</property>
+                        <property name="n_rows">3</property>
+                        <property name="n_columns">3</property>
+                        <property name="column_spacing">5</property>
+                        <property name="row_spacing">5</property>
                         <child>
-                          <widget class="GtkTable" id="table3">
+                          <placeholder/>
+                        </child>
+                        <child>
+                          <widget class="GtkLabel" id="label.search">
                             <property name="visible">True</property>
-                            <property name="n_rows">3</property>
-                            <property name="n_columns">1</property>
-                            <property name="column_spacing">10</property>
-                            <property name="row_spacing">7</property>
-                            <child>
-                              <widget class="GtkFrame" id="frame50">
-                                <property name="visible">True</property>
-                                <property name="label_xalign">0</property>
-                                <property name="shadow_type">GTK_SHADOW_NONE</property>
-                                <child>
-                                  <widget class="GtkTable" id="table30">
-                                    <property name="visible">True</property>
-                                    <property name="border_width">5</property>
-                                    <property name="n_rows">3</property>
-                                    <property name="n_columns">3</property>
-                                    <property name="row_spacing">5</property>
-                                    <child>
-                                      <placeholder/>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkCheckButton" id="replace.regex">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="label" translatable="yes">Expand regex back references</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="response_id">0</property>
-                                        <property name="draw_indicator">True</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="right_attach">2</property>
-                                        <property name="top_attach">2</property>
-                                        <property name="bottom_attach">3</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                        <property name="x_padding">4</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkComboBoxEntry" id="replace.string.combo">
-                                        <property name="visible">True</property>
-                                        <child internal-child="entry">
-                                          <widget class="GtkEntry" id="comboboxentry-entry2">
-                                          </widget>
-                                        </child>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">3</property>
-                                        <property name="top_attach">1</property>
-                                        <property name="bottom_attach">2</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkLabel" id="label.replace">
-                                        <property name="visible">True</property>
-                                        <property name="xalign">0</property>
-                                        <property name="xpad">5</property>
-                                        <property name="label" translatable="yes">Replace With:</property>
-                                        <property name="justify">GTK_JUSTIFY_CENTER</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="top_attach">1</property>
-                                        <property name="bottom_attach">2</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkComboBoxEntry" id="search.string.combo">
-                                        <property name="visible">True</property>
-                                        <child internal-child="entry">
-                                          <widget class="GtkEntry" id="comboboxentry-entry1">
-                                          </widget>
-                                        </child>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">3</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkLabel" id="label29">
-                                        <property name="visible">True</property>
-                                        <property name="xalign">0</property>
-                                        <property name="xpad">5</property>
-                                        <property name="label" translatable="yes" comments="This is &quot;the search expression&quot; (noun)">Search Expression:</property>
-                                        <property name="justify">GTK_JUSTIFY_CENTER</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                  </widget>
-                                </child>
-                                <child>
-                                  <widget class="GtkLabel" id="label12357">
-                                    <property name="visible">True</property>
-                                    <property name="label" translatable="yes">&lt;b&gt;Parameters&lt;/b&gt;</property>
-                                    <property name="use_markup">True</property>
-                                  </widget>
-                                  <packing>
-                                    <property name="type">label_item</property>
-                                  </packing>
-                                </child>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">Search for:</property>
+                          </widget>
+                        </child>
+                        <child>
+                          <widget class="GtkComboBoxEntry" id="search.string.combo">
+                            <property name="visible">True</property>
+                            <signal name="changed" handler="on_search_expression_changed"/>
+                            <child internal-child="entry">
+                              <widget class="GtkEntry" id="comboboxentry-entry8">
+                                <signal name="activate" handler="on_search_expression_activate"/>
                               </widget>
-                              <packing>
-                                <property name="x_options">GTK_FILL</property>
-                                <property name="y_options">GTK_FILL</property>
-                              </packing>
                             </child>
-                            <child>
-                              <widget class="GtkFrame" id="frame.search.basic">
-                                <property name="visible">True</property>
-                                <property name="label_xalign">0</property>
-                                <property name="shadow_type">GTK_SHADOW_NONE</property>
-                                <child>
-                                  <widget class="GtkHBox" id="hbox1127">
-                                    <property name="visible">True</property>
-                                    <property name="border_width">5</property>
-                                    <property name="spacing">20</property>
-                                    <child>
-                                      <widget class="GtkRadioButton" id="search.full_buffer">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="label" translatable="yes">Full Buffer</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="response_id">0</property>
-                                        <property name="draw_indicator">True</property>
-                                        <signal name="toggled" handler="on_search_full_buffer_toggled"/>
-                                      </widget>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="fill">False</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkRadioButton" id="search.forward">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="label" translatable="yes">Forward</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="response_id">0</property>
-                                        <property name="draw_indicator">True</property>
-                                        <property name="group">search.full_buffer</property>
-                                        <signal name="toggled" handler="on_search_forward_toggled"/>
-                                      </widget>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="fill">False</property>
-                                        <property name="position">1</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkRadioButton" id="search.backward">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="label" translatable="yes">Backward</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="response_id">0</property>
-                                        <property name="draw_indicator">True</property>
-                                        <property name="group">search.full_buffer</property>
-                                        <signal name="toggled" handler="on_search_backward_toggled"/>
-                                      </widget>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="fill">False</property>
-                                        <property name="position">2</property>
-                                      </packing>
-                                    </child>
-                                  </widget>
-                                </child>
-                                <child>
-                                  <widget class="GtkLabel" id="label12356">
-                                    <property name="visible">True</property>
-                                    <property name="label" translatable="yes">&lt;b&gt;Scope&lt;/b&gt;</property>
-                                    <property name="use_markup">True</property>
-                                  </widget>
-                                  <packing>
-                                    <property name="type">label_item</property>
-                                  </packing>
-                                </child>
+                          </widget>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">3</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkLabel" id="label.replace">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">Replace with:</property>
+                          </widget>
+                          <packing>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkComboBoxEntry" id="replace.string.combo">
+                            <property name="visible">True</property>
+                            <child internal-child="entry">
+                              <widget class="GtkEntry" id="comboboxentry-entry9">
+                                <signal name="activate" handler="on_search_expression_activate"/>
                               </widget>
-                              <packing>
-                                <property name="top_attach">1</property>
-                                <property name="bottom_attach">2</property>
-                                <property name="y_options">GTK_FILL</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <widget class="GtkFrame" id="frame51">
-                                <property name="visible">True</property>
-                                <property name="label_xalign">0</property>
-                                <property name="shadow_type">GTK_SHADOW_NONE</property>
-                                <child>
-                                  <widget class="GtkTable" id="table31">
-                                    <property name="visible">True</property>
-                                    <property name="border_width">5</property>
-                                    <property name="n_rows">3</property>
-                                    <property name="n_columns">2</property>
-                                    <child>
-                                      <widget class="GtkCheckButton" id="search.match.word.start">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="label" translatable="yes">Match at start of word</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="response_id">0</property>
-                                        <property name="draw_indicator">True</property>
-                                        <signal name="toggled" handler="on_search_match_word_start_toggled"/>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">2</property>
-                                        <property name="top_attach">1</property>
-                                        <property name="bottom_attach">2</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                        <property name="x_padding">5</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkCheckButton" id="search.match.whole.line">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="label" translatable="yes">Match complete lines</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="response_id">0</property>
-                                        <property name="draw_indicator">True</property>
-                                        <signal name="toggled" handler="on_search_match_whole_line_toggled"/>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">2</property>
-                                        <property name="top_attach">2</property>
-                                        <property name="bottom_attach">3</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                        <property name="x_padding">5</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkCheckButton" id="search.greedy">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="label" translatable="yes">Greedy matching</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="response_id">0</property>
-                                        <property name="draw_indicator">True</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">2</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                        <property name="x_padding">5</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkCheckButton" id="search.match.whole.word">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="label" translatable="yes">Match complete words</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="response_id">0</property>
-                                        <property name="draw_indicator">True</property>
-                                        <signal name="toggled" handler="on_search_match_whole_word_toggled"/>
-                                      </widget>
-                                      <packing>
-                                        <property name="top_attach">2</property>
-                                        <property name="bottom_attach">3</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                        <property name="x_padding">5</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkCheckButton" id="search.ignore.case">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="label" translatable="yes">Case insensitive</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="response_id">0</property>
-                                        <property name="draw_indicator">True</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="top_attach">1</property>
-                                        <property name="bottom_attach">2</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                        <property name="x_padding">5</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkCheckButton" id="search.regex">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="label" translatable="yes">Regular Expression</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="response_id">0</property>
-                                        <property name="draw_indicator">True</property>
-                                        <signal name="toggled" handler="on_search_regex_toggled"/>
-                                      </widget>
-                                      <packing>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                        <property name="x_padding">5</property>
-                                      </packing>
-                                    </child>
-                                  </widget>
-                                </child>
-                                <child>
-                                  <widget class="GtkLabel" id="label12355">
-                                    <property name="visible">True</property>
-                                    <property name="label" translatable="yes">&lt;b&gt;Options&lt;/b&gt;</property>
-                                    <property name="use_markup">True</property>
-                                  </widget>
-                                  <packing>
-                                    <property name="type">label_item</property>
-                                  </packing>
-                                </child>
-                              </widget>
-                              <packing>
-                                <property name="top_attach">2</property>
-                                <property name="bottom_attach">3</property>
-                                <property name="y_options">GTK_FILL</property>
-                              </packing>
                             </child>
                           </widget>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">3</property>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                          </packing>
                         </child>
+                        <child>
+                          <widget class="GtkCheckButton" id="search.regex">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="label" translatable="yes">_Regular expression</property>
+                            <property name="use_underline">True</property>
+                            <property name="response_id">0</property>
+                            <property name="draw_indicator">True</property>
+                            <signal name="toggled" handler="on_search_regex_toggled"/>
+                          </widget>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">3</property>
+                            <property name="top_attach">2</property>
+                            <property name="bottom_attach">3</property>
+                          </packing>
+                        </child>
+                      </widget>
+                      <packing>
+                        <property name="padding">5</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="sr.params.label">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Expression:&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="type">label_item</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="padding">5</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkFrame" id="frame.sr.options">
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">GTK_SHADOW_NONE</property>
+                <child>
+                  <widget class="GtkTable" id="table.sr.options">
+                    <property name="visible">True</property>
+                    <property name="border_width">3</property>
+                    <property name="n_rows">3</property>
+                    <property name="n_columns">2</property>
+                    <property name="column_spacing">5</property>
+                    <property name="row_spacing">2</property>
+                    <child>
+                      <widget class="GtkCheckButton" id="search.ignore.case">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="label" translatable="yes">Case _insensitive</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="x_padding">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="search.match.word.start">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="label" translatable="yes">Match w_ord start</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="x_padding">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="search.match.whole.word">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="label" translatable="yes">Match whole _words</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_padding">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="search.match.whole.line">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="label" translatable="yes">Match whole _lines</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
                       </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_padding">3</property>
+                      </packing>
                     </child>
                     <child>
-                      <widget class="GtkLabel" id="search.expression.tab">
+                      <widget class="GtkCheckButton" id="search.greedy">
                         <property name="visible">True</property>
-                        <property name="label" translatable="yes" comments="This is &quot;the search expression&quot; (noun)">Search Expression</property>
-                        <property name="justify">GTK_JUSTIFY_CENTER</property>
+                        <property name="can_focus">True</property>
+                        <property name="label" translatable="yes">_Greedy matching</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
                       </widget>
                       <packing>
-                        <property name="type">tab</property>
-                        <property name="tab_fill">False</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="x_padding">3</property>
                       </packing>
                     </child>
                     <child>
-                      <widget class="GtkFrame" id="frame.search.target">
+                      <widget class="GtkCheckButton" id="replace.regex">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="label" translatable="yes">E_xpand back refs</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="x_padding">3</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label.sr.options">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Options&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="type">label_item</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="padding">5</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkExpander" id="expander1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <child>
+                  <widget class="GtkVBox" id="vbox2">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="spacing">5</property>
+                    <child>
+                      <widget class="GtkHBox" id="hbox1">
                         <property name="visible">True</property>
                         <property name="border_width">5</property>
+                        <property name="spacing">5</property>
+                        <child>
+                          <widget class="GtkRadioButton" id="search.whole">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="label" translatable="yes">F_rom start</property>
+                            <property name="use_underline">True</property>
+                            <property name="response_id">0</property>
+                            <property name="draw_indicator">True</property>
+                          </widget>
+                        </child>
+                        <child>
+                          <widget class="GtkRadioButton" id="search.forward">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="label" translatable="yes">_Forward</property>
+                            <property name="use_underline">True</property>
+                            <property name="response_id">0</property>
+                            <property name="draw_indicator">True</property>
+                            <property name="group">search.whole</property>
+                          </widget>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkRadioButton" id="search.backward">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="label" translatable="yes">_Backward</property>
+                            <property name="use_underline">True</property>
+                            <property name="response_id">0</property>
+                            <property name="draw_indicator">True</property>
+                            <property name="group">search.whole</property>
+                          </widget>
+                          <packing>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkComboBox" id="search.target.combo">
+                        <property name="visible">True</property>
+                        <signal name="changed" handler="on_search_target_changed"/>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="padding">5</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkFrame" id="frame.file.filter">
                         <property name="label_xalign">0</property>
                         <property name="shadow_type">GTK_SHADOW_NONE</property>
                         <child>
-                          <widget class="GtkTable" id="table4">
+                          <widget class="GtkTable" id="table3">
                             <property name="visible">True</property>
-                            <property name="n_rows">4</property>
+                            <property name="border_width">3</property>
+                            <property name="n_rows">6</property>
                             <property name="n_columns">2</property>
+                            <property name="column_spacing">5</property>
+                            <property name="row_spacing">2</property>
+                            <child>
+                              <placeholder/>
+                            </child>
                             <child>
-                              <widget class="GtkFrame" id="frame60">
+                              <widget class="GtkCheckButton" id="search.dir.recursive">
                                 <property name="visible">True</property>
-                                <property name="label_xalign">0</property>
-                                <property name="shadow_type">GTK_SHADOW_NONE</property>
-                                <child>
-                                  <widget class="GtkTable" id="table33">
-                                    <property name="visible">True</property>
-                                    <property name="border_width">5</property>
-                                    <property name="n_rows">2</property>
-                                    <property name="n_columns">2</property>
-                                    <property name="column_spacing">5</property>
-                                    <property name="row_spacing">5</property>
-                                    <child>
-                                      <widget class="GtkComboBox" id="search.target.combo">
-                                        <property name="visible">True</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">2</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkComboBox" id="search.direction.combo">
-                                        <property name="visible">True</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">2</property>
-                                        <property name="top_attach">1</property>
-                                        <property name="bottom_attach">2</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkLabel" id="label38">
-                                        <property name="visible">True</property>
-                                        <property name="xalign">0</property>
-                                        <property name="label" translatable="yes">Search Direction:</property>
-                                        <property name="justify">GTK_JUSTIFY_CENTER</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="top_attach">1</property>
-                                        <property name="bottom_attach">2</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkLabel" id="label30">
-                                        <property name="visible">True</property>
-                                        <property name="xalign">0</property>
-                                        <property name="label" translatable="yes">Search In:</property>
-                                        <property name="justify">GTK_JUSTIFY_CENTER</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                  </widget>
-                                </child>
-                                <child>
-                                  <widget class="GtkLabel" id="label12358">
-                                    <property name="visible">True</property>
-                                    <property name="label" translatable="yes">&lt;b&gt;Scope&lt;/b&gt;</property>
-                                    <property name="use_markup">True</property>
-                                  </widget>
-                                  <packing>
-                                    <property name="type">label_item</property>
-                                  </packing>
-                                </child>
+                                <property name="can_focus">True</property>
+                                <property name="label" translatable="yes">Search recursively</property>
+                                <property name="use_underline">True</property>
+                                <property name="response_id">0</property>
+                                <property name="draw_indicator">True</property>
                               </widget>
                               <packing>
+                                <property name="left_attach">1</property>
                                 <property name="right_attach">2</property>
-                                <property name="x_options">GTK_FILL</property>
+                                <property name="top_attach">5</property>
+                                <property name="bottom_attach">6</property>
                               </packing>
                             </child>
                             <child>
-                              <widget class="GtkFrame" id="frame56">
+                              <widget class="GtkComboBoxEntry" id="dir.filter.unmatch.combo">
                                 <property name="visible">True</property>
-                                <property name="label_xalign">0</property>
-                                <property name="shadow_type">GTK_SHADOW_NONE</property>
-                                <child>
-                                  <widget class="GtkTable" id="table32">
-                                    <property name="visible">True</property>
-                                    <property name="border_width">5</property>
-                                    <property name="n_rows">2</property>
-                                    <property name="n_columns">2</property>
-                                    <property name="column_spacing">5</property>
-                                    <property name="row_spacing">5</property>
-                                    <child>
-                                      <widget class="GtkHBox" id="hbox1128">
-                                        <property name="visible">True</property>
-                                        <property name="spacing">5</property>
-                                        <child>
-                                          <widget class="GtkSpinButton" id="actions.max">
-                                            <property name="visible">True</property>
-                                            <property name="can_focus">True</property>
-                                            <property name="adjustment">100 1 400 1 10 10</property>
-                                            <property name="climb_rate">1</property>
-                                          </widget>
-                                          <packing>
-                                            <property name="expand">False</property>
-                                          </packing>
-                                        </child>
-                                        <child>
-                                          <widget class="GtkCheckButton" id="actions.no_limit">
-                                            <property name="visible">True</property>
-                                            <property name="can_focus">True</property>
-                                            <property name="label" translatable="yes">No Limit</property>
-                                            <property name="use_underline">True</property>
-                                            <property name="response_id">0</property>
-                                            <property name="draw_indicator">True</property>
-                                            <signal name="clicked" handler="on_actions_no_limit_clicked"/>
-                                          </widget>
-                                          <packing>
-                                            <property name="expand">False</property>
-                                            <property name="fill">False</property>
-                                            <property name="position">1</property>
-                                          </packing>
-                                        </child>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">2</property>
-                                        <property name="top_attach">1</property>
-                                        <property name="bottom_attach">2</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options">GTK_FILL</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkLabel" id="label39">
-                                        <property name="visible">True</property>
-                                        <property name="xalign">0</property>
-                                        <property name="label" translatable="yes">Maximum Actions</property>
-                                        <property name="justify">GTK_JUSTIFY_CENTER</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="top_attach">1</property>
-                                        <property name="bottom_attach">2</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkComboBox" id="search.action.combo">
-                                        <property name="visible">True</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">2</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkLabel" id="label31">
-                                        <property name="visible">True</property>
-                                        <property name="xalign">0</property>
-                                        <property name="label" translatable="yes">Search Action:</property>
-                                        <property name="justify">GTK_JUSTIFY_CENTER</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
+                                <property name="items" translatable="yes">CVS intl po</property>
+                                <child internal-child="entry">
+                                  <widget class="GtkEntry" id="comboboxentry-entry12">
                                   </widget>
                                 </child>
-                                <child>
-                                  <widget class="GtkLabel" id="label12354">
-                                    <property name="visible">True</property>
-                                    <property name="label" translatable="yes">&lt;b&gt;Actions&lt;/b&gt;</property>
-                                    <property name="use_markup">True</property>
+                              </widget>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">4</property>
+                                <property name="bottom_attach">5</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkComboBoxEntry" id="dir.filter.match.combo">
+                                <property name="visible">True</property>
+                                <child internal-child="entry">
+                                  <widget class="GtkEntry" id="comboboxentry-entry11">
                                   </widget>
-                                  <packing>
-                                    <property name="type">label_item</property>
-                                  </packing>
                                 </child>
                               </widget>
                               <packing>
+                                <property name="left_attach">1</property>
                                 <property name="right_attach">2</property>
                                 <property name="top_attach">3</property>
                                 <property name="bottom_attach">4</property>
-                                <property name="x_options">GTK_FILL</property>
                               </packing>
                             </child>
                             <child>
-                              <widget class="GtkFrame" id="frame.search.var">
-                                <property name="label_xalign">0</property>
-                                <property name="shadow_type">GTK_SHADOW_NONE</property>
-                                <child>
-                                  <widget class="GtkComboBoxEntry" id="search.var.combo">
-                                    <property name="visible">True</property>
-                                    <property name="items">
-$(module.source.files) $(module.include.files)</property>
-                                    <child internal-child="entry">
-                                      <widget class="GtkEntry" id="comboboxentry-entry7">
-                                      </widget>
-                                    </child>
-                                  </widget>
-                                </child>
-                                <child>
-                                  <widget class="GtkLabel" id="label39">
-                                    <property name="visible">True</property>
-                                    <property name="label" translatable="yes" comments="User can select variables that contain lists of files, so this is a combined noun">&lt;b&gt;Search variable&lt;/b&gt;</property>
-                                    <property name="use_markup">True</property>
+                              <widget class="GtkComboBoxEntry" id="file.filter.unmatch.combo">
+                                <property name="visible">True</property>
+                                <property name="items" translatable="yes">*.so *.o *.a *.la</property>
+                                <child internal-child="entry">
+                                  <widget class="GtkEntry" id="comboboxentry-entry10">
                                   </widget>
-                                  <packing>
-                                    <property name="type">label_item</property>
-                                  </packing>
                                 </child>
                               </widget>
                               <packing>
+                                <property name="left_attach">1</property>
                                 <property name="right_attach">2</property>
                                 <property name="top_attach">1</property>
                                 <property name="bottom_attach">2</property>
-                                <property name="x_options">GTK_FILL</property>
                               </packing>
                             </child>
                             <child>
-                              <widget class="GtkFrame" id="frame.file.filter">
-                                <property name="label_xalign">0</property>
-                                <property name="shadow_type">GTK_SHADOW_NONE</property>
-                                <child>
-                                  <widget class="GtkTable" id="table5">
-                                    <property name="visible">True</property>
-                                    <property name="border_width">5</property>
-                                    <property name="n_rows">6</property>
-                                    <property name="n_columns">3</property>
-                                    <property name="column_spacing">5</property>
-                                    <property name="row_spacing">5</property>
-                                    <child>
-                                      <widget class="GtkComboBoxEntry" id="dir.filter.unmatch.combo">
-                                        <property name="visible">True</property>
-                                        <property name="items">
-CVS
-CVS intl po </property>
-                                        <child internal-child="entry">
-                                          <widget class="GtkEntry" id="comboboxentry-entry6">
-                                          </widget>
-                                        </child>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">3</property>
-                                        <property name="top_attach">4</property>
-                                        <property name="bottom_attach">5</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkComboBoxEntry" id="dir.filter.match.combo">
-                                        <property name="visible">True</property>
-                                        <child internal-child="entry">
-                                          <widget class="GtkEntry" id="comboboxentry-entry5">
-                                          </widget>
-                                        </child>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">3</property>
-                                        <property name="top_attach">3</property>
-                                        <property name="bottom_attach">4</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkComboBoxEntry" id="file.filter.unmatch.combo">
-                                        <property name="visible">True</property>
-                                        <property name="items">*.so *.o *.a *.la
-</property>
-                                        <child internal-child="entry">
-                                          <widget class="GtkEntry" id="comboboxentry-entry4">
-                                          </widget>
-                                        </child>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">3</property>
-                                        <property name="top_attach">1</property>
-                                        <property name="bottom_attach">2</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkComboBoxEntry" id="file.filter.match.combo">
-                                        <property name="visible">True</property>
-                                        <property name="items">*\.*
-*.c *.cpp *.cxx *.cc *.C *.h *.H *.hh *.hxx *.hpp
+                              <widget class="GtkComboBoxEntry" id="file.filter.match.combo">
+                                <property name="visible">True</property>
+                                <property name="items" translatable="yes">*\.* *.c *.cpp *.cxx *.cc *.C *.h *.H *.hh *.hxx *.hpp
 *.cpp *.cxx *.cc *.C *.h *.H *.hh *.hxx *.hpp Makefile.am configure.* README AUTHORS ChangeLog *.m4</property>
-                                        <child internal-child="entry">
-                                          <widget class="GtkEntry" id="comboboxentry-entry3">
-                                          </widget>
-                                        </child>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">3</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkCheckButton" id="ignore.binary.files">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="label" translatable="yes">Ignore Binary Files</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="response_id">0</property>
-                                        <property name="draw_indicator">True</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">3</property>
-                                        <property name="top_attach">2</property>
-                                        <property name="bottom_attach">3</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkCheckButton" id="search.dir.recursive">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="label" translatable="yes">Search Recursively</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="response_id">0</property>
-                                        <property name="draw_indicator">True</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="left_attach">1</property>
-                                        <property name="right_attach">3</property>
-                                        <property name="top_attach">5</property>
-                                        <property name="bottom_attach">6</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkCheckButton" id="ignore.hidden.dirs">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="label" translatable="yes">Ignore Hidden Directories</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="response_id">0</property>
-                                        <property name="draw_indicator">True</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="top_attach">5</property>
-                                        <property name="bottom_attach">6</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkLabel" id="label35">
-                                        <property name="visible">True</property>
-                                        <property name="xalign">0</property>
-                                        <property name="label" translatable="yes">Ignore Directories:</property>
-                                        <property name="justify">GTK_JUSTIFY_CENTER</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="top_attach">4</property>
-                                        <property name="bottom_attach">5</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkLabel" id="label34">
-                                        <property name="visible">True</property>
-                                        <property name="xalign">0</property>
-                                        <property name="label" translatable="yes">Choose Directories:</property>
-                                        <property name="justify">GTK_JUSTIFY_CENTER</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="top_attach">3</property>
-                                        <property name="bottom_attach">4</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkCheckButton" id="ignore.hidden.files">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="label" translatable="yes">Ignore Hidden Files</property>
-                                        <property name="use_underline">True</property>
-                                        <property name="response_id">0</property>
-                                        <property name="draw_indicator">True</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="top_attach">2</property>
-                                        <property name="bottom_attach">3</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkLabel" id="label33">
-                                        <property name="visible">True</property>
-                                        <property name="xalign">0</property>
-                                        <property name="label" translatable="yes">Ignore Files:</property>
-                                        <property name="justify">GTK_JUSTIFY_CENTER</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="top_attach">1</property>
-                                        <property name="bottom_attach">2</property>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkLabel" id="label32">
-                                        <property name="visible">True</property>
-                                        <property name="xalign">0</property>
-                                        <property name="label" translatable="yes">Choose Files:</property>
-                                        <property name="justify">GTK_JUSTIFY_CENTER</property>
-                                      </widget>
-                                      <packing>
-                                        <property name="x_options">GTK_FILL</property>
-                                        <property name="y_options"></property>
-                                      </packing>
-                                    </child>
-                                  </widget>
-                                </child>
-                                <child>
-                                  <widget class="GtkLabel" id="label40">
-                                    <property name="visible">True</property>
-                                    <property name="label" translatable="yes">&lt;b&gt;File Filter&lt;/b&gt;</property>
-                                    <property name="use_markup">True</property>
+                                <child internal-child="entry">
+                                  <widget class="GtkEntry" id="comboboxentry-entry7">
                                   </widget>
-                                  <packing>
-                                    <property name="type">label_item</property>
-                                  </packing>
                                 </child>
                               </widget>
                               <packing>
+                                <property name="left_attach">1</property>
                                 <property name="right_attach">2</property>
-                                <property name="top_attach">2</property>
-                                <property name="bottom_attach">3</property>
-                                <property name="x_options">GTK_FILL</property>
                               </packing>
                             </child>
-                          </widget>
-                        </child>
-                      </widget>
-                      <packing>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <widget class="GtkLabel" id="search.target.tab">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Search Target</property>
-                        <property name="justify">GTK_JUSTIFY_CENTER</property>
-                      </widget>
-                      <packing>
-                        <property name="type">tab</property>
-                        <property name="position">1</property>
-                        <property name="tab_fill">False</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <widget class="GtkFrame" id="frame.setting">
-                        <property name="visible">True</property>
-                        <property name="label_xalign">0</property>
-                        <property name="shadow_type">GTK_SHADOW_NONE</property>
-                        <child>
-                          <widget class="GtkVBox" id="vbox1124">
-                            <property name="visible">True</property>
-                            <property name="border_width">5</property>
                             <child>
-                              <widget class="GtkFrame" id="frame54">
+                              <widget class="GtkCheckButton" id="ignore.hidden.dirs">
                                 <property name="visible">True</property>
-                                <property name="border_width">3</property>
-                                <property name="label_xalign">0</property>
-                                <property name="shadow_type">GTK_SHADOW_NONE</property>
-                                <child>
-                                  <widget class="GtkCheckButton" id="search.basic">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="label" translatable="yes">Basic Search &amp; Replace</property>
-                                    <property name="use_underline">True</property>
-                                    <property name="response_id">0</property>
-                                    <property name="draw_indicator">True</property>
-                                    <signal name="toggled" handler="on_setting_basic_search_toggled"/>
-                                  </widget>
-                                </child>
+                                <property name="can_focus">True</property>
+                                <property name="label" translatable="yes">Ignore hidden directories</property>
+                                <property name="use_underline">True</property>
+                                <property name="response_id">0</property>
+                                <property name="draw_indicator">True</property>
                               </widget>
                               <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">False</property>
+                                <property name="top_attach">5</property>
+                                <property name="bottom_attach">6</property>
                               </packing>
                             </child>
                             <child>
-                              <widget class="GtkFrame" id="frame55">
+                              <widget class="GtkLabel" id="label35">
                                 <property name="visible">True</property>
-                                <property name="border_width">3</property>
-                                <property name="label_xalign">0</property>
-                                <property name="shadow_type">GTK_SHADOW_NONE</property>
-                                <child>
-                                  <widget class="GtkVBox" id="vbox1126">
-                                    <property name="visible">True</property>
-                                    <child>
-                                      <widget class="GtkHBox" id="hbox1126">
-                                        <property name="visible">True</property>
-                                        <property name="border_width">3</property>
-                                        <property name="spacing">3</property>
-                                        <child>
-                                          <widget class="GtkScrolledWindow" id="scrolledwindow27">
-                                            <property name="height_request">100</property>
-                                            <property name="visible">True</property>
-                                            <property name="can_focus">True</property>
-                                            <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-                                            <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-                                            <property name="shadow_type">GTK_SHADOW_IN</property>
-                                            <child>
-                                              <widget class="GtkTreeView" id="setting.pref.treeview">
-                                                <property name="visible">True</property>
-                                                <property name="can_focus">True</property>
-                                              </widget>
-                                            </child>
-                                          </widget>
-                                        </child>
-                                        <child>
-                                          <widget class="GtkVBox" id="vbox1125">
-                                            <property name="visible">True</property>
-                                            <child>
-                                              <widget class="GtkLabel" id="label12343">
-                                                <property name="visible">True</property>
-                                                <property name="xalign">0</property>
-                                                <property name="yalign">0</property>
-                                                <property name="label" translatable="yes">New Name:</property>
-                                              </widget>
-                                              <packing>
-                                                <property name="expand">False</property>
-                                                <property name="fill">False</property>
-                                                <property name="padding">5</property>
-                                              </packing>
-                                            </child>
-                                            <child>
-                                              <widget class="GtkEntry" id="setting.pref.entry">
-                                                <property name="visible">True</property>
-                                                <property name="can_focus">True</property>
-                                                <property name="invisible_char">*</property>
-                                              </widget>
-                                              <packing>
-                                                <property name="expand">False</property>
-                                                <property name="fill">False</property>
-                                                <property name="position">1</property>
-                                              </packing>
-                                            </child>
-                                          </widget>
-                                          <packing>
-                                            <property name="expand">False</property>
-                                            <property name="fill">False</property>
-                                            <property name="position">1</property>
-                                          </packing>
-                                        </child>
-                                      </widget>
-                                    </child>
-                                    <child>
-                                      <widget class="GtkHBox" id="hbox1129">
-                                        <property name="visible">True</property>
-                                        <property name="border_width">3</property>
-                                        <property name="spacing">10</property>
-                                        <property name="homogeneous">True</property>
-                                        <child>
-                                          <widget class="GtkButton" id="setting.pref.add">
-                                            <property name="visible">True</property>
-                                            <property name="can_focus">True</property>
-                                            <property name="can_default">True</property>
-                                            <property name="label">gtk-add</property>
-                                            <property name="use_stock">True</property>
-                                            <property name="response_id">0</property>
-                                            <signal name="clicked" handler="on_setting_pref_add_clicked"/>
-                                          </widget>
-                                        </child>
-                                        <child>
-                                          <widget class="GtkButton" id="setting.pref.remove">
-                                            <property name="visible">True</property>
-                                            <property name="can_focus">True</property>
-                                            <property name="can_default">True</property>
-                                            <property name="label">gtk-remove</property>
-                                            <property name="use_stock">True</property>
-                                            <property name="response_id">0</property>
-                                            <signal name="clicked" handler="on_setting_pref_remove_clicked"/>
-                                          </widget>
-                                          <packing>
-                                            <property name="position">1</property>
-                                          </packing>
-                                        </child>
-                                        <child>
-                                          <widget class="GtkButton" id="setting.pref.modify">
-                                            <property name="visible">True</property>
-                                            <property name="can_focus">True</property>
-                                            <property name="can_default">True</property>
-                                            <property name="label" translatable="yes">Modify</property>
-                                            <property name="use_underline">True</property>
-                                            <property name="response_id">0</property>
-                                            <signal name="clicked" handler="on_setting_pref_modify_clicked"/>
-                                          </widget>
-                                          <packing>
-                                            <property name="position">2</property>
-                                          </packing>
-                                        </child>
-                                      </widget>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="fill">False</property>
-                                        <property name="position">1</property>
-                                      </packing>
-                                    </child>
-                                  </widget>
-                                </child>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">and/or not named like:</property>
+                              </widget>
+                              <packing>
+                                <property name="top_attach">4</property>
+                                <property name="bottom_attach">5</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkLabel" id="label34">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">In project directories like:</property>
+                              </widget>
+                              <packing>
+                                <property name="top_attach">3</property>
+                                <property name="bottom_attach">4</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkCheckButton" id="ignore.hidden.files">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="label" translatable="yes">Ignore _hidden files</property>
+                                <property name="use_underline">True</property>
+                                <property name="response_id">0</property>
+                                <property name="draw_indicator">True</property>
                               </widget>
                               <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">False</property>
-                                <property name="position">1</property>
+                                <property name="top_attach">2</property>
+                                <property name="bottom_attach">3</property>
                               </packing>
                             </child>
+                            <child>
+                              <widget class="GtkLabel" id="label33">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">and/or not named like:</property>
+                              </widget>
+                              <packing>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkLabel" id="label32">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Files named like:</property>
+                              </widget>
+                            </child>
                           </widget>
                         </child>
+                        <child>
+                          <placeholder/>
+                          <packing>
+                            <property name="type">label_item</property>
+                          </packing>
+                        </child>
                       </widget>
                       <packing>
                         <property name="position">2</property>
                       </packing>
                     </child>
                     <child>
-                      <widget class="GtkLabel" id="label12342">
+                      <widget class="GtkHBox" id="hbox6">
                         <property name="visible">True</property>
-                        <property name="label" translatable="yes">Setting</property>
+                        <property name="border_width">5</property>
+                        <property name="spacing">5</property>
+                        <child>
+                          <widget class="GtkRadioButton" id="actions.no_limit">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="label" translatable="yes">_All</property>
+                            <property name="use_underline">True</property>
+                            <property name="response_id">0</property>
+                            <property name="draw_indicator">True</property>
+                            <signal name="toggled" handler="on_search_actions_no_limit_toggled"/>
+                          </widget>
+                        </child>
+                        <child>
+                          <widget class="GtkRadioButton" id="actions.limit">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="label" translatable="yes">S_top after</property>
+                            <property name="use_underline">True</property>
+                            <property name="response_id">0</property>
+                            <property name="draw_indicator">True</property>
+                            <property name="group">actions.no_limit</property>
+                          </widget>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkSpinButton" id="actions.max">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="adjustment">100 1 200 1 10 10</property>
+                            <property name="climb_rate">1</property>
+                          </widget>
+                          <packing>
+                            <property name="fill">False</property>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
                       </widget>
                       <packing>
-                        <property name="type">tab</property>
-                        <property name="position">2</property>
-                        <property name="tab_fill">False</property>
+                        <property name="position">3</property>
                       </packing>
                     </child>
                   </widget>
                 </child>
+                <child>
+                  <widget class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Scope:&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="type">label_item</property>
+                  </packing>
+                </child>
               </widget>
+              <packing>
+                <property name="position">3</property>
+              </packing>
             </child>
             <child>
-              <widget class="GtkHButtonBox" id="hbuttonbox7">
+              <widget class="GtkHSeparator" id="hseparator1">
+                <property name="visible">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">4</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHButtonBox" id="hbuttonbox1">
                 <property name="visible">True</property>
                 <property name="border_width">3</property>
-                <property name="spacing">4</property>
+                <property name="spacing">3</property>
                 <property name="layout_style">GTK_BUTTONBOX_END</property>
                 <child>
                   <widget class="GtkButton" id="button.close">
@@ -1048,6 +616,10 @@
                     <property name="response_id">0</property>
                     <signal name="clicked" handler="on_search_button_close_clicked"/>
                   </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
                 </child>
                 <child>
                   <widget class="GtkButton" id="button.stop">
@@ -1060,40 +632,46 @@
                     <signal name="clicked" handler="on_search_button_stop_clicked"/>
                   </widget>
                   <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
                     <property name="position">1</property>
                   </packing>
                 </child>
                 <child>
-                  <widget class="GtkButton" id="button.next">
+                  <widget class="GtkButton" id="button.replace">
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="can_default">True</property>
-                    <property name="label">gtk-find</property>
+                    <property name="label">gtk-find-and-replace</property>
                     <property name="use_stock">True</property>
                     <property name="response_id">0</property>
-                    <signal name="clicked" handler="on_search_button_next_clicked"/>
+                    <signal name="clicked" handler="on_search_button_replace_clicked"/>
                   </widget>
                   <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
                     <property name="position">2</property>
                   </packing>
                 </child>
                 <child>
-                  <widget class="GtkButton" id="button.jump">
+                  <widget class="GtkButton" id="button.start">
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="can_default">True</property>
                     <property name="label">gtk-find</property>
                     <property name="use_stock">True</property>
                     <property name="response_id">0</property>
-                    <signal name="clicked" handler="on_search_button_jump_clicked"/>
+                    <signal name="clicked" handler="on_search_button_start_clicked"/>
                   </widget>
                   <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
                     <property name="position">3</property>
                   </packing>
                 </child>
               </widget>
               <packing>
-                <property name="position">1</property>
+                <property name="position">5</property>
               </packing>
             </child>
           </widget>

Modified: trunk/plugins/search/anjuta-search.ui
==============================================================================
--- trunk/plugins/search/anjuta-search.ui	(original)
+++ trunk/plugins/search/anjuta-search.ui	Fri Apr 11 00:19:38 2008
@@ -3,7 +3,7 @@
 	<menubar name="MenuMain">
 		<menu name="MenuEdit" action="ActionMenuEdit">
 			<placeholder name="PlaceholderEditMenus">
-			<placeholder name="PlaceholderEditSearchMenus">			
+			<placeholder name="PlaceholderEditSearchMenus">
 			<menu name="Search" action="ActionMenuEditSearch">
 				<placeholder name="PlaceholderQuickSearchMenu" />
 				<menuitem name="Find" action="ActionEditSearchFind"/>
@@ -11,17 +11,20 @@
 				<menuitem name="FindPrevious" action="ActionEditSearchFindPrevious"/>
 				<menuitem name="Replace" action="ActionEditSearchReplace"/>
 				<menuitem name="FindInFiles" action="ActionEditSearchInFiles"/>
-			</menu>
+				<menuitem name="Repeat" action="ActionEditSearchAgain"/>
+ 			</menu>
 			</placeholder>
 			</placeholder>
 		</menu>
-		<placeholder name="PlaceholderGotoMenus">
-		<menu name="Goto" action="ActionMenuGoto">
-			<placeholder name="PlaceholderGotoOccurence">
-				<menuitem name="PreviousOccurance" action="ActionEditGotoOccurancePrev" />
-				<menuitem name="NextOccurance" action="ActionEditGotoOccuranceNext" />
-			</placeholder>
-		</menu>
-		</placeholder>
 	</menubar>
+	<popup name="PopupDocumentManager">
+		<placeholder name="PlaceholderFindUsage">
+			<menuitem name="ListAllUsage" action="ActionEditSearchUseInFiles" />
+		</placeholder>
+	</popup>
+	<popup name="DetachedPopupDocumentManager">
+		<placeholder name="PlaceholderFindUsage">
+			<menuitem name="ListAllUsage" action="ActionEditSearchUseInFiles" />
+		</placeholder>
+	</popup>
 </ui>

Modified: trunk/plugins/search/plugin.c
==============================================================================
--- trunk/plugins/search/plugin.c	(original)
+++ trunk/plugins/search/plugin.c	Fri Apr 11 00:19:38 2008
@@ -1,22 +1,23 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
-    plugin.c
-    Copyright (C) 2000 Naba Kumar
-
-    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 2 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, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-*/
+ * plugin.c
+ * Copyright (C) 2000-2007 Naba Kumar <naba gnome org>
+ *
+ * This file is part of anjuta.
+ * Anjuta 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 2 of the License, or
+ * at your option) any later version.
+ *
+ * Anjuta 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 anjuta; if not, contact the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
 
 #include <libanjuta/interfaces/ianjuta-editor.h>
 #include <libanjuta/interfaces/ianjuta-editor-selection.h>
@@ -32,205 +33,280 @@
 #define UI_FILE PACKAGE_DATA_DIR"/ui/anjuta-search.ui"
 #define ICON_FILE "anjuta-search-plugin-48.png"
 
-#define ANJUTA_PIXMAP_MATCH_NEXT				  "anjuta-go-match-next"
-#define ANJUTA_PIXMAP_MATCH_PREV				  "anjuta-go-match-prev"
-#define ANJUTA_STOCK_MATCH_NEXT				  "anjuta-match-next"
-#define ANJUTA_STOCK_MATCH_PREV				  "anjuta-match-prev"
-
-/* Find next occurence of expression in Editor
-   Caching of FileBuffer might be useful here to improve performance
-   Returns: TRUE = found, FALSE = not found
-*/
+#define ANJUTA_PIXMAP_MATCH_NEXT	"anjuta-go-match-next"
+#define ANJUTA_PIXMAP_MATCH_PREV	"anjuta-go-match-prev"
+#define ANJUTA_STOCK_MATCH_NEXT		"anjuta-match-next"
+#define ANJUTA_STOCK_MATCH_PREV		"anjuta-match-prev"
 
-static gboolean find_incremental(IAnjutaEditor* te, gchar* expression, 
-								 SearchDirection dir)
-{
-	FileBuffer* fb = file_buffer_new_from_te (te);
-	SearchExpression* se = g_new0(SearchExpression, 1);
-	MatchInfo* info;
-	gboolean ret;
-		
-	se->search_str = expression;
-	se->regex = FALSE;
-	se->greedy = FALSE;
-	se->ignore_case = TRUE;
-	se->whole_word = FALSE;
-	se->whole_line = FALSE;
-	se->word_start = FALSE;
-	se->no_limit = FALSE;
-	se->actions_max = 1;
-	se->re = NULL;
-
-	info = get_next_match(fb, dir, se);
-	
-	if (info != NULL)
-	{
-		IAnjutaIterable *start, *end;
-		start = ianjuta_editor_get_position_from_offset (te, info->pos, NULL);
-		end = ianjuta_editor_get_position_from_offset (te, info->pos + info->len, NULL);
-		ianjuta_editor_selection_set (IANJUTA_EDITOR_SELECTION (te),
-									  start, end, NULL);
-		g_object_unref (start);
-		g_object_unref (end);
-		ret = TRUE;
-	}
-	else
-		ret = FALSE;
-	
-	match_info_free(info);
-	file_buffer_free(fb);
-	g_free(se);
-	
-	return ret;
-}
+static gpointer parent_class;
 
+/* user_data for all actions is AnjutaPlugin *plugin */
 static void
-on_find1_activate (GtkAction * action, gpointer user_data)
+on_find1_activate (GtkAction *action, gpointer user_data)
 {
-	anjuta_search_replace_activate(FALSE, FALSE);
+	/* FIXME get sg data from somewhere not static
+	SearchPlugin *plugin;
+	SearchReplaceGUI *sg;
+
+	plugin = ANJUTA_PLUGIN_SEARCH (user_data);
+	sg = plugin->dialog_data;
+	anj_sr_activate (sg, FALSE, FALSE);
+*/
+	anj_sr_activate (FALSE, FALSE);
 }
 
 static void
-on_find_and_replace1_activate (GtkAction * action, gpointer user_data)
+on_find_and_replace1_activate (GtkAction *action, gpointer user_data)
 {
-	anjuta_search_replace_activate(TRUE, FALSE);
+	/* FIXME get sg data from somewhere not static
+	SearchPlugin *plugin;
+	SearchReplaceGUI *sg;
+
+	plugin = ANJUTA_PLUGIN_SEARCH (user_data);
+	sg = plugin->dialog_data;
+	anj_sr_activate (sg, TRUE, FALSE);
+*/
+	anj_sr_activate (TRUE, FALSE);
 }
 
 static void
-on_find_in_files1_activate (GtkAction * action, gpointer user_data)
+on_find_in_files1_activate (GtkAction *action, gpointer user_data)
 {
-	anjuta_search_replace_activate(FALSE, TRUE);
+	/* FIXME get sg data from somewhere not static
+	SearchPlugin *plugin;
+	SearchReplaceGUI *sg;
+
+	plugin = ANJUTA_PLUGIN_SEARCH (user_data);
+	sg = plugin->dialog_data;
+	anj_sr_activate (sg, FALSE, TRUE);
+*/
+	anj_sr_activate (FALSE, TRUE);
 }
 
-/*  *user_data : TRUE=Forward  False=Backward  */
 static void
-on_findnext1_activate (GtkAction * action, gpointer user_data)
+on_findnext1_activate (GtkAction *action, gpointer user_data)
 {
-	search_replace_next();
+	/* FIXME get sg data from somewhere not static
+	SearchPlugin *plugin;
+	SearchReplaceGUI *sg;
+
+	plugin = ANJUTA_PLUGIN_SEARCH (user_data);
+	sg = plugin->dialog_data;
+*/
+	SearchReplaceGUI *sg;
+
+	anj_sr_get_best_uidata (&sg, NULL);
+	anj_sr_select_next (sg);
 }
 
 static void
-on_findprevious1_activate (GtkAction * action, gpointer user_data)
+on_findprevious1_activate (GtkAction *action, gpointer user_data)
 {
-	search_replace_previous();
-}
+	/* FIXME get sg data from somewhere not static
+	SearchPlugin *plugin;
+	SearchReplaceGUI *sg;
 
+	plugin = ANJUTA_PLUGIN_SEARCH (user_data);
+	sg = plugin->dialog_data;
+*/
+	SearchReplaceGUI *sg;
+
+	anj_sr_get_best_uidata (&sg, NULL);
+	anj_sr_select_previous (sg);
+}
+/* this is not a duplicate of on_findprevious1_activate(). That re-uses the
+  pattern from the last search via the search dialog
+  CHECKME is this available in UI ?
 static void
-on_prev_occur(GtkAction * action, gpointer user_data)
+on_prev_occur (GtkAction *action, gpointer user_data)
 {
-	IAnjutaEditor* te;
-	IAnjutaDocumentManager *docman;
-	IAnjutaDocument* doc;
 	SearchPlugin *plugin;
-    gint return_;
-	gchar *buffer = NULL;
-	
+	IAnjutaDocumentManager *docman;
+	IAnjutaDocument *doc;
+
 	plugin = ANJUTA_PLUGIN_SEARCH (user_data);
 	docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
 										IAnjutaDocumentManager, NULL);
-	doc = ianjuta_document_manager_get_current_document(docman, NULL);
-	te = IANJUTA_IS_EDITOR(doc) ? IANJUTA_EDITOR(doc) : NULL;
-	if(!te) return;
-	if ((buffer = ianjuta_editor_selection_get (IANJUTA_EDITOR_SELECTION (te), NULL)))
+	doc = ianjuta_document_manager_get_current_document (docman, NULL);
+	if (IANJUTA_IS_EDITOR (doc))
 	{
-		g_strstrip(buffer);
-		if ('\0' == *buffer)
+		IAnjutaEditor *te;
+		gchar *buffer;
+
+		te = IANJUTA_EDITOR (doc);
+		buffer = ianjuta_editor_selection_get (IANJUTA_EDITOR_SELECTION (te), NULL);
+		if (buffer != NULL)
+		{
+			g_strstrip (buffer);
+			if (*buffer == 0)
+			{
+				g_free (buffer);
+				buffer = NULL;
+			}
+		}
+		if (buffer == NULL)
+			buffer = ianjuta_editor_get_current_word (te, NULL);
+		if (buffer != NULL)
 		{
-			g_free(buffer);
-			buffer = NULL;
+		    search_incremental (te, buffer, SD_BACKWARD);
+			g_free (buffer);
 		}
 	}
-	if (NULL == buffer)
+}
+*/
+/* this is not a duplicate of on_findnext1_activate(). That re-uses the
+  pattern from the last search via the search dialog.
+  CHECKME is this available in UI ?
+static void
+on_next_occur (GtkAction *action, gpointer user_data)
+{
+	SearchPlugin *plugin;
+	IAnjutaDocumentManager *docman;
+	IAnjutaDocument *doc;
+
+	plugin = ANJUTA_PLUGIN_SEARCH (user_data);
+	docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
+										IAnjutaDocumentManager, NULL);
+	doc = ianjuta_document_manager_get_current_document (docman, NULL);
+	if (IANJUTA_IS_EDITOR (doc))
 	{
-		buffer = ianjuta_editor_get_current_word(te, NULL);
-		if (!buffer)
-			return;
+		IAnjutaEditor *te;
+		gchar *buffer;
+
+		te = IANJUTA_EDITOR (doc);
+		buffer = ianjuta_editor_selection_get (IANJUTA_EDITOR_SELECTION (te), NULL);
+		if (buffer != NULL)
+		{
+			g_strstrip (buffer);
+			if (*buffer == 0)
+			{
+				g_free (buffer);
+				buffer = NULL;
+			}
+		}
+		if (buffer == NULL)
+			buffer = ianjuta_editor_get_current_word (te, NULL);
+		if (buffer != NULL)
+		{
+		    search_incremental (te, buffer, SD_FORWARD);
+			g_free (buffer);
+		}
 	}
-    return_= find_incremental(te, buffer, SD_BACKWARD);
-	
-	g_free(buffer);
 }
+*/
 
-static void 
-on_next_occur(GtkAction * action, gpointer user_data)
+static void
+on_search_again_activate (GtkAction *action, gpointer user_data)
+{
+	/* FIXME get sg data from somewhere not static
+	SearchPlugin *plugin;
+	SearchReplaceGUI *sg;
+
+	plugin = ANJUTA_PLUGIN_SEARCH (user_data);
+	sg = plugin->dialog_data;
+*/
+	SearchReplaceGUI *sg;
+
+	sg = anj_sr_get_default_uidata ();
+	anj_sr_repeat (sg);
+}
+
+static void
+on_find_usage (GtkAction *action, gpointer user_data)
 {
-	IAnjutaEditor* te;
-	IAnjutaDocumentManager *docman;
-	IAnjutaDocument* doc;
 	SearchPlugin *plugin;
-    gint return_;
-	gchar *buffer = NULL;
-	
+	IAnjutaDocumentManager *docman;
+	IAnjutaDocument *doc;
+
 	plugin = ANJUTA_PLUGIN_SEARCH (user_data);
 	docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
 										IAnjutaDocumentManager, NULL);
-	doc = ianjuta_document_manager_get_current_document(docman, NULL);
-	te = IANJUTA_IS_EDITOR(doc) ? IANJUTA_EDITOR(doc) : NULL;
-	if(!te) return;
-	if ((buffer = ianjuta_editor_selection_get (IANJUTA_EDITOR_SELECTION (te), NULL)))
+	doc = ianjuta_document_manager_get_current_document (docman, NULL);
+	if (IANJUTA_IS_EDITOR (doc))
 	{
-		g_strstrip(buffer);
-		if ('\0' == *buffer)
+		IAnjutaEditor *te;
+		gchar *buffer;
+
+		te = IANJUTA_EDITOR (doc);
+		buffer = ianjuta_editor_selection_get (IANJUTA_EDITOR_SELECTION (te), NULL);
+		if (buffer != NULL)
 		{
-			g_free(buffer);
-			buffer = NULL;
+			g_strstrip (buffer);
+			if (*buffer == 0)
+			{
+				g_free (buffer);
+				buffer = NULL;
+			}
+		}
+		if (buffer == NULL)
+			buffer = ianjuta_editor_get_current_word (te, NULL);
+		if (buffer != NULL)
+		{
+			anj_sr_list_all_uses (buffer);
+			g_free (buffer);
 		}
 	}
-	if (NULL == buffer)
-	{
-		buffer = ianjuta_editor_get_current_word(te, NULL);
-		if (!buffer)
-			return;
-	}
-    return_= find_incremental(te, buffer, SD_FORWARD);
-	
-	g_free(buffer);
 }
 
-static GtkActionEntry actions_search[] = {
+static GtkActionEntry actions_search[] =
+{
   { "ActionMenuEditSearch", NULL, N_("_Search"), NULL, NULL, NULL},
   { "ActionEditSearchFind", GTK_STOCK_FIND, N_("_Find..."), "<control><alt>f",
 	N_("Search for a string or regular expression in the editor"),
     G_CALLBACK (on_find1_activate)},
-  { "ActionEditSearchFindNext", GTK_STOCK_FIND, N_("Find _Next"), "<control>g",
-	N_("Repeat the last Find command"),
+  { "ActionEditSearchFindNext", ANJUTA_STOCK_MATCH_NEXT, N_("Find _Next"), "<control>g",
+	N_("Find next match using the last-used search parameters"),
     G_CALLBACK (on_findnext1_activate)},
-  { "ActionEditSearchFindPrevious", GTK_STOCK_FIND, N_("Find _Previous"),
+  { "ActionEditSearchFindPrevious", ANJUTA_STOCK_MATCH_PREV, N_("Find _Previous"),
 	"<control><shift>g",
-	N_("Repeat the last Find command"),
+	N_("Find previous match using the last-used search parameters"),
 	G_CALLBACK (on_findprevious1_activate)},
   { "ActionEditSearchReplace", GTK_STOCK_FIND_AND_REPLACE, N_("Find and R_eplace..."),
 	"<control>h",
-	N_("Search for and replace a string or regular expression with another string"),
+	N_("Search for a string or regular expression and replace with another string"),
     G_CALLBACK (on_find_and_replace1_activate)},
-  { "ActionEditAdvancedSearch", GTK_STOCK_FIND, N_("Search and Replace"),
-	NULL, N_("Search and Replace"),
+  { "ActionEditSearchAgain", NULL, N_("Search/Replace _Again"),	"<shift><control><alt>f",
+	N_("Repeat last-used find or replace operation"),
+    G_CALLBACK (on_search_again_activate)},
+/*  { "ActionEditAdvancedSearch", GTK_STOCK_FIND, N_("Advanced Search And Replace"),
+	NULL, N_("New advance search and replace stuff"),
 	G_CALLBACK (on_find1_activate)},
+*/
   { "ActionEditSearchInFiles", NULL, N_("Fin_d in Files..."), NULL,
 	N_("Search for a string in multiple files or directories"),
     G_CALLBACK (on_find_in_files1_activate)},
-	{ "ActionEditGotoOccuranceNext", ANJUTA_STOCK_MATCH_NEXT,
+  { "ActionEditSearchUseInFiles", NULL, N_("List all matches"), NULL,
+	N_("List occurrences of current selection or word in all project files"),
+    G_CALLBACK (on_find_usage)},
+/* effectively superseded by search-box
+  { "ActionEditGotoOccuranceNext", ANJUTA_STOCK_MATCH_NEXT,
 	N_("Ne_xt Occurrence"), NULL,
 	N_("Find the next occurrence of current word"),
     G_CALLBACK (on_next_occur)},
-  { "ActionEditGotoOccurancePrev",ANJUTA_STOCK_MATCH_PREV,
+  { "ActionEditGotoOccurancePrev", ANJUTA_STOCK_MATCH_PREV,
 	N_("Pre_vious Occurrence"),  NULL,
 	N_("Find the previous occurrence of current word"),
     G_CALLBACK (on_prev_occur)},
+ extract from .ui file to enable the above
+		<placeholder name="PlaceholderGotoMenus">
+		<menu name="Goto" action="ActionMenuGoto">
+			<placeholder name="PlaceholderGotoOccurence">
+				<menuitem name="PreviousOccurance" action="ActionEditGotoOccurancePrev" />
+				<menuitem name="NextOccurance" action="ActionEditGotoOccuranceNext" />
+			</placeholder>
+		</menu>
+		</placeholder>
+*/
 };
 
-gpointer parent_class;
-
 static gboolean
 activate_plugin (AnjutaPlugin *plugin)
 {
 	static gboolean init = FALSE;
 	AnjutaUI *ui;
-	SearchPlugin* splugin = ANJUTA_PLUGIN_SEARCH (plugin);
-	IAnjutaDocumentManager* docman = anjuta_shell_get_interface(ANJUTA_PLUGIN(plugin)->shell,
-																IAnjutaDocumentManager, NULL);
-	
-	
+	SearchPlugin *splugin;
+	IAnjutaDocumentManager *docman;
+
 	if (!init)
 	{
 		BEGIN_REGISTER_ICON (plugin);
@@ -239,7 +315,7 @@
 		END_REGISTER_ICON;
 		init = TRUE;
 	}
-	
+
 	ui = anjuta_shell_get_ui (plugin->shell, NULL);
 	anjuta_ui_add_action_group_entries (ui, "ActionGroupSearch",
 					_("Searching..."),
@@ -247,18 +323,26 @@
 					G_N_ELEMENTS (actions_search),
 					GETTEXT_PACKAGE, TRUE, plugin);
 
-	
+	splugin = ANJUTA_PLUGIN_SEARCH (plugin);
 	splugin->uiid = anjuta_ui_merge (ui, UI_FILE);
+	docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
+										IAnjutaDocumentManager,
+										NULL);
 	splugin->docman = docman;
-	search_and_replace_init(docman);
-	
+
+	search_replace_init (plugin);
+
 	return TRUE;
 }
 
 static gboolean
 deactivate_plugin (AnjutaPlugin *plugin)
 {
-	
+	SearchReplaceGUI *sg;
+
+	sg = anj_sr_get_default_uidata (); /* CHECKME if > 1 dialog */
+	anj_sr_destroy_ui_data (sg);
+	search_replace_data_destroy (NULL);
 	return TRUE;
 }
 
@@ -266,16 +350,8 @@
 dispose (GObject *obj)
 {
 	//SearchPlugin *plugin = ANJUTA_PLUGIN_SEARCH (obj);
-	
-	G_OBJECT_CLASS (parent_class)->dispose (obj);
-}
 
-static void
-finalize (GObject *obj)
-{
-	//SearchPlugin *plugin = ANJUTA_PLUGIN_SEARCH (obj);
-	
-	G_OBJECT_CLASS (parent_class)->finalize (obj);
+	GNOME_CALL_PARENT (G_OBJECT_CLASS, dispose, (obj));
 }
 
 static void
@@ -285,17 +361,20 @@
 }
 
 static void
-search_plugin_class_init (GObjectClass *klass) 
+search_plugin_class_init (GObjectClass *klass)
 {
-	AnjutaPluginClass *plugin_class = ANJUTA_PLUGIN_CLASS (klass);
+	AnjutaPluginClass *plugin_class;
 
 	parent_class = g_type_class_peek_parent (klass);
 
+	plugin_class = ANJUTA_PLUGIN_CLASS (klass);
 	plugin_class->activate = activate_plugin;
 	plugin_class->deactivate = deactivate_plugin;
 	klass->dispose = dispose;
-	klass->finalize = finalize;
 }
+
+#undef ICON_FILE
+
 ANJUTA_PLUGIN_BEGIN (SearchPlugin, search_plugin);
 ANJUTA_PLUGIN_END;
 ANJUTA_SIMPLE_PLUGIN (SearchPlugin, search_plugin);

Modified: trunk/plugins/search/plugin.h
==============================================================================
--- trunk/plugins/search/plugin.h	(original)
+++ trunk/plugins/search/plugin.h	Fri Apr 11 00:19:38 2008
@@ -1,20 +1,27 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
- * This program is free software; you can redistribute it and/or modify
+ * plugin.h
+ * Copyright (C) 2000-2007 Naba Kumar <naba gnome org>
+ *
+ * This file is part of anjuta.
+ * Anjuta 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 2 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
+ * at your option) any later version.
+ *
+ * Anjuta 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 Library General Public License for more details.
- * 
+ * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with anjuta; if not, contact the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
- 
- 
+
+#ifndef _SEARCH_PLUGIN_H
+#define _SEARCH_PLUGIN_H
+
 #include <libanjuta/anjuta-plugin.h>
 #include <libanjuta/anjuta-preferences.h>
 #include <libanjuta/anjuta-ui.h>
@@ -32,13 +39,18 @@
 typedef struct _SearchPlugin SearchPlugin;
 typedef struct _SearchPluginClass SearchPluginClass;
 
-struct _SearchPlugin{
+struct _SearchPlugin
+{
 	AnjutaPlugin parent;
-	
+
 	gint uiid;
-	IAnjutaDocumentManager* docman;
+	IAnjutaDocumentManager *docman;
+	/*SearchReplaceGUI *dialog_data;*/
 };
 
-struct _SearchPluginClass{
+struct _SearchPluginClass
+{
 	AnjutaPluginClass parent_class;
 };
+
+#endif /* ndef _SEARCH_PLUGIN_H */

Modified: trunk/plugins/search/search-replace.c
==============================================================================
--- trunk/plugins/search/search-replace.c	(original)
+++ trunk/plugins/search/search-replace.c	Fri Apr 11 00:19:38 2008
@@ -1,10 +1,24 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
-
 /*
-** search-replace.c: Generic Search and Replace
-** Author: Biswapesh Chattopadhyay
-*/
-
+ * search-replace.c: Generic Search and Replace
+ * Copyright (C) 2004 Biswapesh Chattopadhyay
+ * Copyright (C) 2004-2008 Naba Kumar  <naba gnome org>
+ *
+ * This file is part of anjuta.
+ * Anjuta 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 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Anjuta 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 anjuta. If not, contact the Free Software Foundation,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -31,648 +45,1159 @@
 #include <libanjuta/interfaces/ianjuta-message-manager.h>
 #include <libanjuta/interfaces/ianjuta-message-view.h>
 #include <libanjuta/interfaces/ianjuta-editor.h>
+#include <libanjuta/interfaces/ianjuta-editor-search.h>
 #include <libanjuta/interfaces/ianjuta-editor-selection.h>
 #include <libanjuta/interfaces/ianjuta-markable.h>
 #include <libanjuta/interfaces/ianjuta-bookmark.h>
 #include <libanjuta/interfaces/ianjuta-indicable.h>
+#include <libanjuta/interfaces/ianjuta-file-savable.h>
 
-#include "search-replace_backend.h"
 #include "search-replace.h"
-#include "search_preferences.h"
 
 #include <libanjuta/interfaces/ianjuta-project-manager.h>
 #include <glib/gi18n.h>
 
 #define GLADE_FILE_SEARCH_REPLACE PACKAGE_DATA_DIR"/glade/anjuta-search.glade"
+/* some checks involve label text, this needs to conform to the tab label set
+   via glade (not currently translateable or translated) */
+#define GLADE_PREFS_TITLE "Parameters"
+#define SEARCH_GUI_KEY "_anj_sr_guidata_"
+#define MAX_ITEMS_SEARCH_COMBO 16
+/* limit on search-string length */
+#define MAX_LENGTH_SEARCH 128
 
-/* LibGlade's auto-signal-connect will connect to these signals.
- * Do not declare them static.
- */
-gboolean
-on_search_dialog_key_press_event(GtkWidget *widget, GdkEventKey *event,
-                               gpointer user_data);
-void on_search_match_whole_word_toggled (GtkToggleButton *togglebutton, 
-					 gpointer user_data);
-void on_search_match_whole_line_toggled (GtkToggleButton *togglebutton,
-					 gpointer user_data);
-void on_search_match_word_start_toggled (GtkToggleButton *togglebutton,
-					 gpointer user_data);
-gboolean on_search_replace_delete_event(GtkWidget *window, GdkEvent *event,
-					gboolean user_data);
-void on_replace_regex_toggled (GtkToggleButton *togglebutton, gpointer user_data);
-void on_search_regex_toggled (GtkToggleButton *togglebutton, gpointer user_data);
-void on_search_action_changed (GtkComboBox *combo, gpointer user_data);
-void on_search_target_changed(GtkComboBox *combo, gpointer user_data);
-void on_search_expression_changed(GtkComboBox *combo, gpointer user_data);
-void on_actions_no_limit_clicked(GtkButton *button, gpointer user_data);
-void on_search_button_close_clicked(GtkButton *button, gpointer user_data);
-void on_search_button_close_clicked(GtkButton *button, gpointer user_data);
-void on_search_button_help_clicked(GtkButton *button, gpointer user_data);
-void on_search_button_next_clicked(GtkButton *button, gpointer user_data);
-void on_search_button_jump_clicked(GtkButton *button, gpointer user_data);
-void on_search_expression_activate (GtkEditable *edit, gpointer user_data);
-void on_search_button_save_clicked(GtkButton *button, gpointer user_data);
-void on_search_button_stop_clicked(GtkButton *button, gpointer user_data);
-
-void on_search_direction_changed (GtkComboBox *combo, gpointer user_data);
-void on_search_full_buffer_toggled (GtkToggleButton *togglebutton, 
-									gpointer user_data);
-void on_search_forward_toggled (GtkToggleButton *togglebutton, 
-									gpointer user_data);
-void on_search_backward_toggled (GtkToggleButton *togglebutton, 
-									gpointer user_data);
-void on_setting_basic_search_toggled (GtkToggleButton *togglebutton, 
-									  gpointer user_data);
-
-/* GUI dropdown option strings */
-AnjutaUtilStringMap search_direction_strings[] = {
-/* the order of these matters - it must match the order of the corresponding
-   radio buttons on another page */
-	{SD_BEGINNING, N_("Full Buffer")},
-	{SD_FORWARD, N_("Forward")},
-	{SD_BACKWARD, N_("Backward")},
-	{-1, NULL}
-};
+static SearchReplaceGUI *def_sg;
 
-AnjutaUtilStringMap search_target_strings[] = {
-	{SR_BUFFER, N_("Current Buffer")},
-	{SR_SELECTION, N_("Current Selection")},
-	{SR_BLOCK, N_("Current Block")},
-	{SR_FUNCTION, N_("Current Function")},
-	{SR_OPEN_BUFFERS, N_("All Open Buffers")},
-	{SR_PROJECT, N_("All Project Files")},
-/*	{SR_VARIABLE, N_("Specify File List")},*/
-	{SR_FILES, N_("Specify File Patterns")},
+/* translated button labels */
+static const gchar *button_search_label;
+static const gchar *button_replace_label;
+static const gchar *button_replace_all_label;
+
+AnjutaUtilStringMap search_target_strings[] =
+{
+	{SR_BUFFER, N_("Current file")},
+	{SR_SELECTION, N_("Current selection")},
+	{SR_BLOCK, N_("Current block")},
+	{SR_FUNCTION, N_("Current function")},
+	{SR_OPEN_BUFFERS, N_("All open files")},
+	{SR_PROJECT, N_("All project files")},
+/*	CHECKME is this for the "variable" widget in the glade UI ?
+	{SR_VARIABLE, N_("These files ...")}, */
+	{SR_FILES, N_("Files like these ...")},
 	{-1, NULL}
 };
 
-AnjutaUtilStringMap search_action_strings[] = {
-	{SA_SELECT, N_("Select next match")},
+AnjutaUtilStringMap search_action_strings[] =
+{
+	{SA_SELECT, N_("Select nearest match")},
 	{SA_BOOKMARK, N_("Bookmark all matched lines")},
 	{SA_HIGHLIGHT, N_("Mark all matches")},
+	{SA_UNLIGHT, N_("Clear all match-marks")},
 	{SA_FIND_PANE, N_("List matches in find pane")},
-	{SA_REPLACE, N_("Replace next match")},
+	{SA_REPLACE, N_("Replace interactively")},
 	{SA_REPLACEALL, N_("Replace all matches")},
 	{-1, NULL}
 };
 
-
-typedef struct _SearchReplaceGUI
+static GUIElement glade_widgets[] =
 {
-	GladeXML *xml;
-	GtkWidget *dialog;
-	gboolean showing;
-} SearchReplaceGUI;
-
-
-static GladeWidget glade_widgets[] = {
 	/* CLOSE_BUTTON */
-	{GE_BUTTON, "button.close", NULL, NULL},
+ 	{GE_BUTTON, "button.close", NULL},
 	/* STOP_BUTTON */
-	{GE_BUTTON, "button.stop", NULL, NULL},
+	{GE_BUTTON, "button.stop", NULL},
+	/* REPLACE_BUTTON */
+	{GE_BUTTON, "button.replace", NULL},
 	/* SEARCH_BUTTON */
-	{GE_BUTTON, "button.next", NULL, NULL},
-	/* JUMP_BUTTON */
-	{GE_BUTTON, "button.jump", NULL, NULL},
-	/* SEARCH_NOTEBOOK */
-	{GE_NONE, "search.notebook", NULL, NULL},
-	/* SEARCH_EXPR_FRAME */
-	{GE_NONE, "frame.search.expression", NULL, NULL},
-	/* SEARCH_TARGET_FRAME */
-	{GE_NONE, "frame.search.target", NULL, NULL},
-	/* SEARCH_VAR_FRAME */
-	{GE_NONE, "frame.search.var", NULL, NULL},
+	{GE_BUTTON, "button.start", NULL},
+#if 0
+	/* LOG_SRCH_BUTTON */
+	{GE_BUTTON, "button.log.search", NULL},
+	/* LOG_REPL_BUTTON */
+	{GE_BUTTON, "button.log.replace", NULL},
+#endif
+	
 	/* FILE_FILTER_FRAME */
-	{GE_NONE, "frame.file.filter", NULL, NULL},
-	/* FRAME_SEARCH_BASIC */
-	{GE_NONE, "frame.search.basic", NULL, NULL},
+	{GE_NONE, "frame.file.filter", NULL},
+	/* SEARCH_SCOPE_FRAME */
+	{GE_NONE, "frame.sr.scope", NULL},
+	
 	/* LABEL_REPLACE */
-	{GE_NONE, "label.replace", NULL, NULL},
+	{GE_NONE, "label.replace", NULL},
 	/* SEARCH_STRING */
-	{GE_COMBO_ENTRY, "search.string.combo", NULL, NULL},
-	/* SEARCH_VAR */
-	{GE_COMBO_ENTRY, "search.var.combo", NULL, NULL},
+	{GE_COMBO_ENTRY, "search.string.combo", NULL},
 	/* MATCH_FILES */
-	{GE_COMBO_ENTRY, "file.filter.match.combo", NULL, NULL},
+	{GE_COMBO_ENTRY, "file.filter.match.combo", NULL},
 	/* UNMATCH_FILES */
-	{GE_COMBO_ENTRY, "file.filter.unmatch.combo", NULL, NULL},
+	{GE_COMBO_ENTRY, "file.filter.unmatch.combo", NULL},
 	/* MATCH_DIRS */
-	{GE_COMBO_ENTRY, "dir.filter.match.combo", NULL, NULL},
+	{GE_COMBO_ENTRY, "dir.filter.match.combo", NULL},
 	/* UNMATCH_DIRS */
-	{GE_COMBO_ENTRY, "dir.filter.unmatch.combo", NULL, NULL},
+	{GE_COMBO_ENTRY, "dir.filter.unmatch.combo", NULL},
 	/* REPLACE_STRING */
-	{GE_COMBO_ENTRY, "replace.string.combo", NULL, NULL},
+	{GE_COMBO_ENTRY, "replace.string.combo", NULL},
+
 	/* ACTIONS_MAX */
-	{GE_TEXT, "actions.max", NULL, NULL},
-	/* SETTING_PREF_ENTRY */
-	{GE_TEXT, "setting.pref.entry", NULL, NULL},
+	{GE_TEXT, "actions.max", NULL},
 	/* SEARCH_REGEX */
-	{GE_BOOLEAN, "search.regex", NULL, NULL},
+	{GE_BOOLEAN, "search.regex", NULL},
 	/* GREEDY */
-	{GE_BOOLEAN, "search.greedy", NULL, NULL},
-       	/* IGNORE_CASE */
-	{GE_BOOLEAN, "search.ignore.case", NULL, NULL},
+	{GE_BOOLEAN, "search.greedy", NULL},
+	/* IGNORE_CASE */
+	{GE_BOOLEAN, "search.ignore.case", NULL},
 	/* WHOLE_WORD */
-	{GE_BOOLEAN, "search.match.whole.word", NULL, NULL},
+	{GE_BOOLEAN, "search.match.whole.word", NULL},
 	/* WORD_START */
-	{GE_BOOLEAN, "search.match.word.start", NULL, NULL},
+	{GE_BOOLEAN, "search.match.word.start", NULL},
 	/* WHOLE_LINE */
-	{GE_BOOLEAN, "search.match.whole.line", NULL, NULL},
+	{GE_BOOLEAN, "search.match.whole.line", NULL},
 	/* IGNORE_HIDDEN_FILES */
-	{GE_BOOLEAN, "ignore.hidden.files", NULL, NULL},
-	/* IGNORE_BINARY_FILES */
-	{GE_BOOLEAN, "ignore.binary.files", NULL, NULL},
+	{GE_BOOLEAN, "ignore.hidden.files", NULL},
 	/* IGNORE_HIDDEN_DIRS */
-	{GE_BOOLEAN, "ignore.hidden.dirs", NULL, NULL},
+	{GE_BOOLEAN, "ignore.hidden.dirs", NULL},
 	/* SEARCH_RECURSIVE */
-	{GE_BOOLEAN, "search.dir.recursive", NULL, NULL},
+	{GE_BOOLEAN, "search.dir.recursive", NULL},
 	/* REPLACE_REGEX */
-	{GE_BOOLEAN, "replace.regex", NULL, NULL},
-	/* ACTIONS_NO_LIMIT */
-	{GE_BOOLEAN, "actions.no_limit", NULL, NULL},
-	/* SEARCH_FULL_BUFFER */
-	{GE_BOOLEAN, "search.full_buffer", NULL, NULL},
+	{GE_BOOLEAN, "replace.regex", NULL},
+
+	/* SEARCH_WHOLE */
+	{GE_BOOLEAN, "search.whole", NULL},
 	/* SEARCH_FORWARD */
-	{GE_BOOLEAN, "search.forward", NULL, NULL},
+	{GE_BOOLEAN, "search.forward", NULL},
 	/* SEARCH_BACKWARD */
-	{GE_BOOLEAN, "search.backward", NULL, NULL},
-	/* SEARCH_BASIC */
-	{GE_BOOLEAN, "search.basic", NULL, NULL},
+	{GE_BOOLEAN, "search.backward", NULL},
+	/* ACTIONS_NO_LIMIT */
+	{GE_BOOLEAN, "actions.no_limit", NULL},
+	/* ACTIONS_LIMIT */
+	{GE_BOOLEAN, "actions.limit", NULL},
 	/* SEARCH_STRING_COMBO */
-	{GE_COMBO, "search.string.combo", NULL, NULL},
+	{GE_COMBO, "search.string.combo", NULL},
 	/* SEARCH_TARGET_COMBO */
-	{GE_COMBO, "search.target.combo", search_target_strings, NULL},
+	{GE_COMBO, "search.target.combo", search_target_strings},
 	/* SEARCH_ACTION_COMBO */
-	{GE_COMBO, "search.action.combo", search_action_strings, NULL},
-	/* SEARCH_VAR_COMBO */
-	{GE_COMBO, "search.var.combo", NULL, NULL},
+	{GE_COMBO, "search.action.combo", search_action_strings},
 	/* MATCH_FILES_COMBO */
-	{GE_COMBO, "file.filter.match.combo", NULL, NULL},
+	{GE_COMBO, "file.filter.match.combo", NULL},
 	/* UNMATCH_FILES_COMBO */
-	{GE_COMBO, "file.filter.unmatch.combo", NULL, NULL},
+	{GE_COMBO, "file.filter.unmatch.combo", NULL},
 	/* MATCH_DIRS_COMBO */
-	{GE_COMBO, "dir.filter.match.combo", NULL, NULL},
+	{GE_COMBO, "dir.filter.match.combo", NULL},
 	/* UNMATCH_DIRS_COMBO */
-	{GE_COMBO, "dir.filter.unmatch.combo", NULL, NULL},
+	{GE_COMBO, "dir.filter.unmatch.combo", NULL},
 	/* REPLACE_STRING_COMBO */
-	{GE_COMBO, "replace.string.combo", NULL, NULL},
-	/* SEARCH_DIRECTION_COMBO */
-	{GE_COMBO, "search.direction.combo", search_direction_strings, NULL},
-	/* SETTING_PREF_TREEVIEW */
-	{GE_NONE, "setting.pref.treeview", NULL, NULL},
-	{GE_NONE, NULL, NULL, NULL}
+	{GE_COMBO, "replace.string.combo", NULL},
 };
 
-/***********************************************************/
+/* LibGlade's auto-signal-connect will connect to these callbacks.
+ * Do not declare them static.
+ */
+/*void on_search_dialog_page_switch (GtkNotebook *notebook,
+									GtkNotebookPage *page,
+									guint page_num,
+									gpointer user_data);
+*/
+void on_search_match_whole_word_toggled (GtkToggleButton *togglebutton,
+										 gpointer user_data);
+void on_search_match_whole_line_toggled (GtkToggleButton *togglebutton,
+										 gpointer user_data);
+void on_search_match_word_start_toggled (GtkToggleButton *togglebutton,
+										 gpointer user_data);
+//void on_replace_regex_toggled (GtkToggleButton *togglebutton, gpointer user_data);
+void on_search_regex_toggled (GtkToggleButton *togglebutton, gpointer user_data);
+void on_search_actions_no_limit_toggled (GtkToggleButton *togglebutton,
+										 gpointer user_data);
+gboolean on_search_dialog_delete_event (GtkWidget *window, GdkEvent *event,
+										 gpointer user_data);
+void on_search_action_changed (GtkComboBox *combo, gpointer user_data);
+void on_search_target_changed (GtkComboBox *combo, gpointer user_data);
+void on_search_expression_changed (GtkComboBox *combo, gpointer user_data);
+void on_search_button_close_clicked (GtkButton *button, gpointer user_data);
+void on_search_button_help_clicked (GtkButton *button, gpointer user_data);
+void on_search_button_start_clicked (GtkButton *button, gpointer user_data);
+void on_search_button_replace_clicked (GtkButton *button, gpointer user_data);
+void on_search_expression_activate (GtkEditable *edit, gpointer user_data);
+void on_search_button_save_clicked (GtkButton *button, gpointer user_data);
+void on_search_button_stop_clicked (GtkButton *button, gpointer user_data);
 
-static void
-write_message_pane(IAnjutaMessageView* view, FileBuffer *fb, SearchEntry *se, MatchInfo *mi);
-static gboolean on_message_clicked (GObject* object, gchar* message, gpointer data);
-static void on_message_buffer_flush (IAnjutaMessageView *view, const gchar *one_line, gpointer data);
-static void save_not_opened_files(FileBuffer *fb);
-static gboolean replace_in_not_opened_files(FileBuffer *fb, MatchInfo *mi, gchar *repl_str);
-static void search_set_action(SearchAction action);
-static void search_set_target(SearchRangeType target);
-static void search_set_direction(SearchDirection dir);
-static void populate_value(GladeWidgetId id, gpointer val_ptr);
-static void reset_flags(void);
-static void reset_flags_and_search_button (void);
-static void search_start_over (SearchDirection direction);
-static void search_end_alert (gchar *string);
-static void max_results_alert (void);
-static void nb_results_alert (gint nb);
-static void search_show_replace(gboolean hide);
-static void modify_label_image_button(GladeWidgetId button_name, gchar *name, char *stock_image);
-static void show_jump_button (gboolean show);
-static gboolean create_dialog(void);
-static void show_dialog(void);
-static gboolean word_in_list(GList *list, gchar *word);
-static GList* list_max_items(GList *list, guint nb_max);
-static void search_update_combos (void);
-static void replace_update_combos (void);
-static void search_direction_changed(SearchDirection dir);
-static void search_set_direction(SearchDirection dir);
-static void search_set_toggle_direction(SearchDirection dir);
-static void search_disconnect_set_toggle_connect(GladeWidgetId id, 
-	GCallback function, gboolean active);
-static void search_replace_next_previous(SearchDirection dir);
-static void basic_search_toggled(void);
-
-static SearchReplaceGUI *sg = NULL;
-
-static SearchReplace *sr = NULL;
-
-static gboolean flag_select = FALSE;
-static gboolean interactive = FALSE;
-static gboolean end_activity = FALSE;
-static gboolean labels_translated = FALSE;
+void on_search_direction_changed (GtkToggleButton *togglebutton, gpointer user_data);
+void on_search_full_buffer_toggled (GtkToggleButton *togglebutton,
+									gpointer user_data);
+//void on_search_forward_toggled (GtkToggleButton *togglebutton,
+//								gpointer user_data);
+//void on_search_backward_toggled (GtkToggleButton *togglebutton,
+//								gpointer user_data);
+//void on_setting_basic_search_toggled (GtkToggleButton *togglebutton,
+//									  gpointer user_data);
 
 /***********************************************************/
 
-void
-search_and_replace_init (IAnjutaDocumentManager *dm)
-{
-	sr = create_search_replace_instance (dm);
-}
+static gboolean on_search_dialog_key_press (GtkWidget *widget,
+											GdkEventKey *event,
+										    gpointer user_data);
+static gboolean on_message_clicked (IAnjutaMessageView *view,
+									gchar *message,
+									gpointer user_data);
+static void on_message_buffer_flush (IAnjutaMessageView *view,
+									 const gchar *one_line,
+									 gpointer user_data);
+static void anj_sr_write_match_message (IAnjutaMessageView *view,
+										SearchEntry *se,
+										gchar *project_root_uri,
+										gint rootlen);
+static void anj_sr_set_action (SearchReplaceGUI *sg, SearchAction action);
+static void anj_sr_set_target (SearchReplaceGUI *sg, SearchRangeType target);
+static void anj_sr_set_direction (SearchReplaceGUI *sg, SearchDirection dir);
+static void anj_sr_populate_value (SearchReplaceGUI *sg,
+									GUIElementId id,
+									gpointer val_ptr);
+static void anj_sr_reset_flags (SearchReplace *sr);
+//static void anj_sr_roll_editor_over (SearchReplace *sr);
+static gboolean anj_sr_end_alert (SearchReplace *sr);
+static void anj_sr_max_results_alert (SearchReplace *sr);
+static void anj_sr_total_results_alert (SearchReplace *sr);
+static void anj_sr_show_replace (SearchReplaceGUI *sg, gboolean hide);
+static void anj_sr_modify_button (SearchReplaceGUI *sg,
+								  GUIElementId button_name,
+								  const gchar *name,
+								  const gchar *stock_id);
+static void anj_sr_show_replace_button (SearchReplaceGUI *sg, gboolean show);
+static void anj_sr_enable_replace_button (SearchReplaceGUI *sg, gboolean show);
+static void anj_sr_reset_replace_buttons (SearchReplaceGUI *sg);
+static gboolean anj_sr_create_dialog (SearchReplace *sr);
+static void anj_sr_present_dialog (SearchReplaceGUI *sg);
+static gboolean anj_sr_find_in_list (GList *list, gchar *word);
+static void anj_sr_trim_list (GList **list, guint nb_max);
+static void anj_sr_update_search_combos (SearchReplaceGUI *sg);
+static void anj_sr_update_replace_combos (SearchReplaceGUI *sg);
+static void anj_sr_conform_direction_change (SearchReplaceGUI *sg,
+											SearchDirection dir);
+static void anj_sr_disconnect_set_toggle_connect (SearchReplaceGUI *sg,
+												  GUIElementId id,
+												  GCallback function,
+												  gboolean active);
+static void anj_sr_select_nearest (SearchReplace *sr, SearchDirection dir);
+//CHECKME keep this ?
+//static void basic_search_toggled (void);
+
+/***********************************************************/
 
+/**
+ * anj_sr_execute:
+ * @sr: pointer to search/replace data struct
+ * @dlg: TRUE when the operation involves the search-dialog
+ *
+ * Conduct a search [and replace] operation in accordance with data in @sr
+ * Depending on the operation performed, this loops sequentially through all
+ * matches in the chosen scope, and when relevant, then through all relevant
+ * files.
+ * But if the operation is interactive-replacement, then each such operation
+ * involves 2 "phases" - before and after confirmation - and those both,
+ * separately, invoke a call to this func. In such calls, the loop terminates
+ * either immediately (after a search-button click) or after a second pass to
+ * find the next match (after a replace-button click). These quick exits mean
+ * that most of the data about subsequent files to search, accumulated at the
+ * start of the function, are discarded immediately and need to be re-created
+ * when the second phase happens.
+ * This is wasteful, but it allows complete freedom between phases to change
+ * the search-operation or or -scope or -expression, and it avoidss blocking
+ * any other UI or other functionality while waiting for confirmation.
+ *
+ * Return value: none
+ */
 void
-search_and_replace (void)
+anj_sr_execute (SearchReplace *sr, gboolean dlg)
 {
-	GList *entries;
-	GList *tmp;
-	SearchEntry *se;
-	FileBuffer *fb;
-	static MatchInfo *mi;
+	GList *node;
 	Search *s;
-	gint offset;
-	gint found_line = 0;
-	static gint os = 0;
-	gint nb_results;
-	static long start_sel = 0;
-	static long end_sel = 0;
-	static gchar *ch = NULL;
-	gchar *regx_pattern;
-	gboolean save_file = FALSE;
-	IAnjutaMessageManager* msgman;
-	IAnjutaMessageView* view = NULL;
+	IAnjutaMessageView *view;
+	GtkWidget *button;	/* the STOP_BUTTON widget */
 	gboolean backward;
-					
-	g_return_if_fail(sr);
+	SearchReplaceGUI *sg;
+	gchar *project_root_uri;
+	gint rootlen;
+	IAnjutaIterable* set_start;
+	IAnjutaIterable* set_end;
+
+	g_return_if_fail (sr);
+
+	if (sr->search.stop_count < 0)
+	{
+		/* something triggered an abort */
+		sr->search.stop_count = 0;
+		return;
+	}
 	s = &(sr->search);
-	
-	if (s->expr.search_str == NULL)
+	sg = sr->sg;
+
+	s->busy = TRUE;	/* mutex */
+	if (s->expr.search_str == NULL)	/* CHECKME when repeating regex search */
+	{
+		s->busy = FALSE;
 		return;
-	
-	entries = create_search_entries(s);
-	if (!entries)
+	}
+
+	dlg = (dlg && sg != NULL && sg->dialog != NULL);	/* bullet-proofing */
+	if (s->action == SA_REPLACE && !dlg)
 		return;
-	
-	end_activity = FALSE;
-	backward = (s->range.direction == SD_BACKWARD);
-	
-	search_update_combos (); 
-	if (s->action == SA_REPLACE || s->action == SA_REPLACEALL)
-		replace_update_combos ();
-
-	if (SA_FIND_PANE == s->action)
-	{
-		gchar* name = g_strconcat(_("Find: "), s->expr.search_str, NULL);		
-		AnjutaShell* shell;
-		g_object_get(G_OBJECT(sr->docman), "shell", &shell, NULL);
-		msgman = anjuta_shell_get_interface(shell, 
-			IAnjutaMessageManager, NULL);
-		g_return_if_fail(msgman != NULL);
-		
-		view = ianjuta_message_manager_get_view_by_name(msgman, name, NULL);
-		if (view == NULL)	
+
+	if (s->candidates == NULL)		/* if starting a fresh operation */
+		create_search_entries (sr); /* grab a list of all items to be searched */
+	if (s->candidates == NULL)
+	{
+		s->busy = FALSE;
+		return;
+	}
+
+	if (s->action == SA_FIND_PANE)	/* list matches in msgman pane */
+	{
+		gchar *name;
+//		AnjutaShell *shell;
+		IAnjutaMessageManager *msgman;
+
+//		g_object_get (G_OBJECT (sr->docman), "shell", &shell, NULL);
+//		msgman = anjuta_shell_get_interface(shell, IAnjutaMessageManager, NULL);
+		msgman = anjuta_shell_get_interface(ANJUTA_PLUGIN (sr->docman)->shell,
+											IAnjutaMessageManager,
+											NULL);
+		if (msgman == NULL)
+			s->busy = FALSE;
+		g_return_if_fail (msgman != NULL);
+
+		project_root_uri = NULL;
+		anjuta_shell_get (ANJUTA_PLUGIN (sr->docman)->shell,
+						  "project_root_uri", G_TYPE_STRING,
+						  &project_root_uri, NULL);
+		if (project_root_uri)
+			rootlen = strlen (project_root_uri);
+		else
+			rootlen = 0;	/* warning prevention */
+
+		name = g_strconcat(_("Find: "), s->expr.search_str, NULL);
+		view = ianjuta_message_manager_get_view_by_name (msgman, name, NULL);
+		if (view == NULL)
 		{
 			// FIXME: Put a nice icon here:
-			view = ianjuta_message_manager_add_view(msgman, name,
-													GTK_STOCK_FIND_AND_REPLACE, NULL);	
-			g_return_if_fail(view != NULL);
-			g_signal_connect (G_OBJECT(view), "buffer_flushed",
+			view = ianjuta_message_manager_add_view (msgman, name,
+													GTK_STOCK_FIND_AND_REPLACE, NULL);
+			if (view == NULL)
+				s->busy = FALSE;
+			g_return_if_fail (view != NULL);
+			g_signal_connect (G_OBJECT (view), "buffer-flushed",
 			                  G_CALLBACK (on_message_buffer_flush), NULL);
-			g_signal_connect (G_OBJECT(view), "message_clicked",
-			                  G_CALLBACK (on_message_clicked), NULL);
+			g_signal_connect (G_OBJECT (view), "message-clicked",
+			                  G_CALLBACK (on_message_clicked), sr->docman);
 		}
 		else
-			ianjuta_message_view_clear(view, NULL);
-		ianjuta_message_manager_set_current_view(msgman, view, NULL);
+			ianjuta_message_view_clear (view, NULL);
+		ianjuta_message_manager_set_current_view (msgman, view, NULL);
 	}
-	gtk_widget_set_sensitive (sr_get_gladewidget(STOP_BUTTON)->widget, TRUE);
-	nb_results = 0;
-	for (tmp = entries; tmp && (nb_results <= s->expr.actions_max); 
-		 tmp = g_list_next(tmp))
+	else
 	{
-		if (end_activity)
+		/* warning prevention */
+		view = NULL;
+		project_root_uri = NULL;
+		rootlen = 0;
+	}
+
+	if (dlg)	/* operation involves dialog */
+	{
+		anj_sr_update_search_combos (sg);
+		if (s->action == SA_REPLACE || s->action == SA_REPLACEALL)
+			anj_sr_update_replace_combos (sg);
+		button = anj_sr_get_ui_widget (STOP_BUTTON);
+		gtk_widget_set_sensitive (button, TRUE);
+	}
+	else
+		button = NULL;	/* warning prevention */
+
+	s->stop_count = 0;
+	backward = (s->range.direction == SD_BACKWARD);
+	s->limited =  (s->range.target == SR_SELECTION
+				|| s->range.target == SR_FUNCTION
+				|| s->range.target == SR_BLOCK);
+
+	set_start = set_end = NULL;
+
+	for (node = s->candidates; node != NULL; node = g_list_next (node))
+	{
+		FileBuffer *fb;
+		SearchEntry *se;
+		gboolean fresh; 	/* file was opened for this search operation */
+
+		if (node->data == NULL)	/* this candidate was cleared before */
+			continue;
+
+		if (dlg && s->stop_count != 0)
 			break;
-		while(gtk_events_pending())
+		while (gtk_events_pending ())
 			gtk_main_iteration();
-		
-		/*to eliminate un-needed moves, when not bookmarking, this could be
-		  current line i.e. ianjuta_editor_get_lineno (IANJUTA_EDITOR (se->te), NULL);
-		  or sometimes last-line ? */
-		found_line = (s->action == SA_BOOKMARK) ? -1 : 1;
 
-		se = (SearchEntry *) tmp->data;
-		if (flag_select)
+		se = (SearchEntry *) node->data;
+
+		if (s->action == SA_REPLACE && sr->replace.phase != SA_REPL_FIRST)
 		{
-			se->start_pos = start_sel;
-			se->end_pos = end_sel;
+			/* this is either a confirmation (sr->replace.phase == SA_REPL_CONFIRM)
+				or skip (sr->replace.phase == SA_REPL_SKIP)*/
+			/* buffer from the prior phase 1 is still present */
+			fresh = se->fresh;
 		}
-		else
-			end_sel = se->end_pos;
-		if (SE_BUFFER == se->type)
-			fb = file_buffer_new_from_te(se->te);
-		else /* if (SE_FILE == se->type) */
-			fb = file_buffer_new_from_path(se->path, NULL, -1, 0);
-
-		if (fb)
-		{		
-			fb->pos = se->start_pos;
-			offset = 0;
-/* NO - there's no reason for user to expect existing marks to be removed.
-	And that can easily be done manually by user if so desired.
-			if (s->action == SA_BOOKMARK && IANJUTA_IS_MARKABLE (fb->te))
-				ianjuta_markable_delete_all_markers(IANJUTA_MARKABLE(fb->te), 
-				                                    IANJUTA_MARKABLE_LINEMARKER, NULL);
-*/
-		//FIXME enable clearing of marks by some means other than a 0-match search
-			if (s->action == SA_HIGHLIGHT)	
-				ianjuta_indicable_clear (IANJUTA_INDICABLE(fb->te), NULL); 				
-	
-			while (interactive || 
-				NULL != (mi = get_next_match(fb, s->range.direction, &(s->expr))))
+		else if (se->type == SE_BUFFER)	/* operation intended to apply to part or all
+										of an open buffer or to all open buffers */
+		{
+			se->fb = file_buffer_new_from_te (se->te);
+			fresh = FALSE;
+		}
+		else /* se->type == SE_FILE, unopened file, operation intended to apply
+				to all project files or to pattern-matching files */
+		{
+			se->fb = file_buffer_new_from_uri (sr, se->uri, NULL, -1);
+			fresh = TRUE;
+		}
+
+		fb = se->fb;
+
+		if (fb != NULL && fb->len > 0)
+		{
+			position_t replace_length;
+			gboolean terminate; /* stop doing this file immediately */
+			gboolean dirty;	/* fresh file has been changed somehow */
+			gboolean save_file;
+
+			if ((s->action == SA_HIGHLIGHT || s->action == SA_UNLIGHT)
+				&& !fresh	/* no reason to do this for newly-opened files */
+				&& fb->te != NULL)
+				ianjuta_indicable_clear (IANJUTA_INDICABLE (fb->te), NULL);
+
+			/* local operations work in byte-positions, all editors work with chars */
+			s->expr.postype = (fb->te == NULL) ? SP_BYTES : SP_CHARS;
+
+			/* CHECKME simply test for fb->start_pos and fb->end_pos not both == 0 ? */
+			if (s->limited)
 			{
-				if ((s->range.direction == SD_BACKWARD) && (mi->pos < se->end_pos))
-						break; 
-				if ((s->range.direction != SD_BACKWARD) && ((se->end_pos != -1) &&
-					(mi->pos+mi->len > se->end_pos)))
-						break; 
-				nb_results++; 
-				if (nb_results > sr->search.expr.actions_max)
-					break;
-				
+				if (se->sel_first_start == se->sel_first_end)	/* both 0 @ first usage */
+				{
+					/* one of these will be updated after a match is found */
+					se->sel_first_start = se->start_pos;
+					se->sel_first_end = se->end_pos;
+				}
+				else
+				{
+					/* when scope is the selection, use the original settings cuz the
+						current selection can move around in the searching process */
+					se->start_pos = se->sel_first_start; /* CHECKME when SA_REPLACE */
+					se->end_pos = se->sel_first_end;
+				}
+			}
+			if (s->action != SA_REPLACE || sr->replace.phase == SA_REPL_FIRST)
+			{
+				if (s->expr.postype == SP_BYTES)
+				{
+					if (se->start_pos != 0)
+						se->start_pos = file_buffer_get_char_offset (fb, se->start_pos);
+					if (se->end_pos == -1)
+						se->end_pos = fb->len - 1;
+					else
+						se->end_pos = file_buffer_get_char_offset (fb, se->end_pos);
+				}
+				fb->start_pos = se->start_pos;
+				fb->end_pos = se->end_pos;
+			}
+
+			/* pity about repetition of this inside loop, but can't do it before
+			   each editor (maybe of different sorts) is present and its
+			   position-type is known */
+			if (!s->expr.regex)
+			{
+				if (s->expr.postype == SP_BYTES)
+				{
+					/* except for regex searching, the match-length is constant */
+					se->mi.len = strlen (s->expr.search_str);
+					/* likewise the replacement length */
+					if (s->action == SA_REPLACE || s->action == SA_REPLACEALL)
+						replace_length = strlen (sr->replace.repl_str);
+					else
+						replace_length = 0;	/* warning prevention */
+				}
+				else
+				{
+					se->mi.len = g_utf8_strlen (s->expr.search_str, -1);
+					if (s->action == SA_REPLACE || s->action == SA_REPLACEALL)
+						replace_length = g_utf8_strlen (sr->replace.repl_str, -1);
+					else
+						replace_length = 0;	/* warning prevention */
+				}
+				/* and the adjustment needed after a replacement */
+				/* +ve differential when replacement string is longer than original */
+//				if (s->action == SA_REPLACE || s->action == SA_REPLACEALL)
+//					se->offset = replace_length - se->mi.len;
+			}
+			else
+			{
+				if (s->action == SA_REPLACE || s->action == SA_REPLACEALL)
+				/* length will be changed later if replacement string has backrefs */
+					replace_length = strlen (sr->replace.repl_str);
+				else
+					replace_length = 0;	/* warning prevention */
+//				se->offset = 0;
+			}
+
+			/* CHECKME to eliminate un-needed moves, when not SA_BOOKMARK, this could be
+			   current line i.e. ianjuta_editor_get_lineno (IANJUTA_EDITOR (fe->te), NULL);
+			   or sometimes last-line ? */
+			if (se->found_line == 0)
+				se->found_line = (s->action == SA_BOOKMARK) ? -1 : 1;
+again:
+			dirty = FALSE;
+			terminate = FALSE;
+			save_file = FALSE;
+
+			/* AT LAST, WE BEGIN SEARCHING */
+			while (sr->replace.phase == SA_REPL_CONFIRM	/* always proceed if this is phase 2 of a confirmed replacement */
+					|| get_next_match (fb, s->range.direction, &(s->expr), &(se->mi)))
+			{
+				if (//s->action != SA_REPLACE ||
+					sr->replace.phase != SA_REPL_CONFIRM)
+				{
+					/* this is not phase 2 of a confirmed replacement */
+					position_t thisoffset;
+
+					if (backward)
+					{
+						thisoffset = (s->expr.postype == SP_BYTES) ?
+							file_buffer_get_char_offset (fb, se->mi.pos) : se->mi.pos;
+						if (thisoffset < fb->start_pos)
+							break;
+					}
+
+					if (!backward && fb->end_pos != -1)
+					{
+						thisoffset = (s->expr.postype == SP_BYTES) ?
+							file_buffer_get_char_offset (fb, se->mi.pos + se->mi.len) :
+							se->mi.pos + se->mi.len;
+						if (thisoffset > fb->end_pos + 1)	/* match at end of buffer will go past last char */
+							break;
+					}
+				}
+
 				/* NOTE - mi->line is "editor-style" 1-based, but some things
-					here use/expect 0-base, so adjustments are made as needed */
-				
+					here use/expect 0-base, so adjustments are made as needed.
+
+					Lengths and last chars are 1-past actual last char to process,
+					to suit sourceview-style positioning with iter affer that
+					last char. Scintilla needs downstream adjustments for this */
+
 				switch (s->action)
 				{
 					case SA_HIGHLIGHT:
-						found_line = mi->line;
-
-						if (fb->te == NULL)
-							fb->te =
-								IANJUTA_EDITOR (ianjuta_document_manager_get_current_document
-									(sr->docman, NULL));
-
-						if (IANJUTA_INDICABLE (fb->te))
+						if (fb->te && IANJUTA_IS_INDICABLE (fb->te))
 						{
-							IAnjutaIterable *start_pos, *end_pos;
-							/* end-location is correct for sourceview, 1-too-big for scintilla */
-							start_pos = ianjuta_editor_get_position_from_offset (fb->te, mi->pos, NULL);
-							end_pos = ianjuta_editor_get_position_from_offset (fb->te, mi->pos + mi->len, NULL);
-							ianjuta_indicable_set (IANJUTA_INDICABLE(fb->te),
-												   start_pos, end_pos,
-												   IANJUTA_INDICABLE_IMPORTANT, NULL);
-							g_object_unref (start_pos);
-							g_object_unref (end_pos);
+							if (set_start == NULL)
+							{
+								set_start = ianjuta_editor_get_start_position (fb->te, NULL);
+								set_end = ianjuta_iterable_clone (set_start, NULL);
+							}
+
+							if (ianjuta_iterable_set_position (IANJUTA_ITERABLE (set_start),
+																se->mi.pos,
+																NULL)
+							&& ianjuta_iterable_set_position (IANJUTA_ITERABLE (set_end),
+																se->mi.pos + se->mi.len,
+																NULL))
+								 ianjuta_indicable_set (IANJUTA_INDICABLE (fb->te),
+														IANJUTA_ITERABLE (set_start),
+														IANJUTA_ITERABLE (set_end),
+														IANJUTA_INDICABLE_IMPORTANT, NULL);
+							else
+							{
+								//FIXME failure warning
+							}
+							dirty = TRUE;
 						}
+						else
+							terminate = TRUE;
+
 						break;
 
 					case SA_BOOKMARK:
-						if (found_line != mi->line)
+						if (fb->te && IANJUTA_IS_MARKABLE (fb->te))
 						{
-							found_line = mi->line;
-						
-							if (fb->te == NULL)
-								fb->te =
-									IANJUTA_EDITOR (ianjuta_document_manager_get_current_document
-										(sr->docman, NULL));
-
-							if (IANJUTA_IS_MARKABLE (fb->te) &&
-								!ianjuta_markable_is_marker_set (
-														IANJUTA_MARKABLE(fb->te),
-														mi->line,
+							if (se->found_line != se->mi.line)
+							{
+								se->found_line = se->mi.line;
+
+								if (!ianjuta_markable_is_marker_set (
+														IANJUTA_MARKABLE (fb->te),
+														se->mi.line,
 														IANJUTA_MARKABLE_BOOKMARK,
 														NULL))
-							{
-								ianjuta_bookmark_toggle (IANJUTA_BOOKMARK(fb->te),
-														mi->line, FALSE, NULL);
+								{
+									ianjuta_bookmark_toggle (IANJUTA_BOOKMARK (fb->te),
+														se->mi.line, FALSE, NULL);
+									dirty = TRUE;
+								}
 							}
 						}
+						else
+							terminate = TRUE;
+
+						break;
+
+					case SA_FIND_PANE:
+						anj_sr_write_match_message (view, se, project_root_uri, rootlen);
 						break;
-						
+
 					case SA_SELECT:
-						if (found_line != mi->line || fb->te == NULL)
+						if (fresh) /* not an open file */
 						{
-							if (fb->te)
-								ianjuta_editor_goto_line (fb->te, mi->line, NULL);
-							else
-								fb->te = ianjuta_document_manager_goto_uri_line_mark
-									(sr->docman, fb->uri, mi->line, FALSE, NULL);
-							found_line = mi->line;
+							editor_new_from_file_buffer (se);
+							if (fb->te && IANJUTA_IS_EDITOR_SELECTION (fb->te))
+							{
+								fresh = FALSE;
+								s->expr.postype = SP_CHARS;
+							}
+							else if (fb->te)
+							{
+								/* new editor which is not selectable */
+								ianjuta_document_manager_remove_document
+												(sr->docman,
+												IANJUTA_DOCUMENT (fb->te),
+												FALSE, NULL);
+								terminate = TRUE;
+							}
 						}
+						if (fb->te && IANJUTA_IS_EDITOR_SELECTION (fb->te))
 						{
-							IAnjutaIterable* start = ianjuta_editor_get_position_from_offset (fb->te, mi->pos, NULL);
-							IAnjutaIterable* end = ianjuta_editor_get_position_from_offset (fb->te, mi->pos + mi->len, NULL);
-							ianjuta_editor_selection_set(IANJUTA_EDITOR_SELECTION (fb->te), 
-														 start,
-														 end,
-														 NULL);
-							g_object_unref (start);
-							g_object_unref (end);
-							break;
+							if (se->found_line != se->mi.line)
+							{
+								se->found_line = se->mi.line;
+								ianjuta_editor_goto_line (fb->te, se->mi.line, NULL);
+							}
+
+							if (set_start == NULL)
+							{
+								set_start = ianjuta_editor_get_start_position (fb->te, NULL);
+								set_end = ianjuta_iterable_clone (set_start, NULL);
+							}
+
+							if (ianjuta_iterable_set_position (IANJUTA_ITERABLE (set_start),
+																se->mi.pos,
+																NULL)
+							&& ianjuta_iterable_set_position (IANJUTA_ITERABLE (set_end),
+																se->mi.pos + se->mi.len,
+																NULL))
+								ianjuta_editor_selection_set (IANJUTA_EDITOR_SELECTION (fb->te),
+															  IANJUTA_ITERABLE (set_start),
+															  IANJUTA_ITERABLE (set_end),
+															  NULL);
+							else
+							{
+								//FIXME failure warning
+							}
+							dirty = TRUE;
 						}
-						
-					case SA_FIND_PANE: 
-						write_message_pane(view, fb, se, mi);
+						else
+							terminate = TRUE;
+
 						break;
-					
+
 					case SA_REPLACE:
-						if (found_line != mi->line || fb->te == NULL)
+						if (fresh) /* not an open file */
+						{
+							editor_new_from_file_buffer (se);
+							if (fb->te && IANJUTA_IS_EDITOR_SELECTION (fb->te))
 							{
-							if (fb->te)
-								ianjuta_editor_goto_line (fb->te, mi->line, NULL);
-							else
-								fb->te = ianjuta_document_manager_goto_uri_line_mark
-									(sr->docman, fb->uri, mi->line, FALSE, NULL);
-							found_line = mi->line;
+								fresh = FALSE;
+								s->expr.postype = SP_CHARS;
 							}
-
-						if (!interactive)
+							else if (fb->te)
+							{
+								/* new editor which is not selectable */
+								ianjuta_document_manager_remove_document
+												(sr->docman,
+												IANJUTA_DOCUMENT (fb->te),
+												FALSE, NULL);
+								terminate = TRUE;
+							}
+						}
+						if (fb->te && IANJUTA_IS_EDITOR_SELECTION (fb->te))
 						{
-							IAnjutaIterable* start = ianjuta_editor_get_position_from_offset (fb->te, mi->pos - offset, NULL);
-							IAnjutaIterable* end = ianjuta_editor_get_position_from_offset (fb->te, mi->pos - offset + mi->len, NULL);
-							ianjuta_editor_selection_set(IANJUTA_EDITOR_SELECTION (fb->te), 
-														 start,
-														 end,
-														 NULL);
-							g_object_unref (start);
-							g_object_unref (end);
-							interactive = TRUE;
-							os = offset;
-							modify_label_image_button(SEARCH_BUTTON, _("Replace"), 
-								                      GTK_STOCK_FIND_AND_REPLACE);
-							show_jump_button(TRUE);
-							if (sr->replace.regex && sr->search.expr.regex)
+							if (se->found_line != se->mi.line)
+							{
+								se->found_line = se->mi.line;
+								ianjuta_editor_goto_line (fb->te, se->found_line, NULL);
+							}
+
+							if (sr->replace.phase == SA_REPL_CONFIRM)
 							{
-									g_free (ch);
-								ch = regex_backref (mi, fb);
+								/* this is phase 2, after confirmation */
+								gchar *substitute;
+								position_t newlen, match_pos;
+
+								if (sr->replace.regex && s->expr.regex)
+								{
+									/* this replacement includes backref(s), so it's not constant */
+									substitute = regex_backref (sr, &(se->mi), fb);
+									match_info_free_subs (&(se->mi));
+									se->mi.subs = NULL;
+									newlen = (s->expr.postype == SP_BYTES) ?
+										strlen (substitute) :
+										g_utf8_strlen (substitute, -1);
+								}
+								else
+								{
+									substitute = sr->replace.repl_str;
+									newlen = replace_length;
 								}
+
+								match_pos = se->mi.pos;
+
+//								if (!backward)
+//									se->mi.pos += se->total_offset;
+								if (ianjuta_iterable_set_position (IANJUTA_ITERABLE (set_start),
+																	se->mi.pos,
+																	NULL)
+								&& ianjuta_iterable_set_position (IANJUTA_ITERABLE (set_end),
+																	se->mi.pos + se->mi.len,
+																	NULL))
+								{
+									ianjuta_editor_selection_set (IANJUTA_EDITOR_SELECTION (fb->te),
+																  IANJUTA_ITERABLE (set_start),
+																  IANJUTA_ITERABLE (set_end),
+																  NULL);
+									ianjuta_editor_selection_replace (IANJUTA_EDITOR_SELECTION (fb->te),
+																	 substitute,
+																	 newlen,
+																	 NULL);
+								}
+								else
+								{
+									//FIXME failure warning
+									break;
+								}
+								/* after a replace, the following find will need
+								   total_offset for operations not using editor-native
+								   search to get the match-position and -length
+								   ATM only regex uses local search buffer */
+								/* CHECKME if replacing in local buffer as well as
+									editor-native, probably no need for offset ? */
+								//if (s->expr.regex) all is local ATM
+								//{
+//									if (!backward)
+//										se->total_offset += newlen - se->mi.len;
+									if (!backward)
+									{
+										if (s->expr.postype == SP_BYTES)
+											fb->start_pos +=
+												g_utf8_strlen (substitute, -1) -
+												g_utf8_strlen (fb->buf+ match_pos, se->mi.len);
+										else
+											fb->start_pos += newlen - se->mi.len;
+									}
+									/* using local buffer for search */
+									replace_in_local_buffer (fb, match_pos, se->mi.len, substitute);
+									/* CHECKME any EOL(s) added or removed ? hence must freshen
+										Otherwise, freshen needed or will offset suffice ? */
+									if (!backward)
+										file_buffer_freshen_lines_from_pos (fb, match_pos, s->expr.postype == SP_BYTES);
+								//}
+								if (substitute && sr->replace.regex && s->expr.regex)
+								{
+									g_free (substitute);
+								}
+								dirty = TRUE;
+								sr->replace.phase = SA_REPL_SKIP; /* trigger another pass of this loop to find the next match */
 							}
-						else
-						{
-						if (ch && sr->replace.regex && sr->search.expr.regex)
-						{
-								g_free (sr->replace.repl_str);
-								sr->replace.repl_str = g_strdup (ch);
-							g_free (ch);
-								ch = NULL;
-						}
+							else
 							{
-								IAnjutaIterable* start = ianjuta_editor_get_position_from_offset (fb->te, mi->pos - os, NULL);
-								IAnjutaIterable* end = ianjuta_editor_get_position_from_offset (fb->te, mi->pos + mi->len - os, NULL);
-								ianjuta_editor_selection_set(IANJUTA_EDITOR_SELECTION (fb->te),  
-															 start,														 
-															 end,
-															 NULL);
-								ianjuta_editor_selection_replace(IANJUTA_EDITOR_SELECTION (fb->te), 
-																 sr->replace.repl_str,
-																 strlen(sr->replace.repl_str),
-																 NULL);
-								g_object_unref (start);
-								g_object_unref (end);
+								/* this is before pause for confirm or skip */
+//								if (s->expr.regex && all searching is local ATM
+//								if (!backward)
+//									se->mi.pos += se->total_offset;
+								if (set_start == NULL)
+								{
+									set_start = ianjuta_editor_get_start_position (fb->te, NULL);
+									set_end = ianjuta_iterable_clone (set_start, NULL);
+								}
+								if (ianjuta_iterable_set_position (IANJUTA_ITERABLE (set_start),
+																	se->mi.pos,
+																	NULL)
+								&& ianjuta_iterable_set_position (IANJUTA_ITERABLE (set_end),
+																	se->mi.pos + se->mi.len,
+																	NULL))
+									ianjuta_editor_selection_set (IANJUTA_EDITOR_SELECTION (fb->te),
+																  IANJUTA_ITERABLE (set_start),
+																  IANJUTA_ITERABLE (set_end),
+																  NULL);
+								else
+								{
+									//FIXME failure warning
+								}
+								/* prevent double-offset in phase 2, if the user confirms */
+//								if (!backward)
+//									se->mi.pos -= se->total_offset;
+
+								if (dlg)
+									anj_sr_enable_replace_button (sg, TRUE);
+
+								if (s->limited)
+								{
+									/* update the remembered search scope */
+									if (backward)
+										se->sel_first_end = fb->start_pos;
+									else
+										se->sel_first_start = fb->start_pos;
+								}
+
+								/* trigger immediate exit from loop and then
+								   phase 2 (confirmed) or another phase 1 (skipped) */
+								sr->replace.phase = SA_REPL_CONFIRM;
 							}
-						if (se->direction != SD_BACKWARD)
-							offset += mi->len - (sr->replace.repl_str?strlen(sr->replace.repl_str):0);
-						
-						interactive = FALSE;
 						}
+						else
+							terminate = TRUE;
+
 						break;
 
 					case SA_REPLACEALL:
-						if (sr->replace.regex && sr->search.expr.regex)
+						if (fresh) /* not an open file */
 						{
-							regx_pattern = sr->replace.repl_str;	/* preserve for later matches */
-							sr->replace.repl_str = regex_backref (mi, fb);
-						}
-						else
-							regx_pattern = NULL;
-						if (fb->te == NULL) /* NON OPENED FILES */
-						{
-							if (replace_in_not_opened_files(fb, mi, sr->replace.repl_str))
+							gchar *substitute;
+
+							if (sr->replace.regex && s->expr.regex)
+							{
+								substitute = regex_backref (sr, &(se->mi), fb);
+								match_info_free_subs (&(se->mi));
+								se->mi.subs = NULL;
+							}
+							else
+							{
+								substitute = sr->replace.repl_str;
+							}
+
+							if (replace_in_local_buffer (fb, se->mi.pos, se->mi.len, substitute))
+							{
+//								position_t thisoffset;
+
 								save_file = TRUE;
+/* un-opened files don't need backward searching
+								if (backward)
+								{
+									GList *node;
+									/ * update length data in last member of list * /
+									node = g_list_last (fb->lines);
+									node = g_list_previous (node);
+									thisoffset = ((EOLdata *)node->data)->offb;
+									file_buffer_freshen_lines_from_pos (fb, thisoffset, TRUE);
+								}
+								else
+								{
+*/
+									/*freshen lines from current*/
+//									file_buffer_freshen_lines_from_pos (fb, se->mi.pos, TRUE);
+									//sr->total_offset += se->mi.len - newlen;
+//								}
+							}
 						}
 						else
 						{
-							IAnjutaIterable* start = ianjuta_editor_get_position_from_offset (fb->te, mi->pos - offset, NULL);
-							IAnjutaIterable* end = ianjuta_editor_get_position_from_offset (fb->te, mi->pos + mi->len - offset, NULL);
-							ianjuta_editor_selection_set(IANJUTA_EDITOR_SELECTION (fb->te),  
-														 start,
-														 end,
-														 NULL);
-							ianjuta_editor_selection_replace(IANJUTA_EDITOR_SELECTION (fb->te), 
-															 sr->replace.repl_str,
-															 strlen(sr->replace.repl_str),
-															 NULL);
-							g_object_unref (start);
-							g_object_unref (end);
-						}
-						if (se->direction != SD_BACKWARD)
- 							offset += mi->len - (sr->replace.repl_str?strlen(sr->replace.repl_str):0);
-						if (regx_pattern)
-						{
-							g_free (sr->replace.repl_str);
-							sr->replace.repl_str = regx_pattern;
+							if (fb->te && IANJUTA_IS_EDITOR_SELECTION (fb->te))
+							{
+								gchar *substitute;
+								position_t newlen, match_pos;
+
+								if (sr->replace.regex && s->expr.regex)
+								{
+									substitute = regex_backref (sr, &(se->mi), fb);
+									match_info_free_subs (&(se->mi));
+									se->mi.subs = NULL;
+									newlen = g_utf8_strlen (substitute, -1);
+								}
+								else
+								{
+									substitute = sr->replace.repl_str;
+									newlen = replace_length;
+								}
+								/* the select/replace will need total_offset for
+								   operations not using editor-native search
+								   to get the match-position and -length
+								   ATM only regex uses local search buffer */
+								/* CHECKME if replacing in local buffer as well as
+									editor-native, probably no need for offset ? */
+								//if (s->expr.regex) all is local ATM
+
+								match_pos = se->mi.pos;
+
+								if (!backward)
+								{
+									se->mi.pos += se->total_offset;
+									se->total_offset += newlen - se->mi.len;
+								}
+
+								if (set_start == NULL)
+								{
+									set_start = ianjuta_editor_get_start_position (fb->te, NULL);
+									set_end = ianjuta_iterable_clone (set_start, NULL);
+								}
+								if (ianjuta_iterable_set_position (IANJUTA_ITERABLE (set_start),
+																	se->mi.pos,
+																	NULL)
+								&& ianjuta_iterable_set_position (IANJUTA_ITERABLE (set_end),
+																	se->mi.pos + se->mi.len,
+																	NULL))
+								{
+									ianjuta_editor_selection_set (IANJUTA_EDITOR_SELECTION (fb->te),
+																  IANJUTA_ITERABLE (set_start),
+																  IANJUTA_ITERABLE (set_end),
+																  NULL);
+									ianjuta_editor_selection_replace (IANJUTA_EDITOR_SELECTION (fb->te),
+																substitute,
+																newlen,
+																NULL);
+								}
+								else
+								{
+									//FIXME failure warning
+								}
+
+/*								if (s->expr.regex)	/ * using local buffer for search * /
+								{ */
+									replace_in_local_buffer (fb, match_pos, se->mi.len, substitute);
+									/* CHECKME any EOL(s) added or removed ? hence must freshen
+										Otherwise, freshen needed or will offset suffice ? */
+									if (!backward)
+										file_buffer_freshen_lines_from_pos (fb, match_pos, s->expr.postype == SP_BYTES);
+//								}
+
+								if (substitute && sr->replace.regex && s->expr.regex)
+								{
+									g_free (substitute);
+								}
+								dirty = TRUE;
+							}
+							else
+								terminate = TRUE;
 						}
+
 						break;
 
 					default:
 						g_warning ("Not implemented - File %s - Line %d\n", __FILE__, __LINE__);
+					case SA_UNLIGHT:	/* the action was done before the loope*/
+						terminate = TRUE;
 						break;
-				}  // switch
+				}  /* switch */
 
-				if (se->direction != SD_BACKWARD)
-					start_sel = mi->pos + mi->len - offset; 
-				else
-					start_sel = mi->pos - offset; 
-				
-				if (SA_REPLACE != s->action || !interactive)
-					match_info_free(mi);
-				
-				if (SA_SELECT == s->action ||
-					((SA_REPLACE == s->action || SA_REPLACEALL == s->action) && interactive))
+				if (terminate /* immediate end to processing this file */
+				|| (s->action == SA_REPLACE && sr->replace.phase == SA_REPL_CONFIRM)) /* wait for confirmation */
 					break;
-			} // while
-/* NO - leave the current position unchanged when marking-all
-			if (nb_results > 0)
+				s->matches_sofar++;
+				if ((!backward && fb->start_pos >= fb->len) /* can't go further forward */
+				 || (backward && fb->end_pos <= 0)	/* can't go further back */
+				 || (!s->expr.no_limit && s->matches_sofar == s->expr.actions_max) /* limit reached */
+				 || s->action != SA_REPLACE)	/* after a replacement, go back to find next match */
+					break;
+
+			} /* while something to do to this buffer */
+
+			if (s->matches_sofar == 0
+				&& !fresh
+				&& (s->action != SA_REPLACE || sr->replace.phase != SA_REPL_CONFIRM)
+				&& s->action != SA_UNLIGHT)
 			{
-				switch (s->action)
+				if (anj_sr_end_alert (sr))
 				{
-					case SA_HIGHLIGHT:
-					case SA_BOOKMARK:
-						ianjuta_editor_goto_line (fb->te, found_line, NULL);
-					default:
-						break;
+					/* rollover is allowed and wanted */
+//					anj_sr_roll_editor_over (sr); no need for this
+					if (backward)
+						fb->end_pos = fb->len;/* from end, all prvious offsets
+												 will be wrong ? */
+					else
+					{
+						fb->start_pos = 0;
+						se->total_offset = 0; /* from start, offset can't be re-used,
+												BUT there will be a misalignment
+												problem if the searching continues
+												past the point of first replacement
+												in the previous stage ?*/
+					}
+					goto again;
 				}
 			}
-*/
-		if (save_file)
+
+			if (save_file)
+			{
+				if (!save_file_buffer (fb))
+				{
+					//FIXME UI warning
+					g_warning ("Error saving modified file %s", se->uri);
+				}
+				save_file = FALSE;
+			}
+
+			if (s->action == SA_REPLACE && sr->replace.phase == SA_REPL_CONFIRM)
+			{
+				/* save these for the confirmation phase */
+				se->fresh = fresh;
+				/* remember the next search-range in case this replacement is skipped */
+				se->start_pos = fb->start_pos;
+				se->end_pos = fb->end_pos;
+			}
+			else
+				se->fb = NULL;	/* trigger a cleanup, fb still non-NULL */
+		} /* if (fb && te) */
+		else	/* fb == NULL or fb->len == 0 */
+			if (fb->len == 0)
 		{
-				save_not_opened_files (fb);
-			save_file = FALSE;
+			se->fb = NULL;	/* trigger a cleanup, fb still non-NULL */
+		}
+		else
+		{
+			//FIXME UI warning
+			g_warning ("Skipping %s, problem with editor or file buffer", se->uri);
 		}
-		
-			file_buffer_free (fb);
-		}  // if (fb)
 
-		g_free (se->path);
-		g_free (se);
+		if (se->fb == NULL)	/* indicates ready for cleanup */
+		{
+			/* this candidate now finished so NULL its data for post-loop cleanup */
+			/* no need to clean file-buffer here, it's handled above */
+			g_free (se->uri);
+			g_free (se->regx_repl_str);
+			if (fb != NULL)
+				file_buffer_free (fb);
+			if (se->mi.subs != NULL)
+				match_info_free_subs (&(se->mi));
+			g_slice_free1 (sizeof (SearchEntry), se);
+			node->data = NULL;
+		}
 
-		if (SA_SELECT == s->action && nb_results > 0)
+		if (s->action == SA_SELECT && s->matches_sofar > 0)
 			break;
-	}
+	} /* candidates loop */
 
-	gtk_widget_set_sensitive (sr_get_gladewidget(STOP_BUTTON)->widget, FALSE);
-	
-	if (s->range.type == SR_BLOCK || s->range.type == SR_FUNCTION || 
-		s->range.type == SR_SELECTION)
-			flag_select = TRUE;
-	
-	if (entries)
-		g_list_free (entries);
-	
 	if (s->action == SA_FIND_PANE)
 	{
 		ianjuta_message_view_append (view, IANJUTA_MESSAGE_VIEW_TYPE_INFO,
 									 _("Search complete"), "", NULL);
 	}
-	
-	if (nb_results == 0)
+
+	if (dlg)
 	{
-		search_end_alert(sr->search.expr.search_str);
+		if (s->action != SA_REPLACE || sr->replace.phase != SA_REPL_CONFIRM)
+		{
+			gtk_widget_set_sensitive (button, FALSE);	/* disable the stop button */
+			anj_sr_enable_replace_button (sg, FALSE);
+		}
+		else //redundant if (s->action == SA_REPLACE)
+			anj_sr_enable_replace_button (sg, TRUE);
 	}
-	else if (nb_results > sr->search.expr.actions_max)
-		max_results_alert();
-	else if (s->action == SA_REPLACEALL)
-		nb_results_alert(nb_results);
-	
-	if ((s->range.direction == SD_BEGINNING) &&
-		((s->action == SA_SELECT) || (s->action == SA_REPLACE)) )
+
+	if (s->action == SA_REPLACE	&& sr->replace.phase == SA_REPL_CONFIRM)
+		s->candidates = g_list_remove_all (s->candidates, NULL);
+	else
+	{
+		if (s->expr.regex)
+		{
+			pcre_info_free (s->expr.re);
+			s->expr.re = NULL;
+		}
+		clear_search_entries (&(s->candidates));
+	}
+
+	if (s->action != SA_UNLIGHT)
 	{
-		search_set_direction(SD_FORWARD);
+		/* 0-matches is reported at the end of the file-loop */
+		if (s->matches_sofar > 0)
+		{
+			if (!s->expr.no_limit &&
+				s->matches_sofar >= s->expr.actions_max)
+				anj_sr_max_results_alert (sr);
+			else if (s->action == SA_REPLACEALL)
+				anj_sr_total_results_alert (sr);
+
+			if (s->action != SA_REPLACE)
+				s->matches_sofar = 0; /* we can't rollover unless there really
+										is no replacement cuz all the offsets
+										will be wrong after rolling */
+			/* For replaces, 0 the count in the button callback */
+		}
+	}
+
+	if (set_start != NULL)
+			g_object_unref (G_OBJECT (set_start));
+	if (set_end != NULL)
+			g_object_unref (G_OBJECT (set_end));
+
+	if (project_root_uri)
+		g_free (project_root_uri);
+
+	if (s->action != SA_REPLACE || sr->replace.phase != SA_REPL_CONFIRM)
+		s->busy = FALSE;
+
+	/* CHECKME any other convenient adjustments ? */
+	if (dlg && s->range.direction == SD_WHOLE &&
+		(s->action == SA_SELECT || s->action == SA_REPLACE))
+	{
+		s->range.direction = SD_FORWARD;
+		anj_sr_set_direction (sg, SD_FORWARD);
 	}
 }
 
+#define SHORT_START "... "
+
+/**
+ * anj_sr_write_match_message:
+ * @view: messageview data struct
+ * @se: searchentry data struct
+ * @project_root_uri: string for ellipsizing
+ * @rootlen: byte-length of @project_root_uri
+ *
+ * Prepare and display in message manager info about a match
+ *
+ * Return value: none
+ */
 static void
-write_message_pane(IAnjutaMessageView* view, FileBuffer *fb, SearchEntry *se,
-				   MatchInfo *mi)
+anj_sr_write_match_message (IAnjutaMessageView *view, SearchEntry *se,
+							gchar *project_root_uri, gint rootlen)
 {
+	FileBuffer *fb;
 	gchar *match_line;
-	char buf[BUFSIZ];
 	gchar *tmp;
-	
-	match_line = file_match_line_from_pos(fb, mi->pos);
+	gchar buf[BUFSIZ];
 
-	if (SE_BUFFER == se->type)
-	{
-		/* DEBUG_PRINT ("FBPATH  %s\n", fb->path); */
-		const gchar* filename = ianjuta_document_get_filename(IANJUTA_DOCUMENT(se->te), NULL);
-		tmp = g_strrstr(fb->path, "/");
-		tmp = g_strndup(fb->path, tmp + 1 -(fb->path));
-		snprintf(buf, BUFSIZ, "%s%s:%d:%s\n", tmp, filename,
-		         mi->line, match_line);
-		g_free(tmp);
-	}
-	else /* if (SE_FILE == se->type) */
+	fb = se->fb;
+
+	if (se->type == SE_BUFFER)	/* operation applied to part or all of
+									an open buffer or to all open buffers */
 	{
-		snprintf(buf, BUFSIZ, "%s:%d:%s\n", se->path, mi->line + 1, match_line);
+		/* DEBUG_PRINT ("FB URI  %s", fb->uri); */
+		tmp = fb->uri;
 	}
-	g_free(match_line);
+	else /* se->type == SE_FILE, operation applied to all project files or
+			to pattern-matching files */
+		tmp = se->uri;
+
+//	match_line = file_buffer_get_linetext_for_pos (fb, se->mi.pos);
+	match_line = file_buffer_get_linetext_for_line (fb, se->mi.line);
+	/* ellipsize uri @ start of message for files in project dir or descendant */
+	if (project_root_uri != NULL && g_str_has_prefix (tmp, project_root_uri))
+		snprintf (buf, BUFSIZ, "%s%s:%d:%s\n", SHORT_START, tmp + rootlen, se->mi.line, match_line);
+	else
+		/* FIXME omit any scheme, host, user, port, password etc from message */
+		snprintf (buf, BUFSIZ, "%s:%d:%s\n", tmp, se->mi.line, match_line);
+
+	g_free (match_line);
 	ianjuta_message_view_buffer_append (view, buf, NULL);
 }
 
+/**
+ * on_message_buffer_flush:
+ * @view: messageview data struct
+ * @one_line: string displayed as "summary" in msgman pane
+ * @data: UNUSED data specified when callback was connected
+ *
+ * Callback for "buffer-flushed" signal emitted on @view
+ *
+ * Return value: none
+ */
 static void
 on_message_buffer_flush (IAnjutaMessageView *view, const gchar *one_line,
 						 gpointer data)
@@ -682,131 +1207,396 @@
 }
 
 static gboolean
-on_message_clicked (GObject* object, gchar* message, gpointer data)
+on_message_clicked (IAnjutaMessageView *view, gchar* message, gpointer user_data)
 {
 	gchar *ptr, *ptr2;
-	gchar *path, *nline;
-	gchar *uri;
-	gint line;
-		
-	if (!(ptr = g_strstr_len(message, strlen(message), ":")) )
-		return FALSE;
-	path = g_strndup(message, ptr - message);
-	
-	ptr++;
-	if (!(ptr2 = g_strstr_len(ptr, strlen(ptr), ":")) )
+	gchar *uri, *nline;
+	line_t line;
+	gboolean condensed;
+
+	condensed = g_str_has_prefix (message, SHORT_START"/");
+	if (condensed)
+	{
+		ptr = strchr (message, ':');
+		if (ptr == NULL)
+			return FALSE;
+	}
+	else
+	{
+/*	FIXME find a valid way to pass scheme, host, user, port, password etc
+		gchar *path;
+		path = gnome_vfs_get_uri_scheme (message);
+		len = strlen (scheme);
+		g_free (scheme);
+		ptr = strchr (message + len + 1, ':');
+*/
+		ptr = strchr (message, ':');
+		if (ptr == NULL)	/* end of "file:" */
+			return FALSE;
+		ptr = strchr (ptr+1, ':');
+		if (ptr == NULL)
+			return FALSE;
+	}
+	ptr2 = strchr (ptr + 1, ':');
+	if (ptr2 == NULL)
 		return FALSE;
-	nline = g_strndup(ptr, ptr2 - ptr);
-	line = atoi(nline);
-	
-	uri = gnome_vfs_get_uri_from_local_path (path);  
-	ianjuta_document_manager_goto_uri_line_mark (sr->docman, uri, line, TRUE, NULL);
-	g_free(uri);
-	g_free(path);
-	g_free(nline);
+	if (condensed)
+	{
+		gchar *project_root_uri;
+		/* FIXME what if the project is changed before the message is clicked ? */
+		project_root_uri = NULL;
+		anjuta_shell_get (ANJUTA_PLUGIN ((IAnjutaDocumentManager *)user_data)->shell,
+						  "project_root_uri", G_TYPE_STRING,
+						  &project_root_uri, NULL);
+		if (project_root_uri != NULL)
+		{
+			gchar *freeme;
+			/* 4 is length of SHORT_START */
+			freeme = g_strndup (message + 4, ptr - message - 4);
+			uri = g_strconcat (project_root_uri, freeme, NULL);
+			g_free (freeme);
+			g_free (project_root_uri);
+		}
+		else
+			return FALSE;
+	}
+	else
+		uri = g_strndup (message, ptr - message);
+	nline = g_strndup (ptr + 1, ptr2 - ptr - 1);
+	line = atoi (nline);
+	ianjuta_document_manager_goto_uri_line_mark ((IAnjutaDocumentManager *)user_data,
+													uri, line, TRUE, NULL);
+	g_free (uri);
+	g_free (nline);
 	return FALSE;
 }
 
+/* replace search-expression string in @sr if possible */
 static void
-save_not_opened_files(FileBuffer *fb)
+anj_sr_set_search_string (SearchReplace *sr)
 {
-	FILE *fp;
+	if (sr->search.range.target != SR_SELECTION)
+	{
+		IAnjutaDocument *doc;
 
-	fp = fopen(fb->path, "wb");	
-	if (!fp)
-			return;
-	fwrite(fb->buf, fb->len, 1, fp);
-	fclose(fp);
-}
+		doc = ianjuta_document_manager_get_current_document (sr->docman, NULL);
+		if (IANJUTA_IS_EDITOR (doc))
+		{
+			IAnjutaEditor *te;
+			gchar *current_word;
 
-static gboolean
-replace_in_not_opened_files(FileBuffer *fb, MatchInfo *mi, gchar *repl_str)
-{
-	gint l;
-	g_return_val_if_fail (repl_str != NULL, FALSE);
-	
-	if (strlen(repl_str) > mi->len)
-	{
-		l = fb->len - mi->pos;
-		fb->len = fb->len + strlen(repl_str) - mi->len;
-		if ( (fb->buf = g_realloc(fb->buf, fb->len)) == NULL )
-			return FALSE;
-		memmove((fb->buf) + mi->pos + strlen(repl_str) - mi->len, fb->buf + mi->pos,l);
-	}
-	if  (strlen(repl_str) < mi->len)
-	{
-		l = fb->len - mi->pos - mi->len ;
-		memmove((fb->buf) + mi->pos + strlen(repl_str), fb->buf + mi->pos + mi->len,l);
-		fb->len = fb->len + strlen(repl_str) - mi->len;
-		if ( (fb->buf = g_realloc(fb->buf, fb->len)) == NULL)
-			return FALSE;
+			te = IANJUTA_EDITOR (doc);
+			current_word = ianjuta_editor_selection_get (IANJUTA_EDITOR_SELECTION (te), NULL);
+			if (current_word == NULL)
+				current_word = ianjuta_editor_get_current_word (te, NULL);
+			if (current_word != NULL && *current_word != 0)
+			{
+				if (strlen (current_word) > MAX_LENGTH_SEARCH)
+					current_word[MAX_LENGTH_SEARCH] = '\0';
+				g_free (sr->search.expr.search_str);
+				sr->search.expr.search_str = current_word;
+			}
+		}
 	}
-
-	for (l=0; l < strlen(repl_str); l++)
-		(fb->buf)[(mi->pos)+l] = repl_str [l];
-		
-	return TRUE;
 }
 
-
 static void
-search_replace_next_previous(SearchDirection dir)
+anj_sr_select_nearest (SearchReplace *sr, SearchDirection dir)
 {
-	SearchDirection save_direction;
-	SearchAction save_action;
-	SearchRangeType save_type;
-	
-	if (sr)
+	if (!(sr == NULL || sr->search.busy))
 	{
+		SearchAction save_action;
+		SearchRangeType save_target;
+		SearchDirection save_direction;
+
 		save_action = sr->search.action;
-		save_type = sr->search.range.type;
+		save_target = sr->search.range.target;
 		save_direction = sr->search.range.direction;
-		sr->search.range.direction = dir;	
-		if (save_type == SR_OPEN_BUFFERS || save_type == SR_PROJECT ||
-				save_type == SR_FILES)
-			sr->search.range.direction = SR_BUFFER;
+		sr->search.range.direction = dir;
+		if (save_target == SR_OPEN_BUFFERS ||
+			save_target == SR_PROJECT ||
+			save_target == SR_FILES)
+				sr->search.range.direction = SD_WHOLE;
 		sr->search.action = SA_SELECT;
-		
-		search_and_replace();
-		
+
+		anj_sr_execute (sr, TRUE);
+
 		sr->search.action = save_action;
-		sr->search.range.type = save_type;
+		sr->search.range.target = save_target;
 		sr->search.range.direction = save_direction;
-	}	
+	}
 	else
 	{
-		DEBUG_PRINT ("sr null\n");
+		DEBUG_PRINT ("busy or no sr data");
+	}
+}
+
+/**
+ * anj_sr_select_next:
+ * @sg: Pointer to search data struct
+ *
+ * Backend for action callback on_findnext1_activate, etc
+ *
+ * Return value: None
+ */
+void
+anj_sr_select_next (SearchReplaceGUI *sg)
+{
+	SearchReplace *sr;
+
+	if (sg == NULL || sg->dialog == NULL)
+	{
+		sr = search_get_default_data ();
+		if (sr == NULL)
+			return;
+		anj_sr_create_dialog (sr);
+		anj_sr_set_search_string (sr); /* not overwritten by anythig in active search */
+	}
+	else
+	{
+		sr = sg->sr;
+		anj_sr_populate_dialog (sg);
+	}
+	anj_sr_select_nearest (sr, SD_FORWARD);
+}
+
+/**
+ * anj_sr_select_previous:
+ * @sg: Pointer to search data struct
+ *
+ * Backend for action callback on_findprevious1_activate, etc
+ *
+ * Return value: None
+ */
+void
+anj_sr_select_previous (SearchReplaceGUI *sg)
+{
+	SearchReplace *sr;
+
+	if (sg == NULL || sg->dialog == NULL)
+	{
+		sr = search_get_default_data ();
+		if (sr == NULL)
+			return;
+		anj_sr_create_dialog (sr);
+		anj_sr_set_search_string (sr); /* not overwritten by anythig in active search */
+	}
+	else
+	{
+		sr = sg->sr;
+		anj_sr_populate_dialog (sg);
+	}
+	anj_sr_select_nearest (sr, SD_BACKWARD);
+}
+
+/* there's no gui involved in this action */
+void
+anj_sr_list_all_uses (const gchar *symbol)
+{
+	gchar *project_root_uri;
+	AnjutaShell* shell;
+	SearchReplace *sr;
+
+	sr = search_replace_data_new ();
+	sr->search.expr.search_str = g_strdup (symbol);
+	sr->search.expr.ignore_case = TRUE;	//CHECKME
+	sr->search.expr.whole_word = TRUE;
+	sr->search.expr.no_limit = TRUE;
+	sr->search.expr.actions_max = G_MAXINT;
+
+	g_object_get (G_OBJECT(sr->docman), "shell", &shell, NULL);
+	project_root_uri = NULL;
+	anjuta_shell_get (shell, "project_root_uri", G_TYPE_STRING,
+					  &project_root_uri, NULL);
+	sr->search.range.target =
+		project_root_uri != NULL ? SR_PROJECT : SR_OPEN_BUFFERS;
+	g_free (project_root_uri);
+
+	sr->search.range.direction = SD_WHOLE;
+
+//	sr->search.range.files.ignore_binary_files = TRUE;
+	sr->search.range.files.ignore_hidden_files = TRUE;
+	sr->search.range.files.ignore_hidden_dirs = TRUE;
+	sr->search.range.files.recurse = TRUE;
+	sr->search.action = SA_FIND_PANE;
+	sr->search.incremental_wrap = TRUE;
+
+	anj_sr_execute (sr, FALSE);	/* no dialog usage */
+
+	search_replace_data_destroy (sr);
+}
+
+/**
+ * anj_sr_activate:
+ * @replace: TRUE if operation involves replacement
+ * @project: TRUE if operation spans all project files
+ *
+ * Backend for action callbacks: on_find1, on_find_and_replace1, on_find_in_files1
+ * These may be used before there is a s/r dialog - one will be created if needed
+ *
+ * Return value: None
+ */
+void
+anj_sr_activate (gboolean replace, gboolean project)
+{
+	SearchReplaceGUI *sg;
+	SearchReplace *sr;
+	GtkWidget *search_entry, *combo;
+
+	sg = NULL;
+	sr = NULL;
+	anj_sr_get_best_uidata (&sg, &sr);
+
+	if (sr->search.busy)
+		return;
+
+	if (sg == NULL || sg->dialog == NULL)
+	{
+		anj_sr_create_dialog (sr);
+		sg = sr->sg;
+	}
+
+	search_entry = anj_sr_get_ui_widget (SEARCH_STRING);
+
+	anj_sr_reset_flags (sr);	/* CHECKME selection flag ? just sr->replace.phase = SA_REPL_FIRST; ?*/
+	if (!(sg->showing || replace || project))
+	{
+		/* update the backend search string, it will be be over-written if the
+		   active search includes a specified search string */
+		anj_sr_set_search_string (sr);
+	}
+	else /* sg->showing || replace || project */
+	{
+		if (sg->showing)
+		{
+			anj_sr_populate_data (sg);
+			anj_sr_set_search_string (sr);
+			if (search_entry)
+				gtk_entry_set_text (GTK_ENTRY (search_entry),
+									sr->search.expr.search_str);
+		}
+		else
+		{
+			anj_sr_set_search_string (sr);
+			anj_sr_populate_dialog (sg);
+		}
+
+		anj_sr_reset_replace_buttons (sg);
+
+		if (replace)
+		{
+			if (!(sr->search.action == SA_REPLACE ||
+				  sr->search.action == SA_REPLACEALL))
+			{
+				anj_sr_set_action (sg, SA_REPLACE);
+				sr->search.action = SA_REPLACE;
+				anj_sr_show_replace (sg, TRUE);
+			}
+		}
+		else
+		{
+			if (sr->search.action == SA_REPLACE ||
+				sr->search.action == SA_REPLACEALL)
+			{
+				anj_sr_set_action(sg, SA_SELECT);
+				sr->search.action = SA_SELECT;
+				anj_sr_show_replace (sg, FALSE);
+			}
+		}
+		if (sr->search.action != SA_REPLACEALL)
+			anj_sr_modify_button (sg, SEARCH_BUTTON, button_search_label, GTK_STOCK_FIND);
+		else
+			anj_sr_modify_button (sg, SEARCH_BUTTON, button_replace_all_label, GTK_STOCK_FIND_AND_REPLACE);
+
+		if (project)
+		{
+			anj_sr_set_target (sg, SR_PROJECT);
+			if (!replace)
+			{
+				anj_sr_set_action (sg, SA_FIND_PANE);
+				anj_sr_set_direction (sg, SD_WHOLE);
+			}
+		}
+		anj_sr_show_replace_button (sg, FALSE);	/* hide the replace button */
+		anj_sr_enable_replace_button (sg, FALSE);
+	}
+
+	if (search_entry)
+	{
+		gtk_editable_select_region (GTK_EDITABLE (search_entry), 0, -1);
+//		gtk_widget_grab_focus (search_entry);
 	}
-}
 
-void
-search_replace_next(void)
-{
-	search_replace_next_previous(SD_FORWARD);
+	combo = anj_sr_get_ui_widget (SEARCH_ACTION_COMBO);
+	if (combo)
+		gtk_widget_grab_focus (combo);
+
+	/* Show the dialog */
+	anj_sr_present_dialog (sg);
 }
 
+/**
+ * anj_sr_repeat:
+ * @sg: pointer to sr data struct containing operation data
+ *
+ * Repeat previous main (i.e. not-incremental) search operation, using data
+ * from that time
+ *
+ * Return value: none
+ */
 void
-search_replace_previous(void)
+anj_sr_repeat (SearchReplaceGUI *sg)
 {
-	search_replace_next_previous(SD_BACKWARD);
+	SearchReplace *sr;
+
+	anj_sr_get_best_uidata (&sg, &sg->sr);
+	sr = sg->sr;
+
+	if (!sr->search.busy
+		/* minimal check for whether there was a prior search */
+		&& anj_sr_create_dialog (sr)
+		&& (sr->search.expr.search_str || sr->search.expr.re))
+	{
+		anj_sr_execute (sr, TRUE);
+		/* show search dialog if currently hidden */
+		if (!sg->showing)
+		{
+			gtk_widget_show (sg->dialog);
+			sg->showing = TRUE;
+		}
+	}
 }
 
 /****************************************************************/
 
-GladeWidget *
-sr_get_gladewidget(GladeWidgetId id)
+/**
+ * anj_sr_is_idle:
+ * @sg: pointer to dialog data struct or NULL
+ *
+ * Check whether a search is in progress now
+ *
+ * Return value: TRUE if sg is non-NULL and no search (involving current sr data) is busy
+ */
+static gboolean
+anj_sr_is_idle (SearchReplaceGUI *sg)
 {
-	return &glade_widgets[id];
+	SearchReplace *sr;
+
+	if (sg == NULL)
+		return FALSE;
+	sr = sg->sr;
+	g_return_val_if_fail (sr, TRUE);
+	return !sr->search.busy;
 }
 
 static void
-search_set_popdown_strings (GtkComboBoxEntry *combo, GList* strings)
+anj_sr_set_popdown_strings (GtkComboBoxEntry *combo, GList* strings)
 {
 	GtkListStore *store;
 	gboolean init;
 
 	init = gtk_combo_box_get_model (GTK_COMBO_BOX(combo)) == NULL;
-		
+
 	store = gtk_list_store_new (1, G_TYPE_STRING);
 	for (; strings != NULL; strings = g_list_next(strings))
 	{
@@ -817,19 +1607,19 @@
 	}
 	gtk_combo_box_set_model (GTK_COMBO_BOX(combo), GTK_TREE_MODEL (store));
 	g_object_unref (store);
-	
-	if (init) gtk_combo_box_entry_set_text_column (combo, 0);	
+
+	if (init) gtk_combo_box_entry_set_text_column (combo, 0);
 }
 
 static void
-search_set_popdown_map (GtkComboBox *combo, AnjutaUtilStringMap *map)
+anj_sr_set_popdown_map (GtkComboBox *combo, AnjutaUtilStringMap *map)
 {
 	GtkListStore *store;
 	gboolean init;
 	gint i;
 
 	init = gtk_combo_box_get_model (combo) == NULL;
-		
+
 	store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
 	for (i = 0; map[i].type != -1; ++i)
 	{
@@ -841,11 +1631,11 @@
 	gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
 	g_object_unref (store);
 	gtk_combo_box_set_active (combo, 0);
-	
+
 	if (init)
 	{
-		GtkCellRenderer *cell;		
-		
+		GtkCellRenderer *cell;
+
 		cell = gtk_cell_renderer_text_new ();
   		gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
   		gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
@@ -854,7 +1644,7 @@
 }
 
 static void
-search_select_item(GtkComboBox* combo, gint item)
+anj_sr_activate_combo_item (GtkComboBox *combo, gint item)
 {
 	GtkTreeModel *model;
 	GtkTreeIter iter;
@@ -867,13 +1657,12 @@
 		 gtk_tree_model_iter_next (model, &iter))
 	{
 		gint id;
-		
+
 		gtk_tree_model_get (model, &iter, 1, &id, -1);
-		
+
 		if (id == item)
 		{
-			/* Find command */
-			gtk_combo_box_set_active_iter(combo, &iter);
+			gtk_combo_box_set_active_iter (combo, &iter);
 			break;
 		}
 	}
@@ -881,655 +1670,927 @@
 }
 
 static void
-search_set_combo(GladeWidgetId id_combo, gint command)
+anj_sr_activate_combo_id_item (SearchReplaceGUI *sg, GUIElementId id_combo, gint item)
 {
-	GtkComboBox *combo;
-	
-	combo = GTK_COMBO_BOX(sr_get_gladewidget(id_combo)->widget);
-	search_select_item (combo, command);	
+	if (anj_sr_is_idle (sg))
+	{
+		GtkComboBox *combo;
+
+		combo = GTK_COMBO_BOX (anj_sr_get_ui_widget (id_combo));
+		anj_sr_activate_combo_item (combo, item);
+	}
 }
 
 static void
-search_set_action(SearchAction action)
+anj_sr_set_action (SearchReplaceGUI *sg, SearchAction action)
 {
-	search_set_combo(SEARCH_ACTION_COMBO, action); 
+	anj_sr_activate_combo_id_item (sg, SEARCH_ACTION_COMBO, action);
 }
 
 static void
-search_set_target(SearchRangeType target)
+anj_sr_set_target (SearchReplaceGUI *sg, SearchRangeType target)
 {
-	search_set_combo(SEARCH_TARGET_COMBO, target);
+	anj_sr_activate_combo_id_item (sg, SEARCH_TARGET_COMBO, target);
 }
 
+/* set "direction" radio-button */
 static void
-search_set_direction(SearchDirection dir)
+anj_sr_set_direction (SearchReplaceGUI *sg, SearchDirection dir)
+{
+	if (anj_sr_is_idle (sg))
+	{
+		GUIElementId id;
+		GtkWidget *widget;
+
+		switch (dir)
+		{
+//			case SD_WHOLE:
+			default:
+				id = SEARCH_WHOLE;
+				break;
+			case SD_FORWARD:
+				id = SEARCH_FORWARD;
+				break;
+			case SD_BACKWARD:
+				id = SEARCH_BACKWARD;
+				break;
+		}
+		widget = anj_sr_get_ui_widget (id);
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+	}
+}
+
+/* get enumerator for active radio-button */
+static SearchDirection
+anj_sr_get_direction (SearchReplaceGUI *sg)
 {
-	search_set_combo(SEARCH_DIRECTION_COMBO, dir);
+	gint i;
+	GUIElementId dir_widgets[] =
+	{
+		SEARCH_WHOLE, SEARCH_FORWARD, SEARCH_BACKWARD
+	};
+	SearchDirection id[] =
+	{
+		SD_WHOLE, SD_FORWARD, SD_BACKWARD
+	};
+
+	for (i = 0; i < 3; i++)
+	{
+		GtkWidget *widget;
+
+		widget = sg->widgets[dir_widgets[i]];
+		if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+			return (id[i]);
+	}
+	return SD_FORWARD;
 }
 
 static gint
-search_get_item_combo(GtkComboBox *combo)
+anj_sr_get_combo_active_value (GtkComboBox *combo)
 {
 	gint item;
 	GtkTreeModel *model;
 	GtkTreeIter iter;
 	gboolean sel;
-	
+
 	sel = gtk_combo_box_get_active_iter (combo, &iter);
 	model = gtk_combo_box_get_model (combo);
 	gtk_tree_model_get (model, &iter, 1, &item, -1);
-		
+
 	return item;
 }
 
 static gint
-search_get_item_combo_name(GladeWidgetId id)
+anj_sr_get_combo_id_active_value (SearchReplaceGUI *sg, GUIElementId id)
 {
-	GtkWidget *combo = sr_get_gladewidget(id)->widget;
-	return search_get_item_combo(GTK_COMBO_BOX(combo));
+	GtkWidget *combo = anj_sr_get_ui_widget (id);
+	return anj_sr_get_combo_active_value (GTK_COMBO_BOX (combo));
 }
 
 static void
-search_direction_changed(SearchDirection dir)
+anj_sr_conform_direction_change (SearchReplaceGUI *sg, SearchDirection dir)
 {
-	SearchEntryType tgt;
-	SearchAction act;
-	
-	tgt = search_get_item_combo_name(SEARCH_TARGET_COMBO);
-	if (dir != SD_BEGINNING)
+	SearchRangeType tgt;
+
+	tgt = anj_sr_get_combo_id_active_value (sg, SEARCH_TARGET_COMBO);
+	if (dir != SD_WHOLE)
 	{
-		if (tgt == SR_OPEN_BUFFERS || tgt == SR_PROJECT
-				   || tgt == SR_FILES)
-			search_set_target(SR_BUFFER);
+		/* can only go forward|backward in current file, selection, function or block */
+		if (tgt == SR_OPEN_BUFFERS || tgt == SR_PROJECT || tgt == SR_FILES)
+			anj_sr_set_target (sg, SR_BUFFER);
 	}
-	else
+/*	else	/ * search in all of something * /
 	{
-		if (tgt == SR_BUFFER ||tgt == SR_SELECTION || tgt == SR_BLOCK ||
-				tgt == SR_FUNCTION)
-			search_set_target(SR_BUFFER);
-		else
+		if ((tgt == SR_BUFFER ||tgt == SR_SELECTION
+			|| tgt == SR_FUNCTION || tgt == SR_BLOCK))
 		{
-			act = search_get_item_combo_name(SEARCH_ACTION_COMBO);
+			SearchAction act;
+
+			act = anj_sr_get_combo_id_active_value (sg, SEARCH_ACTION_COMBO);
 			if (act == SA_SELECT)
-				search_set_action(SA_BOOKMARK);
-			if (act == SA_REPLACE)
-				search_set_action(SA_REPLACEALL);				
+				anj_sr_set_action (sg, SA_BOOKMARK);
 		}
 	}
+*/
 }
 
+/* this assumes an upstream busy-check is ok */
 static void
-populate_value(GladeWidgetId id, gpointer val_ptr)
+anj_sr_populate_value (SearchReplaceGUI *sg, GUIElementId id, gpointer val_ptr)
 {
-	GladeWidget *gw;
+	GtkWidget *widget;
 
-	g_return_if_fail(id && val_ptr);
-	
-	gw = sr_get_gladewidget(id);
-	g_return_if_fail(gw);
-	switch(gw->type)
+	g_return_if_fail (id >=0 && id < GUI_ELEMENT_COUNT);
+	g_return_if_fail (val_ptr);
+
+	widget = sg->widgets[id];
+
+	switch (glade_widgets[id].type) /* lookup static data */
 	{
 		case GE_COMBO_ENTRY:
 		case GE_TEXT:
-			if (*((char **) val_ptr))
-				g_free(* ((char **) val_ptr));
-			*((char **) val_ptr) = gtk_editable_get_chars(
-			  GTK_EDITABLE(gw->widget), 0, -1);
+			if (*((gchar **) val_ptr))
+				g_free(* ((gchar **) val_ptr));
+			*((gchar **) val_ptr) = gtk_editable_get_chars
+				(GTK_EDITABLE (widget), 0, -1);
 			break;
 		case GE_BOOLEAN:
-			* ((gboolean *) val_ptr) = gtk_toggle_button_get_active(
-			  GTK_TOGGLE_BUTTON(gw->widget));
+			*((gboolean *) val_ptr) = gtk_toggle_button_get_active
+			(GTK_TOGGLE_BUTTON (widget));
 			break;
 		case GE_COMBO:
-			g_return_if_fail (gw->extra != NULL);
-
-			*((int *) val_ptr) = search_get_item_combo (GTK_COMBO_BOX(gw->widget));
+			g_return_if_fail (glade_widgets[id].extra != NULL);
+			*((gint *) val_ptr) = anj_sr_get_combo_active_value
+				(GTK_COMBO_BOX (widget));
 			break;
 		default:
-			g_warning("Bad option %d to populate_value", gw->type);
+			g_warning ("Bad option %d to anj_sr_populate_value", glade_widgets[id].type);
 			break;
 	}
 }
 
 static void
-reset_flags(void)
+anj_sr_reset_flags (SearchReplace *sr)
 {
-	flag_select = FALSE;
-	interactive = FALSE;
+	if (!sr->search.busy)
+	{
+		sr->search.limited = FALSE;
+		sr->replace.phase = SA_REPL_FIRST;
+	}
 }
 
 static void
-reset_flags_and_search_button(void)
+anj_sr_reset_replace_buttons (SearchReplaceGUI *sg)
 {
-	reset_flags();
-	if (sr->search.action != SA_REPLACEALL)
-		modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
-
+	if (sg->sr->search.action != SA_REPLACEALL)
+		anj_sr_modify_button (sg, SEARCH_BUTTON, button_search_label, GTK_STOCK_FIND);
 	else
-		modify_label_image_button(SEARCH_BUTTON, _("Replace All"), 
-			                      GTK_STOCK_FIND_AND_REPLACE);
-
-	show_jump_button(FALSE);
-}
+		anj_sr_modify_button (sg, SEARCH_BUTTON, button_replace_all_label, GTK_STOCK_FIND_AND_REPLACE);
 
-static void
-search_start_over (SearchDirection direction)
-{
-	IAnjutaDocument* doc = ianjuta_document_manager_get_current_document(sr->docman,
-																		NULL);
-	IAnjutaEditor *te = NULL;
-	if (IANJUTA_IS_EDITOR(doc))
-		te = IANJUTA_EDITOR(doc);
-	
-	if (te)
-	{
-		if (direction != SD_BACKWARD)
-			/* search from doc start */
-			ianjuta_editor_goto_start (te, NULL);
-		else
-			/* search from doc end */
-			ianjuta_editor_goto_end (te, NULL);
-	}
+	anj_sr_show_replace_button (sg, FALSE);	/* hide the replace button */
+	anj_sr_enable_replace_button (sg, FALSE);
 }
 
-static void 
-search_end_alert(gchar *string)
+/* returns true if the user is allowed to and wants to roll around to the other end */
+static gboolean
+anj_sr_end_alert (SearchReplace *sr)
 {
 	GtkWidget *dialog;
-	
-	if (sr->search.range.direction != SD_BEGINNING && !flag_select)
+	gboolean retval;
+
+	if (sr->search.range.target == SR_BUFFER && sr->search.range.direction != SD_WHOLE)
 	{
 		// Ask if user wants to wrap around the doc
 		// Dialog to be made HIG compliant.
-		dialog = gtk_message_dialog_new (GTK_WINDOW (sg->dialog),
+		dialog = gtk_message_dialog_new (GTK_WINDOW (sr->sg->dialog),
 					GTK_DIALOG_DESTROY_WITH_PARENT,
 					GTK_MESSAGE_QUESTION,
 					GTK_BUTTONS_YES_NO,
 					_("The match \"%s\" was not found. Wrap search around the document?"),
-					string);
+					sr->search.expr.search_str);
 
 		gtk_dialog_set_default_response (GTK_DIALOG (dialog),
 										 GTK_RESPONSE_YES);
-		g_signal_connect(G_OBJECT(dialog), "key-press-event",
-			G_CALLBACK(on_search_dialog_key_press_event), NULL);
-		if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES)
-		{
-			search_start_over (sr->search.range.direction);
-			gtk_widget_destroy(dialog);
-			reset_flags();
-			search_and_replace ();
-			return;
-		}
+		g_signal_connect (G_OBJECT(dialog), "key-press-event",
+						G_CALLBACK(on_search_dialog_key_press), sr->sg);
+		retval = (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES);
 	}
 	else
 	{
-		dialog = gtk_message_dialog_new(GTK_WINDOW (sg->dialog),
+		dialog = gtk_message_dialog_new (GTK_WINDOW (sr->sg->dialog),
 					GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
-					_("The match \"%s\" was not found."),
-		        	string);
-		g_signal_connect(G_OBJECT(dialog), "key-press-event",
-			G_CALLBACK(on_search_dialog_key_press_event), NULL);
-		gtk_dialog_run(GTK_DIALOG(dialog));
-	}	
-	gtk_widget_destroy(dialog);
-	reset_flags();
+					_("The match \"%s\" was not found."), sr->search.expr.search_str);
+		g_signal_connect (G_OBJECT (dialog), "key-press-event",
+						G_CALLBACK(on_search_dialog_key_press), sr->sg);
+		gtk_dialog_run (GTK_DIALOG (dialog));
+		retval = FALSE;
+	}
+	gtk_widget_destroy (dialog);
+	return retval;
 }
 
-static void 
-max_results_alert(void)
+static void
+anj_sr_max_results_alert (SearchReplace *sr)
 {
-	GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW (sg->dialog),
+	GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW (sr->sg->dialog),
 				GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
 		        	_("The maximum number of results has been reached."));
-	g_signal_connect(G_OBJECT(dialog), "key-press-event",
-			G_CALLBACK(on_search_dialog_key_press_event), NULL);
-	gtk_dialog_run(GTK_DIALOG(dialog));
-	gtk_widget_destroy(dialog);
-	reset_flags();
+	g_signal_connect (G_OBJECT (dialog), "key-press-event",
+					G_CALLBACK(on_search_dialog_key_press), sr->sg);
+	gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (dialog);
+	anj_sr_reset_flags (sr);
 }
 
-static void 
-nb_results_alert(gint nb)
+static void
+anj_sr_total_results_alert (SearchReplace *sr)
 {
-	GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW (sg->dialog),
+	GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW (sr->sg->dialog),
 				GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
-		        	ngettext("%d match has been replaced.",
-							 "%d matches have been replaced.", nb), nb);
-	g_signal_connect(G_OBJECT(dialog), "key-press-event",
-			G_CALLBACK(on_search_dialog_key_press_event), NULL);
-	gtk_dialog_run(GTK_DIALOG(dialog));
-	gtk_widget_destroy(dialog);
-	reset_flags();
+		        	_("%u matches have been replaced."), sr->search.matches_sofar);
+	g_signal_connect (G_OBJECT (dialog), "key-press-event",
+					G_CALLBACK(on_search_dialog_key_press), sr->sg);
+	gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (dialog);
+	anj_sr_reset_flags (sr);
 }
 
 static void
-search_show_replace(gboolean hide)
+anj_sr_show_replace (SearchReplaceGUI *sg, gboolean hide)
 {
-	static GladeWidgetId hide_widgets[] = {
+	GUIElementId hide_widgets[] =
+	{
 		REPLACE_REGEX, REPLACE_STRING_COMBO, LABEL_REPLACE
 	};
-	int i;
+	gint i;
 	GtkWidget *widget;
-	
-	for (i=0; i < sizeof(hide_widgets)/sizeof(hide_widgets[0]); ++i)
+
+	for (i = 0; i < sizeof(hide_widgets)/sizeof(hide_widgets[0]); i++)
 	{
-		widget = sr_get_gladewidget(hide_widgets[i])->widget;
-		if (NULL != widget)
+		widget = anj_sr_get_ui_widget (hide_widgets[i]);
+		if (widget != NULL)
 		{
-			if (hide)
-				gtk_widget_show(widget);
+			if (hide)	/* CHECKME */
+				gtk_widget_show (widget);
 			else
-				gtk_widget_hide(widget);
+				gtk_widget_hide (widget);
 		}
 	}
 }
 
+/* change label and/or image of button whose id is @button_id*/
 static void
-modify_label_image_button(GladeWidgetId button_id, gchar *name, char *stock_image)
+anj_sr_modify_button (SearchReplaceGUI *sg, GUIElementId button_id,
+					  const gchar *name, const gchar *stock_id)
 {
-	GList *list, *l;
-	GtkHBox *hbox;
-	GtkWidget *alignment;
-	GtkWidget *button = sr_get_gladewidget(button_id)->widget;
-	
-	list = gtk_container_get_children(GTK_CONTAINER (button));
-	alignment = GTK_WIDGET(list->data);
-	g_list_free(list);		
-	list = gtk_container_get_children(GTK_CONTAINER (alignment));
-	hbox = GTK_HBOX(list->data);
-	g_list_free(list);
-	list = gtk_container_get_children(GTK_CONTAINER (hbox));
-	for (l=list; l; l = g_list_next(l))
-	{
-		if (GTK_IS_LABEL(l->data))
-			gtk_label_set_text(GTK_LABEL(l->data), name);
-		if (GTK_IS_IMAGE(l->data))
-			gtk_image_set_from_stock(GTK_IMAGE(l->data), stock_image, 
-									 GTK_ICON_SIZE_BUTTON);
+	GtkWidget *button;
+
+	button = anj_sr_get_ui_widget (button_id);
+
+	if (name == NULL)
+		name = "";
+	gtk_button_set_label (GTK_BUTTON (button), name);
+
+
+	if (stock_id != NULL)
+	{
+		/* FIXME handle non-stock images too */
+		GtkWidget *image;
+		image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
+		gtk_button_set_image (GTK_BUTTON (button), image);
 	}
-	g_list_free(list);
+	else
+		gtk_button_set_image (GTK_BUTTON (button), NULL);
 }
 
-
 /********************************************************************/
 
-#define POP_LIST(str, var) populate_value(str, &s);\
-			if (s) \
-			{\
-				sr->search.range.files.var = anjuta_util_glist_from_string(s);\
-			}
-			
+#define POP_LIST(indx,listvar)\
+	s = NULL; anj_sr_populate_value(sg,indx,&s);\
+	if (s != NULL)\
+	{ anjuta_util_glist_strings_free (sr->search.range.files.listvar);\
+	  sr->search.range.files.listvar = anjuta_util_glist_from_string(s); }
+
 /********************************************************************/
 
+/**
+ * anj_sr_populate_data:
+ * @sr: pointer to search/replace data struct
+ *
+ * Populate @sr with values from the GUI
+ *
+ * Return value: none
+ */
 void
-search_replace_populate(void)
+anj_sr_populate_data (SearchReplaceGUI *sg)
 {
-	char *s = NULL;
-	char *max = NULL;
-	
-	/* Now, populate the instance with values from the GUI */
-	populate_value(SEARCH_STRING, &(sr->search.expr.search_str));
-	populate_value(SEARCH_REGEX, &(sr->search.expr.regex));
-	populate_value(GREEDY, &(sr->search.expr.greedy));
-	populate_value(IGNORE_CASE, &(sr->search.expr.ignore_case));
-	populate_value(WHOLE_WORD, &(sr->search.expr.whole_word));
-	populate_value(WHOLE_LINE, &(sr->search.expr.whole_line));
-	populate_value(WORD_START, &(sr->search.expr.word_start));
-	populate_value(SEARCH_TARGET_COMBO, &(sr->search.range.type));
-	populate_value(SEARCH_DIRECTION_COMBO, &(sr->search.range.direction));
-	populate_value(ACTIONS_NO_LIMIT, &(sr->search.expr.no_limit));
+	SearchReplace *sr;
+	gchar *s;
+
+	g_return_if_fail (sg->dialog);
+
+	sr = sg->sr;
+	if (sr == NULL)
+	{
+		sr = sg->sr = search_get_default_data (); //FIXME non-static
+	}
+	if (sr->search.busy)
+		return;
+
+	anj_sr_populate_value (sg, SEARCH_STRING, &(sr->search.expr.search_str));
+	anj_sr_populate_value (sg, SEARCH_REGEX, &(sr->search.expr.regex));
+	anj_sr_populate_value (sg, IGNORE_CASE, &(sr->search.expr.ignore_case));
+	anj_sr_populate_value (sg, WHOLE_WORD, &(sr->search.expr.whole_word));
+	anj_sr_populate_value (sg, WHOLE_LINE, &(sr->search.expr.whole_line));
+	anj_sr_populate_value (sg, WORD_START, &(sr->search.expr.word_start));
+	anj_sr_populate_value (sg, GREEDY, &(sr->search.expr.greedy));
+	anj_sr_populate_value (sg, REPLACE_REGEX, &(sr->replace.regex));
+	anj_sr_populate_value (sg, SEARCH_TARGET_COMBO, &(sr->search.range.target));
+	sr->search.range.direction = anj_sr_get_direction (sg);
+	anj_sr_populate_value (sg, ACTIONS_NO_LIMIT, &(sr->search.expr.no_limit));
+//	anj_sr_populate_value (SEARCH_BASIC, &(sr->search.basic_search));
 
-	populate_value(SEARCH_BASIC, &(sr->search.basic_search));
-	
 	if (sr->search.expr.no_limit)
-		sr->search.expr.actions_max = G_MAXINT;	
+		sr->search.expr.actions_max = G_MAXINT;
 	else
 	{
-		populate_value(ACTIONS_MAX, &(max));
-		sr->search.expr.actions_max = atoi(max);
-		if (sr->search.expr.actions_max <= 0)
-			sr->search.expr.actions_max = 200;
-		g_free(max);
+		gchar *max = NULL;
+
+		anj_sr_populate_value (sg, ACTIONS_MAX, &(max));
+		if (max)
+		{
+			sr->search.expr.actions_max = atoi (max);
+			if (sr->search.expr.actions_max <= 0)
+				sr->search.expr.actions_max = 200;
+			g_free (max);
+		}
+		else
+			sr->search.expr.actions_max = 1;
 	}
 
-	switch (sr->search.range.type)
+	switch (sr->search.range.target)
 	{
-		case SR_FUNCTION:
+		case SR_FUNCTION:	/* CHECKME this seems wrong */
 		case SR_BLOCK:
-			if (flag_select)
-				sr->search.range.type = SR_SELECTION;
+			if (sr->search.limited)
+			/* CHECKME why is this setting used for all limited-scope operations */
+				sr->search.range.target = SR_SELECTION;
 			break;
 		case SR_FILES:
-			POP_LIST(MATCH_FILES, match_files);
-			POP_LIST(UNMATCH_FILES, ignore_files);
-			POP_LIST(MATCH_DIRS, match_dirs);
-			POP_LIST(UNMATCH_DIRS, ignore_dirs);
-		    populate_value(IGNORE_HIDDEN_FILES, &(sr->search.range.files.ignore_hidden_files));
-		    populate_value(IGNORE_HIDDEN_DIRS, &(sr->search.range.files.ignore_hidden_dirs));
-		    populate_value(SEARCH_RECURSIVE, &(sr->search.range.files.recurse));
-			break;
+			POP_LIST (MATCH_FILES, match_files);
+			if (sr->search.range.files.match_files == NULL)
+				sr->search.range.files.match_files = g_list_prepend (NULL, g_strdup ("*"));
+			POP_LIST (UNMATCH_FILES, ignore_files);
+			POP_LIST (MATCH_DIRS, match_dirs);
+			if (sr->search.range.files.match_dirs == NULL)
+				sr->search.range.files.match_dirs = g_list_prepend (NULL, g_strdup ("*"));
+			POP_LIST (UNMATCH_DIRS, ignore_dirs);
+		    anj_sr_populate_value (sg, SEARCH_RECURSIVE, &(sr->search.range.files.recurse));
+//		    anj_sr_populate_value (sg, IGNORE_BINARY_FILES, &(sr->search.range.files.ignore_binary_files));
+		    anj_sr_populate_value (sg, IGNORE_HIDDEN_FILES, &(sr->search.range.files.ignore_hidden_files));
+		    anj_sr_populate_value (sg, IGNORE_HIDDEN_DIRS, &(sr->search.range.files.ignore_hidden_dirs));
 		default:
 			break;
 	}
-	populate_value(SEARCH_ACTION_COMBO, &(sr->search.action));
+	anj_sr_populate_value (sg, SEARCH_ACTION_COMBO, &(sr->search.action));
 	switch (sr->search.action)
 	{
 		case SA_REPLACE:
 		case SA_REPLACEALL:
-			populate_value(REPLACE_STRING, &(sr->replace.repl_str));
-			populate_value(REPLACE_REGEX, &(sr->replace.regex));
-			break;
+			anj_sr_populate_value (sg, REPLACE_STRING, &(sr->replace.repl_str));
+			anj_sr_populate_value (sg, REPLACE_REGEX, &(sr->replace.regex));
 		default:
 			break;
 	}
 }
 
 static void
-show_jump_button (gboolean show)
+anj_sr_show_replace_button (SearchReplaceGUI *sg, gboolean show)
 {
-	GtkWidget *jump_button = sr_get_gladewidget(JUMP_BUTTON)->widget;
+	GtkWidget *button;
+
+	button = anj_sr_get_ui_widget (REPLACE_BUTTON);
 	if (show)
-		gtk_widget_show(jump_button);
+		gtk_widget_show (button);
 	else
-		gtk_widget_hide(jump_button);
+		gtk_widget_hide (button);
 }
 
-static
-void translate_dialog_strings (AnjutaUtilStringMap labels[])
+static void
+anj_sr_enable_replace_button (SearchReplaceGUI *sg, gboolean sensitive)
+{
+	GtkWidget *button;
+
+	button = anj_sr_get_ui_widget (REPLACE_BUTTON);
+	gtk_widget_set_sensitive (button, sensitive);
+}
+
+/**
+ * anj_sr_get_current_uidata:
+ *
+ * Get pointer to static data struct with search-dialog data
+ *
+ * Return value: the data
+ */
+SearchReplaceGUI *
+anj_sr_get_default_uidata (void)
+{
+	/* CHECKME relevance of other sg* when a search is active */
+	return def_sg;
+}
+
+/**
+ * anj_sr_get_best_uidata:
+ * sg: store for pointer to gui data, or NULL if not wanted
+ * sr: store for pointer to s/r data, or NULL if not wanted
+ *
+ * Get pointers to search data
+ *
+ * Return value: None
+ */
+void
+anj_sr_get_best_uidata (SearchReplaceGUI **sg, SearchReplace **sr)
 {
-	guint i = 0;
-	while (labels[i].name != NULL)
+	if (sg != NULL)
 	{
-		labels[i].name = gettext (labels[i].name);
-		i++;
+		if (*sg == NULL)
+			*sg = def_sg;	/* FIXME find any other current dialog ?? */
+		if (sr != NULL)
+		{
+			if (*sg != NULL && (*sg)->sr != NULL)
+				*sr = (*sg)->sr;
+			else
+				*sr = search_get_default_data ();
+		}
+	}
+	else /* sg == NULL */
+		if (sr != NULL)
+	{
+		*sr = search_get_default_data ();
 	}
 }
 
+SearchReplaceGUI *
+anj_sr_get_current_uidata (GtkWidget *widget)
+{
+	GtkWidget *window;
+	gpointer data;
+
+	window = gtk_widget_get_toplevel (widget);
+	g_return_val_if_fail (GTK_WIDGET_TOPLEVEL (window), NULL);
+
+	data = g_object_get_data (G_OBJECT (window), SEARCH_GUI_KEY);
+	g_return_val_if_fail (data != NULL, NULL);
+	return (SearchReplaceGUI *) data;
+}
+
+void
+anj_sr_set_dialog_searchdata (SearchReplaceGUI *sg, SearchReplace *sr)
+{
+	g_return_if_fail (sg && sr);
+	sg->sr = sr;
+	sr->sg = sg;
+}
+
+static
+void anj_sr_translate_dialog_strings (AnjutaUtilStringMap labels[])
+{
+	guint i;
+
+	for (i = 0; labels[i].name != NULL; i++)
+		labels[i].name = gettext (labels[i].name);
+}
+
+/**
+ * anj_sr_create_dialog:
+ * @sr: s/r data struct, currently this assumes there's only one of those
+ *
+ * Create a new s/r dialog, with settings initialised from preferences data
+ * Dialog is not shown, as widget values may need to be changed before that happens
+ *
+ * Return value: the data
+ */
 static gboolean
-create_dialog(void)
+anj_sr_create_dialog (SearchReplace *sr)
 {
-	GladeWidget *w;
+	static gboolean labels_translated = FALSE; /* ensure dialog labels are translated only once */
+	SearchReplaceGUI *sg;
 	GtkWidget *widget;
-	int i;
+	GladeXML *xml;
+	gint i;
+
+	g_return_val_if_fail (sr != NULL, FALSE);
+	if (sr->sg != NULL && sr->sg->dialog != NULL)	/* dialog already created */
+		return TRUE;
 
-	g_return_val_if_fail(NULL != sr, FALSE);
-	if (NULL != sg) return TRUE;
-	sg = g_new0(SearchReplaceGUI, 1);
-
-	if (NULL == (sg->xml = glade_xml_new(GLADE_FILE_SEARCH_REPLACE,
-		SEARCH_REPLACE_DIALOG, NULL)))
-	{
-		anjuta_util_dialog_error(NULL, _("Unable to build user interface for Search And Replace"));
-		g_free(sg);
-		sg = NULL;
+	xml = glade_xml_new (GLADE_FILE_SEARCH_REPLACE, SEARCH_REPLACE_DIALOG, NULL);
+	if (xml == NULL)
+	{
+		anjuta_util_dialog_error (NULL, _("Unable to build user interface for Search And Replace"));
 		return FALSE;
 	}
-	sg->dialog = glade_xml_get_widget(sg->xml, SEARCH_REPLACE_DIALOG);
-	/* gtk_window_set_transient_for (GTK_WINDOW(sg->dialog)
-	  , GTK_WINDOW(app->widgets.window)); */
-		
+
 	if (!labels_translated)
 	{
 		labels_translated = TRUE;
-		translate_dialog_strings (search_direction_strings);
-		translate_dialog_strings (search_target_strings);
-		translate_dialog_strings (search_action_strings);
-	}
+		anj_sr_translate_dialog_strings (search_target_strings);
+		anj_sr_translate_dialog_strings (search_action_strings);
+		button_search_label = _("S_earch");	/* s,a,r,c are unavailable for mnemonic */
+		button_replace_label = _("_Replace");
+		button_replace_all_label = _("Repace _all");
+	}
+
+	sg = g_slice_alloc (sizeof (SearchReplaceGUI));
+	sg->xml = xml;
+	sg->dialog = glade_xml_get_widget (sg->xml, SEARCH_REPLACE_DIALOG);
+/*	gtk_window_set_transient_for (GTK_WINDOW (sg->dialog),
+								  GTK_WINDOW (app->widgets.window)); */
+	/* all dialog widgets can access sg, and therefore sr, by getting this data
+	   from their toplevel window */
+	g_object_set_data (G_OBJECT (sg->dialog), SEARCH_GUI_KEY, sg);
+	anj_sr_set_dialog_searchdata (sg, sr);
 
-	for (i=0; NULL != glade_widgets[i].name; ++i)
+	for (i = 0; i < GUI_ELEMENT_COUNT; i++)
 	{
-		w = &(glade_widgets[i]);
-		w->widget = glade_xml_get_widget(sg->xml, w->name);
-		if (GE_COMBO_ENTRY == w->type)
+		widget = glade_xml_get_widget (xml, glade_widgets[i].name);
+		if (glade_widgets[i].type == GE_BUTTON)
+		{
+			gtk_button_set_use_underline (GTK_BUTTON (widget), TRUE);
+		}
+		else if (glade_widgets[i].type == GE_COMBO_ENTRY)
 		{
 			/* Get child of GtkComboBoxEntry */
-			w->widget = GTK_BIN(w->widget)->child;
+			widget = GTK_BIN (widget)->child;
 		}
-		gtk_widget_ref(w->widget);
-		if (GE_COMBO == w->type && NULL != w->extra)
+		/* CHECKME no obvious reason for this
+		g_object_ref (G_OBJECT (w->widget));*/
+		if (glade_widgets[i].type == GE_COMBO && glade_widgets[i].extra != NULL)
 		{
-			search_set_popdown_map(GTK_COMBO_BOX(w->widget), (AnjutaUtilStringMap *)w->extra);
+			anj_sr_set_popdown_map (GTK_COMBO_BOX (widget),
+									(AnjutaUtilStringMap *)glade_widgets[i].extra);
 		}
+		sg->widgets[i] = widget;
 	}
 
-	widget = sr_get_gladewidget(SEARCH_STRING_COMBO)->widget;
-	g_signal_connect (widget, "changed", G_CALLBACK (on_search_expression_changed), NULL);
-	widget = sr_get_gladewidget(SEARCH_STRING)->widget;
-	g_signal_connect (widget, "activate", G_CALLBACK (on_search_expression_activate), NULL);
-	widget = sr_get_gladewidget(REPLACE_STRING)->widget;
-	g_signal_connect (widget, "activate", G_CALLBACK (on_search_expression_activate), NULL);
-	widget = sr_get_gladewidget(SEARCH_ACTION_COMBO)->widget;
-	g_signal_connect (widget, "changed", G_CALLBACK (on_search_action_changed), NULL);
-	widget = sr_get_gladewidget(SEARCH_DIRECTION_COMBO)->widget;
-	g_signal_connect (widget, "changed", G_CALLBACK (on_search_direction_changed), NULL);
-	widget = sr_get_gladewidget(SEARCH_TARGET_COMBO)->widget;
-	g_signal_connect (widget, "changed", G_CALLBACK (on_search_target_changed), NULL);
+	/* glade can't independently set stock-button labels */
+	anj_sr_modify_button (sg, SEARCH_BUTTON, button_search_label, GTK_STOCK_FIND);
+	anj_sr_modify_button (sg, REPLACE_BUTTON, button_replace_label, GTK_STOCK_FIND_AND_REPLACE);
+
+	/* replace button presented when that action is in progress */
+	anj_sr_show_replace_button (sg, FALSE);
+	anj_sr_enable_replace_button (sg, FALSE);
+	widget = anj_sr_get_ui_widget (ACTIONS_MAX);
+	gtk_widget_set_sensitive (widget, FALSE);
 
+	/* other callbacks which don't need specific data are connected via glade */
+	g_signal_connect (G_OBJECT (sg->dialog), "key-press-event",
+					G_CALLBACK (on_search_dialog_key_press), sg);
+	widget = anj_sr_get_ui_widget (SEARCH_WHOLE);
+	g_signal_connect (G_OBJECT (widget), "toggled",
+					G_CALLBACK (on_search_direction_changed),
+					GINT_TO_POINTER (SD_WHOLE));
+	widget = anj_sr_get_ui_widget (SEARCH_FORWARD);
+	g_signal_connect (G_OBJECT (widget), "toggled",
+					G_CALLBACK (on_search_direction_changed),
+					GINT_TO_POINTER (SD_FORWARD));
+	widget = anj_sr_get_ui_widget (SEARCH_BACKWARD);
+	g_signal_connect (G_OBJECT (widget), "toggled",
+					G_CALLBACK (on_search_direction_changed),
+					GINT_TO_POINTER (SD_BACKWARD));
 
-	search_preferences_initialize_setting_treeview(sg->dialog);
-	search_preferences_init();
-	
-	glade_xml_signal_autoconnect(sg->xml);
+	glade_xml_signal_autoconnect (sg->xml);
+
+	sg->showing = FALSE;
+	def_sg = sg;	//FIXME non-static data
 	return TRUE;
 }
 
 static void
-show_dialog(void)
+anj_sr_present_dialog (SearchReplaceGUI *sg)
 {
 	gtk_window_present (GTK_WINDOW (sg->dialog));
 	sg->showing = TRUE;
 }
 
+/* note: no included search_replace_data_destroy(sg->sr) */
+void
+anj_sr_destroy_ui_data (SearchReplaceGUI *sg)
+{
+	if (sg != NULL)
+	{
+		if (sg->dialog != NULL)
+			gtk_widget_destroy (sg->dialog);
+		if (sg->xml != NULL)
+			g_object_unref (G_OBJECT (sg->xml));
+
+		g_slice_free1 (sizeof (SearchReplaceGUI), sg);
+	}
+}
+
 static gboolean
-word_in_list(GList *list, gchar *word)
+anj_sr_find_in_list (GList *list, gchar *word)
 {
-	GList *l = list;
+	GList *node;
 
-	while (l != NULL)
+	for (node = list; node != NULL; node = g_list_next (node))
 	{
-		if (strcmp(l->data, word) == 0)
+		if (strcmp ((gchar *)node->data, word) == 0)
 			return TRUE;
-		l = g_list_next(l);
 	}
 	return FALSE;
 }
 
 /*  Remove last item of the list if > nb_max  */
-
-static GList*
-list_max_items(GList *list, guint nb_max)
+static void
+anj_sr_trim_list (GList **list, guint nb_max)
 {
-	GList *last;
+	GList *node;
 
-	if (g_list_length(list) > nb_max)
+	node = *list;
+	if (node != NULL && g_list_length (node) > nb_max)
 	{
-		last = g_list_last(list);
-		g_free(last->data);
-		list = g_list_delete_link (list, last);
+
+		node = g_list_last (node);
+		g_free (node->data);
+		*list = g_list_delete_link (*list, node);
 	}
-	return list;
 }
 
-#define MAX_ITEMS_SEARCH_COMBO 16
-
 static void
-search_update_combos(void)
+anj_sr_update_search_combos (SearchReplaceGUI *sg)
 {
-	GtkWidget *search_entry = NULL;
-	gchar *search_word = NULL;
-	IAnjutaDocument* doc = ianjuta_document_manager_get_current_document(sr->docman,
-																		NULL);
-	IAnjutaEditor *te = NULL;
-	if (IANJUTA_IS_EDITOR(doc))
-		te = IANJUTA_EDITOR(doc);
-
-	search_entry = sr_get_gladewidget(SEARCH_STRING)->widget;
-	if (search_entry && te)
-	{
-		search_word = g_strdup(gtk_entry_get_text(GTK_ENTRY (search_entry)));
-		if (search_word  && strlen(search_word) > 0)
-		{
-			if (!word_in_list(sr->search.expr_history, search_word))
-			{
-				GtkWidget *search_list = 
-					sr_get_gladewidget(SEARCH_STRING_COMBO)->widget;
-				sr->search.expr_history = g_list_prepend(sr->search.expr_history,
-					search_word);
-				sr->search.expr_history = list_max_items(sr->search.expr_history,
-					MAX_ITEMS_SEARCH_COMBO);
-				search_set_popdown_strings(GTK_COMBO_BOX_ENTRY (search_list),
-					sr->search.expr_history);
-				
-				//search_toolbar_set_text(search_word);	
-				//  FIXME  comboentry instead of entry				
-				//~ entry_set_text_n_select (app->widgets.toolbar.main_toolbar.find_entry,
-								 //~ search_word, FALSE);
+	SearchReplace *sr;
+	IAnjutaDocument *doc;
+
+	sr = sg->sr;
+	g_return_if_fail (sr != NULL);
+
+	doc = ianjuta_document_manager_get_current_document (sr->docman, NULL);
+	if (doc && IANJUTA_IS_EDITOR (doc))
+	{
+		GtkWidget *search_entry;
+
+		sg = sr->sg;
+		search_entry = anj_sr_get_ui_widget (SEARCH_STRING);
+		if (search_entry != NULL)
+		{
+			gchar *search_word;
+
+			search_word = g_strdup (gtk_entry_get_text (GTK_ENTRY (search_entry)));
+			if (search_word != NULL && *search_word != 0)
+			{
+				if (!anj_sr_find_in_list (sr->search.expr_history, search_word))
+				{
+					GtkWidget *search_list =
+						anj_sr_get_ui_widget (SEARCH_STRING_COMBO);
+					sr->search.expr_history = g_list_prepend (sr->search.expr_history,
+						search_word);
+					anj_sr_trim_list (&sr->search.expr_history,
+										MAX_ITEMS_SEARCH_COMBO);
+					anj_sr_set_popdown_strings(GTK_COMBO_BOX_ENTRY (search_list),
+						sr->search.expr_history);
+
+					//search_toolbar_set_text(search_word);
+					//  FIXME  comboentry instead of entry
+					//~ entry_set_text_n_select (app->widgets.toolbar.main_toolbar.find_entry,
+									 //~ search_word, FALSE);
+				}
 			}
 		}
 	}
 }
 
 static void
-replace_update_combos(void)
+anj_sr_update_replace_combos (SearchReplaceGUI *sg)
 {
-	GtkWidget *replace_entry = NULL;
-	gchar *replace_word = NULL;
-	IAnjutaDocument* doc = ianjuta_document_manager_get_current_document(sr->docman,
-																		NULL);
-	IAnjutaEditor *te = NULL;
-	if (IANJUTA_IS_EDITOR(doc))
-		te = IANJUTA_EDITOR(doc);
-	
-	replace_entry = sr_get_gladewidget(REPLACE_STRING)->widget;
-	if (replace_entry && te)
+	SearchReplace *sr;
+	IAnjutaDocument *doc;
+
+	sr = sg->sr;
+	g_return_if_fail (sr != NULL);
+
+	doc = ianjuta_document_manager_get_current_document (sr->docman, NULL);
+	if (IANJUTA_IS_EDITOR (doc))
 	{
-		replace_word = g_strdup(gtk_entry_get_text(GTK_ENTRY (replace_entry)));
-		if (replace_word  && strlen(replace_word) > 0)
+		GtkWidget *replace_entry;
+
+		sg = sr->sg;
+		replace_entry = anj_sr_get_ui_widget (REPLACE_STRING);
+		if (replace_entry != NULL)
 		{
-			if (!word_in_list(sr->replace.expr_history, replace_word))
+			gchar *replace_word;
+
+			replace_word = g_strdup (gtk_entry_get_text (GTK_ENTRY (replace_entry)));
+			if (replace_word != NULL && *replace_word != 0)
 			{
-				GtkWidget *replace_list = 
-					sr_get_gladewidget(REPLACE_STRING_COMBO)->widget;
-				sr->replace.expr_history = g_list_prepend(sr->replace.expr_history,
-					replace_word);
-				sr->replace.expr_history = list_max_items(sr->replace.expr_history,
-					MAX_ITEMS_SEARCH_COMBO);
-				search_set_popdown_strings(GTK_COMBO_BOX_ENTRY (replace_list),
-					sr->replace.expr_history);
+				if (!anj_sr_find_in_list(sr->replace.expr_history, replace_word))
+				{
+					GtkWidget *replace_list =
+						anj_sr_get_ui_widget (REPLACE_STRING_COMBO);
+					sr->replace.expr_history = g_list_prepend(sr->replace.expr_history,
+						replace_word);
+					anj_sr_trim_list (&sr->replace.expr_history,
+										MAX_ITEMS_SEARCH_COMBO);
+					anj_sr_set_popdown_strings (GTK_COMBO_BOX_ENTRY (replace_list),
+						sr->replace.expr_history);
+				}
 			}
 		}
 	}
 }
 
-void 
-search_update_dialog(void)
+void
+anj_sr_populate_dialog (SearchReplaceGUI *sg)
 {
+	SearchReplace *sr;
 	GtkWidget *widget;
 	Search *s;
 
+	sr = sg->sr;
+	g_return_if_fail (sr != NULL);
+
 	s = &(sr->search);
-	widget = sr_get_gladewidget(SEARCH_REGEX)->widget;
+
+	if (s->expr.search_str)
+	{
+		widget = anj_sr_get_ui_widget (SEARCH_STRING);
+		gtk_entry_set_text(GTK_ENTRY(widget), s->expr.search_str);
+	}
+	if (sr->replace.repl_str)
+	{
+		widget = anj_sr_get_ui_widget (REPLACE_STRING);
+		gtk_entry_set_text(GTK_ENTRY(widget), sr->replace.repl_str);
+	}
+	widget = anj_sr_get_ui_widget (SEARCH_REGEX);
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.regex);
-	widget = sr_get_gladewidget(GREEDY)->widget;
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.greedy);
-	widget = sr_get_gladewidget(IGNORE_CASE)->widget;
+	widget = anj_sr_get_ui_widget (IGNORE_CASE);
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.ignore_case);
-	widget = sr_get_gladewidget(WHOLE_WORD)->widget;
+	widget = anj_sr_get_ui_widget (WHOLE_WORD);
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.whole_word);
-	widget = sr_get_gladewidget(WHOLE_LINE)->widget;
+	widget = anj_sr_get_ui_widget (WHOLE_LINE);
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.whole_line);
-	widget = sr_get_gladewidget(WORD_START)->widget;
+	widget = anj_sr_get_ui_widget (WORD_START);
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.word_start);
-		
-	widget = sr_get_gladewidget(ACTIONS_NO_LIMIT)->widget;
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.no_limit);
-	widget = sr_get_gladewidget(ACTIONS_MAX)->widget;
+	widget = anj_sr_get_ui_widget (GREEDY);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.greedy);
+	widget = anj_sr_get_ui_widget (REPLACE_REGEX);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), sr->replace.regex);
+
+	if (s->expr.no_limit)
+		widget = anj_sr_get_ui_widget (ACTIONS_NO_LIMIT);
+	else
+		widget = anj_sr_get_ui_widget (ACTIONS_LIMIT);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (widget), TRUE);
+
+	widget = anj_sr_get_ui_widget (ACTIONS_MAX);
 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), s->expr.actions_max);
-	
-	widget = sr_get_gladewidget(REPLACE_REGEX)->widget;	
-	gtk_widget_set_sensitive(widget, sr->search.expr.regex);
-	
-	widget = sr_get_gladewidget(SEARCH_BUTTON)->widget; 	
+
+	widget = anj_sr_get_ui_widget (GREEDY);
+	gtk_widget_set_sensitive(widget, s->expr.regex);
+	widget = anj_sr_get_ui_widget (REPLACE_REGEX);
+	gtk_widget_set_sensitive(widget, s->expr.regex);
+
+	widget = anj_sr_get_ui_widget (SEARCH_BUTTON);
+	gtk_widget_set_sensitive (widget, (s->expr.search_str != NULL) && (*s->expr.search_str != '\0'));
+	widget = anj_sr_get_ui_widget (REPLACE_BUTTON);
 	gtk_widget_set_sensitive (widget, (s->expr.search_str != NULL) && (*s->expr.search_str != '\0'));
 
-	widget = sr_get_gladewidget(SEARCH_STRING)->widget;
-	if (s->expr.search_str)
-		gtk_entry_set_text(GTK_ENTRY(widget), s->expr.search_str);
-	
-	widget = sr_get_gladewidget(SEARCH_DIRECTION_COMBO)->widget;
-	search_select_item (GTK_COMBO_BOX(widget), s->range.direction);
-	
-	widget = sr_get_gladewidget(SEARCH_ACTION_COMBO)->widget;
-	search_select_item (GTK_COMBO_BOX(widget), s->action);
+	anj_sr_set_direction (sg, s->range.direction);
 
-	search_show_replace(s->action == SA_REPLACE || s->action == SA_REPLACEALL);
-	
-	widget = sr_get_gladewidget(SEARCH_TARGET_COMBO)->widget;
-	search_select_item (GTK_COMBO_BOX(widget), s->range.type);
-	
-	widget = sr_get_gladewidget(SEARCH_BASIC)->widget;
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->basic_search);
+	widget = anj_sr_get_ui_widget (SEARCH_ACTION_COMBO);
+	anj_sr_activate_combo_item (GTK_COMBO_BOX(widget), s->action);
+
+	anj_sr_show_replace (sg, s->action == SA_REPLACE || s->action == SA_REPLACEALL);
+
+	widget = anj_sr_get_ui_widget (SEARCH_TARGET_COMBO);
+	anj_sr_activate_combo_item (GTK_COMBO_BOX(widget), s->range.target);
+/* CHECKME populate specific files combo's ? */
+	widget = anj_sr_get_ui_widget (SEARCH_RECURSIVE);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (widget), s->range.files.recurse);
+//	widget = anj_sr_get_ui_widget (IGNORE_BINARY_FILES);
+//	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (widget), s->range.files.ignore_binary_files);
+	widget = anj_sr_get_ui_widget (IGNORE_HIDDEN_FILES);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (widget), s->range.files.ignore_hidden_files);
+	widget = anj_sr_get_ui_widget (IGNORE_HIDDEN_DIRS);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (widget), s->range.files.ignore_hidden_dirs);
+
+//	widget = anj_sr_get_ui_widget (SEARCH_BASIC);
+//	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->basic_search);
 
-	widget = sr_get_gladewidget(STOP_BUTTON)->widget; 	
+	widget = anj_sr_get_ui_widget (STOP_BUTTON);
 	gtk_widget_set_sensitive (widget, FALSE);
 
-	basic_search_toggled();
+//	basic_search_toggled ();
 }
+/*
+static void
+basic_search_toggled (void)
+{
+	GtkToggleButton *togglebutton;
+	SearchReplaceGUI *sg;
 
-/* -------------- Callbacks --------------------- */
-
-gboolean
-on_search_replace_delete_event(GtkWidget *window, GdkEvent *event,
-			       gboolean user_data)
+	sg = ;
+	togglebutton = GTK_TOGGLE_BUTTON(anj_sr_get_ui_widget (SEARCH_BASIC));
+	on_setting_basic_search_toggled (togglebutton, NULL);	/ * don't care if busy * /
+}
+*/
+/* hide dialog and cleanup if currently supended awaiting replacement confirmation */
+static void
+anj_sr_interrupt_nicely (SearchReplaceGUI *sg)
 {
-	if (sg->showing)
+	SearchReplace *sr;
+
+	sr = sg->sr;
+	if (sg->showing)	/* should never fail */
 	{
-		gtk_widget_hide(sg->dialog);
+		GtkWidget *button;
+
+		gtk_widget_hide (sg->dialog);
 		sg->showing = FALSE;
+		button = anj_sr_get_ui_widget (STOP_BUTTON);
+		gtk_widget_set_sensitive (button, FALSE);
+		anj_sr_reset_flags (sr);	/* CHECKME selection flag ? just sr->replace.phase = SA_REPL_FIRST; ?*/
+//		anj_sr_reset_replace_buttons (sr);
+		anj_sr_enable_replace_button (sg, FALSE);
+	}
+	if (sr->search.action == SA_REPLACE)
+	{
+//		while (sr->replace.phase != SA_REPL_CONFIRM)
+//			usleep (10000);	/* must wait until current search ends */
+		sr->search.stop_count = -1;	/* trigger an abort on next pass */
+		/* cleanup ready for next document */
+		//CHECKME report count of processed items ?
+		sr->search.matches_sofar = 0;
+		sr->replace.phase = SA_REPL_FIRST;
 	}
-	return TRUE;
+	sr->search.busy = FALSE;
 }
 
+/* -------------- Callbacks --------------------- */
+
+/* delete-event callback for main s/r window */
 gboolean
-on_search_dialog_key_press_event(GtkWidget *widget, GdkEventKey *event,
-                               gpointer user_data)
+on_search_dialog_delete_event (GtkWidget *window, GdkEvent *event,
+								gpointer user_data)
+{
+	SearchReplaceGUI *sg;
+
+	sg = anj_sr_get_current_uidata (window);
+	if (sg != NULL)
+		anj_sr_interrupt_nicely (sg);
+	return TRUE;
+}
+
+/* key-press callback for various dialog's entry-widget(s) */
+static gboolean
+on_search_dialog_key_press (GtkWidget *widget, GdkEventKey *event,
+							gpointer user_data)
 {
+	SearchReplaceGUI *sg;
+
+	sg = (SearchReplaceGUI *) user_data;	/* for speed, this time we get the data directly */
+
 	if (event->keyval == GDK_Escape)
 	{
-		if (user_data)
+		if (widget == sg->dialog)
 		{
 			/* Escape pressed in Find window */
-			gtk_widget_hide(widget);
-			sg->showing = FALSE;
+//			gtk_widget_hide (widget);
+//			sg->showing = FALSE;
+			anj_sr_interrupt_nicely (sg);
 		}
 		else
 		{
-			/* Escape pressed in wrap yes/no window */
+			/* Escape pressed in message dialog */
 			gtk_dialog_response (GTK_DIALOG (widget), GTK_RESPONSE_NO);
 		}
 		return TRUE;
 	}
-	else
+	else if (widget == sg->dialog)
 	{
-		if ( (event->state & GDK_CONTROL_MASK) &&
+		if (sg->sr->search.busy)
+			return TRUE;	/* prevent string changes while replacing interactively */
+		/* FIXME get relevant shortcuts instead of this */
+		if ((event->state & GDK_CONTROL_MASK) &&
 				((event->keyval & 0x5F) == GDK_G))
 		{
 			if (event->state & GDK_SHIFT_MASK)
-				search_replace_previous();
+				anj_sr_select_previous (sg);
 			else
-				search_replace_next();
+				anj_sr_select_next (sg);
+			return TRUE;
 		}
-		return FALSE;
 	}
+	return FALSE;
 }
 
 static void
-search_disconnect_set_toggle_connect(GladeWidgetId id, GCallback function, 
-	                                 gboolean active)
+anj_sr_disconnect_set_toggle_connect (SearchReplaceGUI *sg, GUIElementId id,
+									  GCallback function, gboolean active)
 {
 	GtkWidget *button;
-	
-	button = sr_get_gladewidget(id)->widget;
+
+	button = anj_sr_get_ui_widget (id);
 	g_signal_handlers_disconnect_by_func(G_OBJECT(button), function, NULL);
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
 	g_signal_connect(G_OBJECT(button), "toggled", function, NULL);
@@ -1537,47 +2598,101 @@
 
 
 void
-on_search_match_whole_word_toggled (GtkToggleButton *togglebutton, 
+on_search_match_whole_word_toggled (GtkToggleButton *togglebutton,
 									gpointer user_data)
 {
-	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)))
+	SearchReplaceGUI *sg;
+	gboolean state;
+
+	state = gtk_toggle_button_get_active (togglebutton);
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (togglebutton));
+	if (anj_sr_is_idle (sg))
+	{
+		if (state)
+		{
+			anj_sr_disconnect_set_toggle_connect (sg, WHOLE_LINE,
+				(GCallback)on_search_match_whole_line_toggled, FALSE);
+			anj_sr_disconnect_set_toggle_connect (sg, WORD_START,
+				(GCallback)on_search_match_word_start_toggled, FALSE);
+		}
+	}
+	else
 	{
-		search_disconnect_set_toggle_connect(WHOLE_LINE, (GCallback) 
-				on_search_match_whole_line_toggled, FALSE);
-		search_disconnect_set_toggle_connect(WORD_START, (GCallback) 
-				on_search_match_word_start_toggled, FALSE);
+		g_signal_handlers_block_by_func (G_OBJECT (togglebutton),
+										(gpointer) on_search_match_whole_word_toggled,
+										user_data);
+		gtk_toggle_button_set_active (togglebutton, !state);
+		g_signal_handlers_unblock_by_func (G_OBJECT (togglebutton),
+										(gpointer) on_search_match_whole_word_toggled,
+										user_data);
 	}
 }
 
 void
-on_search_match_whole_line_toggled (GtkToggleButton *togglebutton, 
+on_search_match_whole_line_toggled (GtkToggleButton *togglebutton,
 									gpointer user_data)
 {
-	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)))
+	SearchReplaceGUI *sg;
+	gboolean state;
+
+	state = gtk_toggle_button_get_active (togglebutton);
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (togglebutton));
+	if (anj_sr_is_idle (sg))
+	{
+		if (state)
+		{
+			anj_sr_disconnect_set_toggle_connect (sg, WHOLE_WORD,
+				(GCallback)on_search_match_whole_word_toggled, FALSE);
+			anj_sr_disconnect_set_toggle_connect (sg, WORD_START,
+				(GCallback)on_search_match_word_start_toggled, FALSE);
+		}
+	}
+	else
 	{
-		search_disconnect_set_toggle_connect(WHOLE_WORD, (GCallback) 
-				on_search_match_whole_word_toggled, FALSE);
-		search_disconnect_set_toggle_connect(WORD_START, (GCallback) 
-				on_search_match_word_start_toggled, FALSE);
+		g_signal_handlers_block_by_func (G_OBJECT (togglebutton),
+										(gpointer) on_search_match_whole_line_toggled,
+										user_data);
+		gtk_toggle_button_set_active (togglebutton, !state);
+		g_signal_handlers_unblock_by_func (G_OBJECT (togglebutton),
+										(gpointer) on_search_match_whole_line_toggled,
+										user_data);
 	}
 }
 
 void
-on_search_match_word_start_toggled (GtkToggleButton *togglebutton, 
+on_search_match_word_start_toggled (GtkToggleButton *togglebutton,
 									gpointer user_data)
-{	
-	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)))
+{
+	SearchReplaceGUI *sg;
+	gboolean state;
+
+	state = gtk_toggle_button_get_active (togglebutton);
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (togglebutton));
+	if (anj_sr_is_idle (sg))
+	{
+		if (state)
+		{
+			anj_sr_disconnect_set_toggle_connect (sg, WHOLE_WORD,
+				(GCallback)on_search_match_whole_word_toggled, FALSE);
+			anj_sr_disconnect_set_toggle_connect (sg, WHOLE_LINE,
+				(GCallback)on_search_match_whole_line_toggled, FALSE);
+		}
+	}
+	else
 	{
-		search_disconnect_set_toggle_connect(WHOLE_WORD, (GCallback) 
-				on_search_match_whole_word_toggled, FALSE);
-		search_disconnect_set_toggle_connect(WHOLE_LINE, (GCallback) 
-				on_search_match_whole_line_toggled, FALSE);
+		g_signal_handlers_block_by_func (G_OBJECT (togglebutton),
+										(gpointer) on_search_match_word_start_toggled,
+										user_data);
+		gtk_toggle_button_set_active (togglebutton, !state);
+		g_signal_handlers_unblock_by_func (G_OBJECT (togglebutton),
+										(gpointer) on_search_match_word_start_toggled,
+										user_data);
 	}
 }
 
 /*
 static void
-search_make_sensitive(gboolean sensitive)
+search_make_sensitive (gboolean sensitive)
 {
 	static char *widgets[] = {
 		SEARCH_EXPR_FRAME, SEARCH_TARGET_FRAME, CLOSE_BUTTON, SEARCH_BUTTON,
@@ -1585,10 +2700,13 @@
 	};
 	gint i;
 	GtkWidget *widget;
-	
+	SearchReplaceGUI *sg;
+
+	sg = ;
+
 	for (i=0; i < sizeof(widgets)/sizeof(widgets[0]); ++i)
 	{
-		widget = sr_get_gladewidget(widgets[i])->widget;
+		widget = anj_sr_get_ui_widget (widgets[i]);
 		if (NULL != widget)
 			gtk_widget_set_sensitive(widget, sensitive);
 	}
@@ -1598,429 +2716,644 @@
 void
 on_search_regex_toggled (GtkToggleButton *togglebutton, gpointer user_data)
 {
-	static GladeWidgetId dependent_widgets[] = {
-		GREEDY, IGNORE_CASE, WHOLE_WORD, WHOLE_LINE, WORD_START
-	};
-	int i;
-	GtkWidget *dircombo = sr_get_gladewidget(SEARCH_DIRECTION_COMBO)->widget;
-	GtkWidget *repl_regex = sr_get_gladewidget(REPLACE_REGEX)->widget;
-	GtkWidget *widget;
-	gboolean state = gtk_toggle_button_get_active(togglebutton);
+	SearchReplaceGUI *sg;
+	gboolean state;
 
-	if (state)
-	{
-		search_set_direction(SD_FORWARD);
-	}
-	
-	gtk_widget_set_sensitive(dircombo, !state);
-	gtk_widget_set_sensitive(repl_regex, state);
-	
-	for (i=0; i < sizeof(dependent_widgets)/sizeof(dependent_widgets[0]); ++i)
+	state = gtk_toggle_button_get_active (togglebutton);
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (togglebutton));
+	if (anj_sr_is_idle (sg))
 	{
-		widget = sr_get_gladewidget(dependent_widgets[i])->widget;
-		if (NULL != widget)
+		SearchAction act;
+		GUIElementId dependent_widgets[] =
+		{
+			GREEDY, REPLACE_REGEX, IGNORE_CASE, WHOLE_WORD, WHOLE_LINE, WORD_START
+		};
+		GtkWidget *widget;
+		gint i;
+
+		widget = anj_sr_get_ui_widget (SEARCH_BACKWARD); /* SD_WHOLE is ok */
+		if (state)
+		{
+			if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+				anj_sr_set_direction (sg, SD_FORWARD);
+		}
+		gtk_widget_set_sensitive (widget, !state);
+
+		for (i = 0; i < sizeof(dependent_widgets)/sizeof(dependent_widgets[0]); ++i)
+		{
+			widget = anj_sr_get_ui_widget (dependent_widgets[i]);
+			if (widget != NULL)
+			{
+				if (i < 2) /* GREEDY and REPLACE_REGEX work only with regex */
+					gtk_widget_set_sensitive (widget, state);
+				else	/* the other options must be expressed in the regex */
+				{
+					gtk_widget_set_sensitive (widget, !state);
+					gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
+				}
+			}
+		}
+
+		act = anj_sr_get_combo_id_active_value (sg, SEARCH_ACTION_COMBO);
+		if (act == SA_REPLACEALL)
 		{
-			gtk_widget_set_sensitive(widget, !state);
-			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
+			SearchRangeType tgt;
+
+			tgt = anj_sr_get_combo_id_active_value (sg, SEARCH_TARGET_COMBO);
+			if (tgt == SR_OPEN_BUFFERS || tgt == SR_PROJECT || tgt == SR_FILES)
+			{
+				widget = anj_sr_get_ui_widget (ACTIONS_LIMIT);
+				gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+			}
 		}
 	}
+	else /* busy*/
+	{
+		g_signal_handlers_block_by_func (G_OBJECT (togglebutton),
+										(gpointer) on_search_regex_toggled,
+										user_data);
+		gtk_toggle_button_set_active (togglebutton, !state);
+		g_signal_handlers_unblock_by_func (G_OBJECT (togglebutton),
+										(gpointer) on_search_regex_toggled,
+										user_data);
+	}
+}
+
+void
+on_search_actions_no_limit_toggled (GtkToggleButton *togglebutton, gpointer user_data)
+{
+	SearchReplaceGUI *sg;
+	gboolean state;
+
+	state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (togglebutton));
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (togglebutton));
+	if (anj_sr_is_idle (sg))
+	{
+		GtkWidget *actions_max;
+
+		actions_max = anj_sr_get_ui_widget (ACTIONS_MAX);
+		gtk_widget_set_sensitive (actions_max, !state);
+	}
+	else
+	{
+		g_signal_handlers_block_by_func (G_OBJECT (togglebutton),
+										(gpointer) on_search_actions_no_limit_toggled,
+										user_data);
+		gtk_toggle_button_set_active (togglebutton, !state);
+		g_signal_handlers_unblock_by_func (G_OBJECT (togglebutton),
+										(gpointer) on_search_actions_no_limit_toggled,
+										user_data);
+	}
 }
 
+/* for old dialog
 static void
-search_set_toggle_direction(SearchDirection dir)
+search_set_toggle_direction (SearchDirection dir)
 {
 	switch (dir)
 	{
+//		case SD_WHOLE :
+		default:
+			anj_sr_disconnect_set_toggle_connect (SEARCH_FULL_BUFFER,
+				(GCallback) on_search_full_buffer_toggled, TRUE);
+			break;
 		case SD_FORWARD :
-			search_disconnect_set_toggle_connect(SEARCH_FORWARD, (GCallback) 
-				on_search_forward_toggled, TRUE);
+			anj_sr_disconnect_set_toggle_connect (SEARCH_FORWARD,
+				(GCallback) on_search_forward_toggled, TRUE);
 			break;
 		case SD_BACKWARD :
-			search_disconnect_set_toggle_connect(SEARCH_BACKWARD, (GCallback) 
-				on_search_backward_toggled, TRUE);
-			break;
-		case SD_BEGINNING :
-			search_disconnect_set_toggle_connect(SEARCH_FULL_BUFFER, (GCallback) 
-				on_search_full_buffer_toggled, TRUE);
+			anj_sr_disconnect_set_toggle_connect (SEARCH_BACKWARD,
+				(GCallback) on_search_backward_toggled, TRUE);
 			break;
 	}
 }
+*/
 
-void
-on_search_direction_changed (GtkComboBox *combo, gpointer user_data)
+/* idle callback to revert a radio-button changed when a search is in progress */
+static gboolean
+anj_sr_revert_button (GtkWidget *btn)
 {
-	SearchDirection dir;
-
-	dir = search_get_item_combo(combo);
-	search_set_toggle_direction(dir);
-	search_direction_changed(dir);
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (btn), TRUE);
+	return FALSE;
 }
 
+/* callback for all search-direction radio-buttons
+	user_data is a pointerised enumerator of corresponding SearchDirection */
 void
-on_search_action_changed (GtkComboBox *combo, gpointer user_data)
+on_search_direction_changed (GtkToggleButton *togglebutton, gpointer user_data)
 {
-	SearchAction act;
-	SearchRangeType rt;
-	
-	reset_flags();
-	act = search_get_item_combo(combo);
-	rt = search_get_item_combo_name(SEARCH_TARGET_COMBO);
-	show_jump_button (FALSE);
-	switch(act)
-	{
-		case SA_SELECT:
-			search_show_replace(FALSE);
-			modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
-			if (rt == SR_OPEN_BUFFERS || rt == SR_PROJECT ||
-					rt == SR_FILES)
-				search_set_target(SR_BUFFER);
-			break;
-		case SA_REPLACE:
-			search_show_replace(TRUE);
-			modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
-			if (rt == SR_OPEN_BUFFERS || rt == SR_PROJECT || 
-					rt == SR_FILES)
-				search_set_target(SR_BUFFER);
-			break;
-		case SA_REPLACEALL:
-			search_show_replace(TRUE);
-			modify_label_image_button(SEARCH_BUTTON, _("Replace All"), 
-								          GTK_STOCK_FIND_AND_REPLACE);
-			break;
-		default:
-			search_show_replace(FALSE);
-			modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
-			break;
+	SearchReplaceGUI *sg;
+	gboolean state;
+	SearchDirection dir;
+
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (togglebutton));
+	if (sg == NULL)
+		return;
+
+	dir = GPOINTER_TO_INT (user_data);
+	state = gtk_toggle_button_get_active (togglebutton);
+	if (anj_sr_is_idle (sg))
+	{
+		if (state)
+		{
+			anj_sr_conform_direction_change (sg, dir);
+		}
+	}
+	else
+	{
+		if (state)
+		{
+			SearchReplace *sr;
+
+			sr = sg->sr;
+			if (sr->search.range.direction != dir) /* attempt to change away from blocked value */
+			{
+				/* setup to re-activate the current button when allowed */
+				gint i;
+				SearchDirection id[] =
+				{
+					SD_WHOLE, SD_FORWARD, SD_BACKWARD
+				};
+				GUIElementId dir_widgets[] =
+				{
+					SEARCH_WHOLE, SEARCH_FORWARD, SEARCH_BACKWARD
+				};
+
+				for (i = 0; i < 3; i++)
+				{
+					if (sr->search.range.direction == id[i])
+					{
+						GtkWidget *btn;
+
+						btn = anj_sr_get_ui_widget (dir_widgets[i]);
+						g_idle_add ((GSourceFunc) anj_sr_revert_button, btn);
+						break;
+					}
+				}
+			}
+		}
 	}
 }
 
 void
-on_search_target_changed(GtkComboBox *combo, gpointer user_data)
+on_search_action_changed (GtkComboBox *combo, gpointer user_data)
 {
-	SearchRangeType tgt;
-	SearchDirection dir;
-	SearchAction act;
-	GtkWidget *search_var_frame = sr_get_gladewidget(SEARCH_VAR_FRAME)->widget;
-	GtkWidget *file_filter_frame = sr_get_gladewidget(FILE_FILTER_FRAME)->widget;
+	SearchReplaceGUI *sg;
 
-	tgt = search_get_item_combo(combo);
-	switch(tgt)
-	{
-		case SR_FILES:
-			gtk_widget_hide(search_var_frame);
-			gtk_widget_show(file_filter_frame);
-			break;
-		default:
-			gtk_widget_hide(search_var_frame);
-			gtk_widget_hide(file_filter_frame);
-			break;
-	}
-	
-	dir = search_get_item_combo_name(SEARCH_DIRECTION_COMBO);	
-	
-	if (tgt == SR_SELECTION || tgt == SR_BLOCK || tgt == SR_FUNCTION)
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (combo));
+	if (anj_sr_is_idle (sg))
 	{
+		SearchAction act;
+		SearchRangeType tgt;
+		GtkWidget *wid;
+
+	//	anj_sr_reset_flags ((SearchReplace *)user_data);	/* CHECKME bad to clear selection scope flag, we may have just selected that*/
+		sg->sr->replace.phase = SA_REPL_FIRST;
+		act = anj_sr_get_combo_active_value (combo);
+		tgt = anj_sr_get_combo_id_active_value (sg, SEARCH_ACTION_COMBO);
+
+		switch (act)
+		{
+			case SA_SELECT:
+				anj_sr_show_replace (sg, FALSE);	/* hide all replacment widgets */
+				anj_sr_show_replace_button (sg, FALSE);	/* hide the replace button */
+				anj_sr_modify_button (sg, SEARCH_BUTTON, button_search_label, GTK_STOCK_FIND);
+//				if (tgt == SR_OPEN_BUFFERS || tgt == SR_PROJECT || tgt == SR_FILES)
+//					anj_sr_set_target (sg, SR_BUFFER);
+				break;
+			case SA_REPLACE:
+				anj_sr_show_replace (sg, TRUE);
+				anj_sr_enable_replace_button (sg, FALSE);
+				anj_sr_show_replace_button (sg, TRUE);	/* show (insensitive) replace button */
+				anj_sr_modify_button (sg, SEARCH_BUTTON, button_search_label, GTK_STOCK_FIND);
+//				if (tgt == SR_OPEN_BUFFERS || tgt == SR_PROJECT || tgt == SR_FILES)
+//					anj_sr_set_target (sg, SR_BUFFER);
+				/* CHECKME something safe if regex is active ? */
+				break;
+			case SA_REPLACEALL:
+				anj_sr_show_replace (sg, TRUE);
+				anj_sr_show_replace_button (sg, FALSE);	/* the search button is the starter */
+				anj_sr_modify_button (sg, SEARCH_BUTTON, button_replace_all_label, GTK_STOCK_FIND_AND_REPLACE);
+				wid = anj_sr_get_ui_widget (SEARCH_REGEX);
+				if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wid)))
+				{
+					wid = anj_sr_get_ui_widget (ACTIONS_LIMIT);
+					gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid), TRUE);
+					/* CHECKME other safety if regex is active ? */
+				}
+				break;
+			case SA_HIGHLIGHT:
+			case SA_BOOKMARK:
+				if (tgt == SR_PROJECT || tgt == SR_FILES)
+				{
+					anj_sr_set_target (sg, SR_BUFFER);
+					anj_sr_set_direction (sg, SD_WHOLE);
+				}
+				anj_sr_show_replace (sg, FALSE);
+				anj_sr_show_replace_button (sg, FALSE);
+				anj_sr_modify_button (sg, SEARCH_BUTTON, button_search_label, GTK_STOCK_FIND);
+			case SA_UNLIGHT:
+				if (!(tgt == SR_BUFFER || tgt == SR_OPEN_BUFFERS))
+					anj_sr_set_target (sg, SR_BUFFER);
+				anj_sr_set_direction (sg, SD_WHOLE);
+				/* CHECKME desensitize direction combo */
+			default:
+				anj_sr_show_replace (sg, FALSE);
+				anj_sr_show_replace_button (sg, FALSE);
+				anj_sr_modify_button (sg, SEARCH_BUTTON, button_search_label, GTK_STOCK_FIND);
+				break;
+		}
+//		g_object_set_data (G_OBJECT (combo), "OLDINDX", GINT_TO_POINTER (act));
+	}
+/*	else
+	{
+		gint oldindex;
+
+		oldindex = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "OLDINDX"));
+		g_signal_handlers_block_by_func (G_OBJECT (combo),
+										(gpointer) on_search_action_changed,
+										user_data);
+		gtk_combo_box_set_active (combo, oldindex);
+		g_signal_handlers_unblock_by_func (G_OBJECT (combo),
+										(gpointer) on_search_action_changed,
+										user_data);
+	} */
+}
+
+void
+on_search_target_changed (GtkComboBox *combo, gpointer user_data)
+{
+	SearchReplaceGUI *sg;
+
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (combo));
+	if (anj_sr_is_idle (sg))
+	{
+		SearchReplace *sr;
+		SearchRangeType tgt;
+//		SearchDirection dir;
+		SearchAction act;
+		GtkWidget *file_filter_frame;
 		
-		if (dir == SD_BEGINNING)
+		file_filter_frame = anj_sr_get_ui_widget (FILE_FILTER_FRAME);
+		tgt = anj_sr_get_combo_active_value (combo);
+		switch (tgt)
 		{
-			search_set_direction(SD_FORWARD);
+			case SR_FILES:
+				gtk_widget_show (file_filter_frame);
+				break;
+			default:
+				gtk_widget_hide (file_filter_frame);
+				break;
 		}
-	}
-	if (tgt == SR_OPEN_BUFFERS || tgt == SR_PROJECT ||
-			tgt == SR_FILES)
-	{
-		search_set_direction(SD_BEGINNING);
 
-		act = search_get_item_combo_name(SEARCH_ACTION_COMBO);	
-		if (act != SA_REPLACE && act != SA_REPLACEALL)
+		sr = sg->sr;
+//		dir = anj_sr_get_direction (sr->sg);
+
+		if (tgt == SR_OPEN_BUFFERS || tgt == SR_PROJECT || tgt == SR_FILES)
 		{
-			if (tgt == SR_OPEN_BUFFERS)
-				search_set_action(SA_BOOKMARK);
+			anj_sr_set_direction (sg, SD_WHOLE);
+
+			act = anj_sr_get_combo_id_active_value (sg, SEARCH_ACTION_COMBO);
+			if (act != SA_REPLACE && act != SA_REPLACEALL)
+			{
+				if (tgt == SR_OPEN_BUFFERS)
+					anj_sr_set_action (sg, SA_BOOKMARK);
+				else
+					anj_sr_set_action (sg, SA_FIND_PANE);
+			}
 			else
-				search_set_action(SA_FIND_PANE);
+			{
+				anj_sr_set_action (sg, SA_REPLACEALL);
+				sr->search.action = SA_REPLACEALL;
+			}
 		}
-		else
+		if (!(tgt == SR_BUFFER || tgt == SR_OPEN_BUFFERS))
 		{
-			search_set_action(SA_REPLACEALL);	
-			sr->search.action = SA_REPLACEALL;
+			act = anj_sr_get_combo_id_active_value (sg, SEARCH_ACTION_COMBO);
+			if (act == SA_UNLIGHT)
+			{
+				anj_sr_set_action (sg, SA_SELECT);
+				anj_sr_set_direction (sg, SD_FORWARD);
+			}
 		}
+
+	//	anj_sr_reset_flags (sr);	/* CHECKME selection flag ? just sr->replace.phase = SA_REPL_FIRST; ?*/
+		sr->replace.phase = SA_REPL_FIRST;
+		/*  Resize dialog  */
+		gtk_window_resize (GTK_WINDOW (sr->sg->dialog), 10, 10);
+//		g_object_set_data (G_OBJECT (combo), "OLDINDX", GINT_TO_POINTER (tgt));
 	}
-	reset_flags_and_search_button();
-	/*  Resize dialog  */
-	gtk_window_resize(GTK_WINDOW(sg->dialog), 10, 10);
+/*	else
+	{
+		gint oldindex;
+
+		oldindex = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "OLDINDX"));
+		g_signal_handlers_block_by_func (G_OBJECT (combo),
+										(gpointer) on_search_target_changed,
+										user_data);
+		gtk_combo_box_set_active (combo, oldindex);
+		g_signal_handlers_unblock_by_func (G_OBJECT (combo),
+										(gpointer) on_search_target_changed,
+										user_data);
+	} */
 }
 
 void
-on_search_expression_changed(GtkComboBox *combo, gpointer user_data)
+on_search_expression_changed (GtkComboBox *combo, gpointer user_data)
 {
-	GtkWidget *search_entry = sr_get_gladewidget(SEARCH_STRING)->widget;
-	GtkWidget *widget = sr_get_gladewidget(SEARCH_BUTTON)->widget;
+	SearchReplaceGUI *sg;
+	GtkWidget *search_entry;
+	GtkWidget *widget;
 	gboolean sensitive;
 
-	sensitive = *gtk_entry_get_text (GTK_ENTRY (search_entry)) == '\0' ? FALSE: TRUE;
-	gtk_widget_set_sensitive (widget, sensitive);
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (combo));
+	if (anj_sr_is_idle (sg))
+	{
+	//	search_entry = anj_sr_get_ui_widget (SEARCH_STRING);
+		search_entry = GTK_BIN (combo)->child;
+		sensitive = (*gtk_entry_get_text (GTK_ENTRY (search_entry)) != '\0');
+		widget = anj_sr_get_ui_widget (SEARCH_BUTTON);
+		gtk_widget_set_sensitive (widget, sensitive);
+//		g_object_set_data (G_OBJECT (combo), "OLDINDX", GINT_TO_POINTER (?));
+	}
+/*	else
+	{
+		gint oldindex;
+
+		oldindex = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "OLDINDX"));
+		g_signal_handlers_block_by_func (G_OBJECT (combo),
+										(gpointer) on_search_expression_changed,
+										user_data);
+		gtk_combo_box_set_active (combo, oldindex);
+		g_signal_handlers_unblock_by_func (G_OBJECT (combo),
+										(gpointer) on_search_expression_changed,
+										user_data);
+	} */
 }
-
-
+/*
 void
-on_actions_no_limit_clicked(GtkButton *button, gpointer user_data)
+on_replace_expression_changed (GtkComboBox *combo, gpointer user_data)
 {
-	GtkWidget *actions_max = sr_get_gladewidget(ACTIONS_MAX)->widget;
-	
-	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
-    	gtk_widget_set_sensitive (actions_max, FALSE);
-	else
-		gtk_widget_set_sensitive (actions_max, TRUE);	
-}
+	SearchReplaceGUI *sg;
 
-void
-on_search_button_close_clicked(GtkButton *button, gpointer user_data)
-{
-	if (sg->showing)
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (combo));
+	if (anj_sr_is_idle (sg))
 	{
-		gtk_widget_hide(sg->dialog);
-		sg->showing = FALSE;
+		g_object_set_data (G_OBJECT (combo), "OLDINDX", GINT_TO_POINTER (?));
 	}
-}
+	else
+	{
+		gint oldindex;
 
-void
-on_search_button_stop_clicked(GtkButton *button, gpointer user_data)
-{
-	end_activity = TRUE;
+		oldindex = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "OLDINDX"));
+		g_signal_handlers_block_by_func (G_OBJECT (combo),
+										(gpointer) on_replace_expression_changed,
+										user_data);
+		gtk_combo_box_set_active (combo, oldindex);
+		g_signal_handlers_unblock_by_func (G_OBJECT (combo),
+										(gpointer) on_replace_expression_changed,
+										user_data);
+	}
 }
-
+*/
 void
-on_search_button_next_clicked(GtkButton *button, gpointer user_data)
-{	
-	clear_pcre(); 	
-	search_replace_populate();
+on_search_button_close_clicked (GtkButton *button, gpointer user_data)
+{
+	SearchReplaceGUI *sg;
 
-	search_and_replace();
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (button));
+	if (sg != NULL)
+		anj_sr_interrupt_nicely (sg);
 }
 
-void search_replace_find_usage(const gchar *symbol)
+void
+on_search_button_stop_clicked (GtkButton *button, gpointer user_data)
 {
-	gchar *project_root_uri = NULL;
-	SearchReplace *old_sr = sr;
-	AnjutaShell* shell;
-	
-	sr = g_new (SearchReplace, 1);
-
-	sr->search.expr.search_str = g_strdup (symbol);
-	sr->search.expr.regex = FALSE;
-	sr->search.expr.greedy = FALSE;
-	sr->search.expr.ignore_case = FALSE;
-	sr->search.expr.whole_word = TRUE;
-	sr->search.expr.whole_line = FALSE;
-	sr->search.expr.word_start = FALSE;
-	sr->search.expr.no_limit = TRUE;
-	sr->search.expr.actions_max = G_MAXINT;
-	sr->search.expr.re = NULL;
-		
-	g_object_get(G_OBJECT(sr->docman), "shell", &shell, NULL);
-	
-	anjuta_shell_get (shell,
-					  "project_root_uri", G_TYPE_STRING,
-					  &project_root_uri, NULL);
-	
-	sr->search.range.type =
-		project_root_uri != NULL ? SR_PROJECT : SR_OPEN_BUFFERS;
-	g_free (project_root_uri);
-	
-	sr->search.range.direction = SD_BEGINNING;
-
-	sr->search.range.var = NULL;
-
-	sr->search.range.files.top_dir = NULL;
-	sr->search.range.files.match_files = NULL;
-	sr->search.range.files.match_dirs = NULL;
-	sr->search.range.files.ignore_files = NULL;
-	sr->search.range.files.ignore_dirs = NULL;
-	sr->search.range.files.ignore_hidden_files = TRUE;
-	sr->search.range.files.ignore_hidden_dirs = TRUE;
-	sr->search.range.files.recurse = TRUE;
-
-	sr->search.action = SA_FIND_PANE;
+	SearchReplaceGUI *sg;
 
-	sr->search.expr_history = NULL;
-	sr->search.incremental_pos = 0;
-	sr->search.incremental_wrap = TRUE;
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (button));
+	if (sg != NULL)
+	{
+		SearchReplace *sr;
 
-	create_dialog ();
+		sr = sg->sr;
 
-	search_and_replace();
-	g_free (sr);
-	sr = old_sr;
+		if (sr->search.action == SA_REPLACE && sr->replace.phase == SA_REPL_CONFIRM)
+		{
+			/* stop the current interactive replace */
+			gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
+			anj_sr_show_replace_button (sg, FALSE);
+			anj_sr_enable_replace_button (sg, FALSE);
+			sr->replace.phase = SA_REPL_FIRST;
+			sr->search.busy = FALSE;
+			if (sr->search.expr.regex)
+			{
+				pcre_info_free (sr->search.expr.re);
+				sr->search.expr.re = NULL;
+			}
+			clear_search_entries (&(sr->search.candidates));
+			anj_sr_set_action (sg, SA_SELECT);
+		}
+		else
+			sr->search.stop_count++;
+		}
 }
 
+/* callback for "search|replace-all" button in s/r dialog */
+/* this initiates a s/r operation or skips to the next location when
+   denying a replacement */
 void
-on_search_button_jump_clicked(GtkButton *button, gpointer user_data)
+on_search_button_start_clicked (GtkButton *button, gpointer user_data)
 {
-	if (sr)
-		interactive = FALSE;
-	gtk_widget_hide(GTK_WIDGET(button));
+	SearchReplaceGUI *sg;
+	SearchReplace *sr;
 
-	search_replace_populate();
-	search_and_replace();
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (button));
+	if (anj_sr_is_idle (sg))
+	{
+		anj_sr_populate_data (sg);
+		sr = sg->sr;
+		if (sr->search.action == SA_REPLACE)
+			sr->replace.phase = SA_REPL_FIRST;
+		sr->search.matches_sofar = 0;
+		anj_sr_execute (sr, TRUE);
+	}
+	else
+	{
+		sr = sg->sr;
+		if (sr->search.action == SA_REPLACE
+			&& sr->replace.phase == SA_REPL_CONFIRM)
+		{
+			/* want to skip a replacement */
+			sr->replace.phase = SA_REPL_SKIP;
+			anj_sr_execute (sr, TRUE);
+		}
+	}
 }
 
+/* callback for "replace" button when confirming a replacement in s/r dialog */
 void
-on_search_expression_activate (GtkEditable *edit, gpointer user_data)
+on_search_button_replace_clicked (GtkButton *button, gpointer user_data)
 {
-	GtkWidget *combo;
-
-	search_replace_populate();
-	
-	search_and_replace();
-	combo = GTK_WIDGET(edit)->parent;
-	reset_flags_and_search_button();
-}
-
+	SearchReplaceGUI *sg;
 
-void
-on_search_full_buffer_toggled (GtkToggleButton *togglebutton, 
-									gpointer user_data)
-{
-	if (gtk_toggle_button_get_active(togglebutton))
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (button));
+	if (!anj_sr_is_idle (sg))	/* this action valid only when paused for confirmation == busy */
 	{
-		search_set_direction(SD_BEGINNING);
+		anj_sr_populate_data (sg);
+		anj_sr_execute (sg->sr, TRUE);
+	/*	if (sr->search.action != SA_REPLACE || sr->replace.phase != SA_REPL_CONFIRM)
+		{
+			anj_sr_reset_flags (sr);	/ * CHECKME selection flag ? just sr->replace.phase = SA_REPL_FIRST; ?* /
+			anj_sr_reset_replace_buttons (sr);
+		}
+	*/
 	}
 }
 
 void
-on_search_forward_toggled (GtkToggleButton *togglebutton, 
-									gpointer user_data)
+on_search_expression_activate (GtkEditable *edit, gpointer user_data)
 {
-	if (gtk_toggle_button_get_active(togglebutton))
+	SearchReplaceGUI *sg;
+
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (edit));
+	if (anj_sr_is_idle (sg))
 	{
-		search_set_direction(SD_FORWARD);
+//		GtkWidget *combo;
+//		SearchReplace *sr;
+
+		anj_sr_populate_data (sg);
+//		sr = sg->sr;
+		anj_sr_execute (sg->sr, TRUE);
+//		combo = GTK_WIDGET(edit)->parent;
+/*		if (sr->search.action != SA_REPLACE || sr->replace.phase != SA_REPL_CONFIRM)
+		{
+			/ * this is not a first-pass replacement * /
+			anj_sr_reset_flags (sr);	/ * CHECKME selection flag ? just sr->replace.phase = SA_REPL_FIRST; ?* /
+			anj_sr_reset_replace_buttons (sr);
+		}
+*/
 	}
 }
-
+/*
 void
-on_search_backward_toggled (GtkToggleButton *togglebutton, 
-									gpointer user_data)
+on_search_full_buffer_toggled (GtkToggleButton *togglebutton, gpointer user_data)
 {
-	if (gtk_toggle_button_get_active(togglebutton))
+	SearchReplaceGUI *sg;
+	gboolean state;
+
+	state = gtk_toggle_button_get_active (togglebutton);
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (togglebutton));
+	if (anj_sr_is_idle (sg))
+	{
+		if (state)
+			anj_sr_set_direction (SD_WHOLE);
+	}
+	else
 	{
-		search_set_direction(SD_BACKWARD);
+		g_signal_handlers_block_by_func (G_OBJECT (togglebutton),
+										(gpointer) ,
+										user_data);
+		gtk_toggle_button_set_active (togglebutton, !state);
+		g_signal_handlers_unblock_by_func (G_OBJECT (togglebutton),
+										(gpointer) ,
+										user_data);
 	}
 }
-
+*/
+/*
 void
-on_setting_basic_search_toggled (GtkToggleButton *togglebutton, 
-									gpointer user_data)
+on_search_forward_toggled (GtkToggleButton *togglebutton,
+							gpointer user_data)
 {
-	SearchAction act;
-	GtkWidget *frame_basic = sr_get_gladewidget(FRAME_SEARCH_BASIC)->widget;
+	SearchReplaceGUI *sg;
+	gboolean state;
 
-	if (gtk_toggle_button_get_active(togglebutton))
+	state = gtk_toggle_button_get_active (togglebutton);
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (togglebutton));
+	if (anj_sr_is_idle (sg))
 	{
-    	gtk_widget_show(frame_basic);
-		search_set_target(SR_BUFFER);	
-		search_set_direction(SD_FORWARD);
-
-		act = search_get_item_combo_name(SEARCH_ACTION_COMBO);
-		if (act == SA_REPLACE || act == SA_REPLACEALL)
-			search_set_action(SA_REPLACE);
-		else		
-			search_set_action(SA_SELECT);
+		if (state)
+			anj_sr_set_direction (SD_FORWARD);
 	}
 	else
-		gtk_widget_hide(frame_basic);
+	{
+		g_signal_handlers_block_by_func (G_OBJECT (togglebutton),
+										(gpointer) ,
+										user_data);
+		gtk_toggle_button_set_active (togglebutton, !state);
+		g_signal_handlers_unblock_by_func (G_OBJECT (togglebutton),
+										(gpointer) ,
+										user_data);
+	}
 }
 
-
-static void
-basic_search_toggled(void)
+void
+on_search_backward_toggled (GtkToggleButton *togglebutton,
+							gpointer user_data)
 {
-	GtkToggleButton *togglebutton;
-	
-	togglebutton = GTK_TOGGLE_BUTTON(sr_get_gladewidget(SEARCH_BASIC)->widget);
-	
-	on_setting_basic_search_toggled (togglebutton, NULL);
-}
+	SearchReplaceGUI *sg;
+	gboolean state;
 
-/***********************************************************************/
-
-#define MAX_LENGTH_SEARCH 64
-
-void 
-anjuta_search_replace_activate (gboolean replace, gboolean project)
+	state = gtk_toggle_button_get_active (togglebutton);
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (togglebutton));
+	if (anj_sr_is_idle (sg))
+	{
+		if (state)
+			anj_sr_set_direction (SD_BACKWARD);
+	}
+	else
+	{
+		g_signal_handlers_block_by_func (G_OBJECT (togglebutton),
+										(gpointer) ,
+										user_data);
+		gtk_toggle_button_set_active (togglebutton, !state);
+		g_signal_handlers_unblock_by_func (G_OBJECT (togglebutton),
+										(gpointer) ,
+										user_data);
+	}
+*/
+/* diabled basic-search option
+void
+on_setting_basic_search_toggled (GtkToggleButton *togglebutton,
+								 gpointer user_data)
 {
-	GtkWidget *notebook;
-	GtkWidget *search_entry;
-	IAnjutaDocument *doc;
-	IAnjutaEditor *te;
+	SearchReplaceGUI *sg;
+	gboolean state;
 
-	create_dialog ();
+	state = gtk_toggle_button_get_active (togglebutton);
+	sg = anj_sr_get_current_uidata (GTK_WIDGET (togglebutton));
+	if (anj_sr_is_idle (sg))
+	{
+		GtkWidget *frame;
 
-	search_update_dialog();
+		frame = anj_sr_get_ui_widget (SEARCH_SCOPE_FRAME); / * CHECKME with new dialog layout * /
+		if (state)
+		{
+			SearchAction act;
 
-	search_replace_populate();
+			gtk_widget_show (frame);
+			anj_sr_set_target (SR_BUFFER);
+			anj_sr_set_direction (SD_FORWARD);
 
-	reset_flags_and_search_button();
-	
-	search_entry = sr_get_gladewidget(SEARCH_STRING)->widget;
-	doc = ianjuta_document_manager_get_current_document(sr->docman, NULL);
-	te = (IANJUTA_IS_EDITOR (doc)) ? IANJUTA_EDITOR (doc) : NULL;
-	if (te && search_entry && sr->search.range.type != SR_SELECTION)
-	{
-		/* Set properties */
-		gchar *current_word;
-
-		current_word = ianjuta_editor_selection_get
-						(IANJUTA_EDITOR_SELECTION (te), NULL);
-		if (current_word == NULL)
-			current_word = ianjuta_editor_get_current_word (te, NULL);
-
-		if (current_word && strlen(current_word) > 0 )
-		{
-			if (strlen(current_word) > MAX_LENGTH_SEARCH)
-				current_word[MAX_LENGTH_SEARCH] = '\0';
-			gtk_entry_set_text(GTK_ENTRY (search_entry), current_word);
-			g_free(current_word);
+			act = anj_sr_get_combo_id_active_value (SEARCH_ACTION_COMBO);
+			if (act == SA_REPLACE || act == SA_REPLACEALL)
+				anj_sr_set_action (SA_REPLACE);
+			else
+				anj_sr_set_action (SA_SELECT);
 		}
-	}
-	
-	if (replace)
-	{
-		if ( !(sr->search.action == SA_REPLACE || 
-				sr->search.action == SA_REPLACEALL))
-		{
-			search_set_action(SA_REPLACE);
-			sr->search.action = SA_REPLACE;
-			search_show_replace(TRUE);
-		}		
+		else
+			gtk_widget_hide (frame);
 	}
 	else
 	{
-		if (sr->search.action == SA_REPLACE || sr->search.action == SA_REPLACEALL)	
-		{
-			search_set_action(SA_SELECT);
-			sr->search.action = SA_SELECT;
-			search_show_replace(FALSE);
-		}
-	}
-	if (sr->search.action != SA_REPLACEALL)
-		modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
-	
-	if (project)
-	{
-		search_set_target(SR_PROJECT);
-		if (!replace)
-		{
-			search_set_action (SA_FIND_PANE);
-			search_set_direction (SD_BEGINNING);
-		}
+		g_signal_handlers_block_by_func (G_OBJECT (togglebutton),
+										(gpointer) on_setting_basic_search_toggled,
+										user_data);
+		gtk_toggle_button_set_active (togglebutton, !state);
+		g_signal_handlers_unblock_by_func (G_OBJECT (togglebutton),
+										(gpointer) on_setting_basic_search_toggled,
+										user_data);
 	}
-	show_jump_button(FALSE);
-	
-	notebook = sr_get_gladewidget(SEARCH_NOTEBOOK)->widget;
-	gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0);
-	
-	/* Show the dialog */
-	if (search_entry)
-	gtk_widget_grab_focus (search_entry);
-	show_dialog();
 }
+*/

Modified: trunk/plugins/search/search-replace.h
==============================================================================
--- trunk/plugins/search/search-replace.h	(original)
+++ trunk/plugins/search/search-replace.h	Fri Apr 11 00:19:38 2008
@@ -1,3 +1,25 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * search-replace.h: Generic Search and Replace header file
+ * Copyright (C) 2004 Biswapesh Chattopadhyay
+ * Copyright (C) 2004-2007 Naba Kumar  <naba gnome org>
+ *
+ * This file is part of anjuta.
+ * Anjuta 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 2 of the License, or (at your option)
+ * any later version.
+ *
+ * Anjuta 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 anjuta. If not, contact the Free Software Foundation,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
 #ifndef _SEARCH_REPLACE_H
 #define _SEARCH_REPLACE_H
 
@@ -8,58 +30,53 @@
 
 #include <glib.h>
 #include <pcre.h>
-#include <glade/glade.h>
-
+#include "search-replace_backend.h"
+	
 typedef enum _GUIElementType
 {
 	GE_NONE,
 	GE_BUTTON,
+	GE_COMBO,
 	GE_COMBO_ENTRY,
-	GE_TEXT,
-	GE_BOOLEAN,
-	GE_COMBO
+	GE_TEXT,	/* anything else that implements GtkEditable interface */
+	GE_BOOLEAN
 } GUIElementType;
 
-typedef struct _GladeWidget
+typedef struct _GUIElement
 {
 	GUIElementType type;
-	char *name;
+	gchar *name;
 	gpointer extra;
-	GtkWidget *widget;
-} GladeWidget;
+} GUIElement;
 
 #define GLADE_FILE "anjuta.glade"
 #define SEARCH_REPLACE_DIALOG "dialog.search.replace"
 
-/* Enum for all useful glade widget */
-typedef enum _GladeWidgetId
+/* enum for all glade widgets that need specific handling */
+typedef enum _GUIElementId
 {
 	CLOSE_BUTTON,
 	STOP_BUTTON,
+	REPLACE_BUTTON,
 	SEARCH_BUTTON,
-	JUMP_BUTTON,
-	SEARCH_NOTEBOOK,
 
 	/* Frames */
-	SEARCH_EXPR_FRAME,
-	SEARCH_TARGET_FRAME,
-	SEARCH_VAR_FRAME,
 	FILE_FILTER_FRAME,
-	FRAME_SEARCH_BASIC,
+	SEARCH_SCOPE_FRAME,
 
 	/* Labels */
 	LABEL_REPLACE,
 
 	/* Entries */
 	SEARCH_STRING,
-	SEARCH_VAR,
 	MATCH_FILES,
 	UNMATCH_FILES,
 	MATCH_DIRS,
 	UNMATCH_DIRS,
 	REPLACE_STRING,
+
+	/* Spinner */
 	ACTIONS_MAX,
-	SETTING_PREF_ENTRY,
 
 	/* Checkboxes */
 	SEARCH_REGEX,
@@ -69,43 +86,59 @@
 	WORD_START,
 	WHOLE_LINE,
 	IGNORE_HIDDEN_FILES,
-	IGNORE_BINARY_FILES,
 	IGNORE_HIDDEN_DIRS,
 	SEARCH_RECURSIVE,
 	REPLACE_REGEX,
-	ACTIONS_NO_LIMIT,
-	SEARCH_FULL_BUFFER,
+//	SEARCH_BASIC,
+
+	/* Radio buttons */
+	SEARCH_WHOLE,
 	SEARCH_FORWARD,
 	SEARCH_BACKWARD,
-	SEARCH_BASIC,
+	ACTIONS_NO_LIMIT,
+	ACTIONS_LIMIT,
 
 	/* Combo boxes */
 	SEARCH_STRING_COMBO,
 	SEARCH_TARGET_COMBO,
 	SEARCH_ACTION_COMBO,
-	SEARCH_VAR_COMBO,
 	MATCH_FILES_COMBO,
 	UNMATCH_FILES_COMBO,
 	MATCH_DIRS_COMBO,
 	UNMATCH_DIRS_COMBO,
 	REPLACE_STRING_COMBO,
-	SEARCH_DIRECTION_COMBO,
 
-	/* Treeview */
-	SETTING_PREF_TREEVIEW
-} GladeWidgetId;
-
-void search_and_replace_init (IAnjutaDocumentManager* dm);
-void search_and_replace (void);
-void search_replace_next(void);
-void search_replace_previous(void);
-void search_replace_find_usage(const gchar *symbol);
-void anjuta_search_replace_activate (gboolean replace, gboolean project);
-GladeWidget *sr_get_gladewidget(GladeWidgetId id);
-void search_replace_populate(void);
-void search_update_dialog(void);
+	GUI_ELEMENT_COUNT
+} GUIElementId;
+
+typedef struct _SearchReplaceGUI
+{
+	GladeXML *xml;
+	GtkWidget *dialog;
+	GtkWidget *widgets [GUI_ELEMENT_COUNT];	/* array of widgets for each GUIElement */
+	SearchReplace *sr;	/* current s/r data */
+	gboolean showing;
+} SearchReplaceGUI;
+
+void anj_sr_execute (SearchReplace *sr, gboolean dlg);
+void anj_sr_select_next (SearchReplaceGUI *sg);
+void anj_sr_select_previous (SearchReplaceGUI *sg);
+void anj_sr_activate (gboolean replace, gboolean project);
+void anj_sr_list_all_uses (const gchar *symbol);
+void anj_sr_repeat (SearchReplaceGUI *sg);
+//GUIElement *anj_sr_get_ui_element (GUIElementId id);
+//GtkWidget *anj_sr_get_ui_widget (GUIElementId id);
+#define anj_sr_get_ui_widget(id) sg->widgets[id]
+void anj_sr_populate_data (SearchReplaceGUI *sg);
+void anj_sr_populate_dialog (SearchReplaceGUI *sg);
+void anj_sr_set_dialog_searchdata (SearchReplaceGUI *sg, SearchReplace *sr);
+SearchReplaceGUI *anj_sr_get_default_uidata (void);
+SearchReplaceGUI *anj_sr_get_current_uidata (GtkWidget *widget);
+void anj_sr_get_best_uidata (SearchReplaceGUI **sg, SearchReplace **sr);
+void anj_sr_destroy_ui_data (SearchReplaceGUI *sg);
+void anj_sr_execute_init (AnjutaPlugin *plugin);
 
-void search_toolbar_set_text(gchar *search_text);
+//void search_toolbar_set_text(gchar *search_text);
 
 #ifdef __cplusplus
 }

Modified: trunk/plugins/search/search-replace_backend.c
==============================================================================
--- trunk/plugins/search/search-replace_backend.c	(original)
+++ trunk/plugins/search/search-replace_backend.c	Fri Apr 11 00:19:38 2008
@@ -1,26 +1,24 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
-
-/*
-** search-replace_backend.c: Generic Search and Replace
-** Author: Biswapesh Chattopadhyay
-*/
-
 /*
- *  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 2 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 Library General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * search-replace_backend.c: Generic Search and Replace
+ * Copyright (C) 2004 Biswapesh Chattopadhyay
+ * Copyright (C) 2004-2007 Naba Kumar  <naba gnome org>
+ *
+ * This file is part of anjuta.
+ * Anjuta 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Anjuta 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 anjuta; if not, contact the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
- 
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -46,90 +44,180 @@
 #include <libanjuta/anjuta-plugin.h>
 #include <libanjuta/anjuta-debug.h>
 #include <libanjuta/interfaces/ianjuta-editor.h>
+#include <libanjuta/interfaces/ianjuta-editor-search.h>
+#include <libanjuta/interfaces/ianjuta-editor-selection.h>
+#include <libanjuta/interfaces/ianjuta-editor-line-mode.h>
 #include <libanjuta/interfaces/ianjuta-document.h>
 #include <libanjuta/interfaces/ianjuta-file.h>
-#include <libanjuta/interfaces/ianjuta-editor-selection.h>
 #include <libanjuta/interfaces/ianjuta-project-manager.h>
 
-/*
-#define GTK
-#undef PLAT_GTK
-#define PLAT_GTK 1
-#include "Scintilla.h"
-#include "SciLexer.h"
-#include "ScintillaWidget.h"
-*/
-
 #include "search-replace_backend.h"
 #include "tm_tagmanager.h"
 
-/* Information about a matched substring */
+/* Information about a matched substring in a regex search */
 typedef struct _MatchSubStr
 {
-	gint start;
-	gint len;
+	position_t start;	/* relates to pcre ovector (gint), bytes or chars depending on utf8 support */
+	position_t len;		/* ditto */
 } MatchSubStr;
+/* Information about an EOL in a file buffer (note - 2 pointers are enough for a slice */
+typedef struct _EOLdata
+{
+	position_t offb;	/* byte-offset of EOL */
+	position_t offc;	/* char-offset of EOL */
+} EOLdata;
+
+#define REGX_BACKCOUNT 10
+#define REGX_BUFSIZE 1024
 
-static SearchReplace *sr = NULL;
+static SearchPlugin *splugin;			/* the plugin pointer set when plugin was activated */
+static SearchReplace *def_sr = NULL;	/* session-static sr data, typically used
+										   with the single "main" search dialog */
+
+//static gboolean search_locally (SearchExpression *se,
+//								  SearchDirection direction,
+//								  position_t hlen);
+static void file_buffer_find_lines (FileBuffer *fb, GList *startpos);
+//static void file_buffer_set_byte_length (FileBuffer *fb, position_t bytelength);
+static void clear_search_replace_instance (SearchReplace *sr);
+
+
+/**
+ * regex_backref:
+ * @sr: pointer to populated search/replace data struct
+ * @mi: pointer to match info data for the match being processed
+ * @fb: pointer to file-buffer data for file being processed
+ *
+ * Construct a replacement string from regex patterns with back reference(s)
+ *
+ * Return value: the newly-allocated string
+ */
+gchar *
+regex_backref (SearchReplace *sr, MatchInfo *mi, FileBuffer *fb)
+{
+	gint i, j, k;
+	gint nb_backref;
+	gint i_backref;
+	gint plen;
+	position_t start, len;
+	position_t backref [REGX_BACKCOUNT][2];	/* contains byte-positions and -lengths */
+	gchar buf [REGX_BUFSIZE + 4];	/* usable space + word-sized space for trailing 0 */
+	GList *node;
 
-void clear_search_replace_instance(void);
+	/* get easier access to back reference data */
+	for (node = mi->subs, i = 1;	/* \0 is not supported */
+		node != NULL && i < REGX_BACKCOUNT;
+		node = g_list_next (node), i++)
+ 	{
+		backref[i][0] = ((MatchSubStr*)node->data)->start;
+		backref[i][1] = ((MatchSubStr*)node->data)->len;
+	}
+	nb_backref = i;
+	plen = strlen (sr->replace.repl_str);
+	for (i = 0, j = 0; i < plen && j < REGX_BUFSIZE; i++)
+	{
+		if (sr->replace.repl_str[i] == '\\')
+		{
+			i++;
+			if (sr->replace.repl_str[i] > '0' && sr->replace.repl_str[i] <= '9')
+			{
+				i_backref = sr->replace.repl_str[i] - '0';
+				if (i_backref < nb_backref)
+				{
+					start = backref[i_backref] [0];
+					len = backref[i_backref] [1];
+					for (k = 0; k < len && j < REGX_BUFSIZE; k++)
+						buf[j++] = fb->buf[start + k];
+				}
+			}
+		}
+		else
+			buf[j++] = sr->replace.repl_str[i];
+	}
+	buf[j] = '\0';
 
+	return g_strdup (buf);
+}
 
-static void
+/**
+ * pcre_info_free:
+ * @re: pointer to re data struct to clear, may be NULL
+ *
+ * Return value: none
+ */
+void
 pcre_info_free (PcreInfo *re)
 {
-	if (re)
+	if (re != NULL)
 	{
 		if (re->re)
 			(*pcre_free)(re->re);
 		if (re->extra)
 			(*pcre_free)(re->extra);
 		if (re->ovector)
-			g_free(re->ovector);
-		g_free(re);
+			g_free (re->ovector);
+		g_slice_free1 (sizeof (PcreInfo), re);
 	}
 }
 
+/**
+ * pcre_info_new:
+ * @se:
+ *
+ * Compile and setup data for regex search/replace
+ *
+ * Return value: pcre data struct
+ */
 static PcreInfo *
-pcre_info_new (SearchExpression *s)
+pcre_info_new (SearchExpression *se)
 {
 	PcreInfo *re;
-	int options = 0;
-	const char *err;
-	int err_offset;
-	int status;
-
-	g_return_val_if_fail(s && s->search_str, NULL);
-	re = g_new0(PcreInfo, 1);
-	if (s->ignore_case)
+	gint options;
+	const gchar *err;
+	gint err_offset;	//CHECKME type position_t
+	gint status;
+
+	g_return_val_if_fail (se && se->search_str, NULL);
+	re = g_slice_new0 (PcreInfo);
+	options = PCRE_NEWLINE_ANYCRLF;	//or PCRE_NEWLINE_ANY ?
+	if (se->ignore_case)
 		options |= PCRE_CASELESS;
-	if (!s->greedy)
+	if (!se->greedy)
 		options |= PCRE_UNGREEDY;
-	re->re = pcre_compile(s->search_str, options, &err, &err_offset, NULL);
-	if (NULL == re->re)
+	if (se->utf8regex)
+		options |= PCRE_UTF8|PCRE_NO_UTF8_CHECK;
+	re->re = pcre_compile (se->search_str, options, &err, &err_offset, NULL);
+	if (re->re == NULL)
 	{
 		/* Compile failed - check error message */
 		g_warning("Regex compile failed! %s at position %d", err, err_offset);
-		pcre_info_free(re);
+		pcre_info_free (re);
 		return NULL;
 	}
-	re->extra = pcre_study(re->re, 0, &err);
-	status = pcre_fullinfo(re->re, re->extra, PCRE_INFO_CAPTURECOUNT
-	  , &(re->ovec_count));
-	re->ovector = g_new0(int, 3 *(re->ovec_count + 1));
+	re->extra = pcre_study (re->re, 0, &err);
+	status = pcre_fullinfo (re->re, re->extra, PCRE_INFO_CAPTURECOUNT,
+							&(re->ovec_count));
+	re->ovector = g_new0 (position_t, 3 *(re->ovec_count + 1));	/* pcre uses gint */
 	return re;
 }
 
-
-static void match_substr_free(MatchSubStr *ms)
+static void
+match_substr_free (MatchSubStr *ms)
 {
 	if (ms)
-		g_free(ms);
+		g_slice_free1 (sizeof (MatchSubStr), ms);
 }
 
-
+/**
+ * match_info_free_subs:
+ * @mi:
+ *
+ * Clear list of regex replacment backref data referenced in @mi
+ *
+ * Return value: None
+ */
 void
-match_info_free (MatchInfo *mi)
+match_info_free_subs (MatchInfo *mi)
 {
 	if (mi)
 	{
@@ -137,401 +225,1582 @@
 		{
 			GList *tmp;
 			for (tmp = mi->subs; tmp; tmp = g_list_next(tmp))
-				match_substr_free((MatchSubStr *) tmp->data);
-			g_list_free(mi->subs);
+				match_substr_free ((MatchSubStr *) tmp->data);
+			g_list_free (mi->subs);
 		}
-		g_free(mi);
 	}
 }
 
-
+/**
+ * editor_new_from_file_buffer:
+ * @te: pointer to file buffer data struct for a not-open file
+ *
+ * Add a new editor to docman, and set it up according to @fb data
+ *
+ * Return value: None, but failure will be indicated by fb->te == NULL
+ */
 void
-file_buffer_free (FileBuffer *fb)
+editor_new_from_file_buffer (SearchEntry *se)
 {
-	if (fb)
-	{
-		if (fb->path)
-			g_free(fb->path);
-		if (fb->uri)
-			g_free (fb->uri);
-		if (fb->buf)
-			g_free(fb->buf);
-		if (fb->lines)
-			g_list_free(fb->lines);
-		g_free(fb);
-	}
+	FileBuffer *fb;
+
+	fb = se->fb;
+	/* CHECKME se->uri must be an escaped uri string such as returned by
+		gnome_vfs_get_uri_from_local_path() */
+	fb->te = ianjuta_document_manager_goto_uri_line (splugin->docman,
+													 se->uri,
+													 se->mi.line, NULL);
+	g_return_if_fail (fb->te);
+
+	/* CHECKME can we safely omit the rest ?*/
+//	g_free (fb->buf);
+//	fb->buf =
+	gchar *newtext = ianjuta_editor_get_text_all (fb->te, NULL);
+	if (strcmp (newtext, fb->buf) == 0)
+		DEBUG_PRINT ("File buffer matches editor text");
+	else
+		DEBUG_PRINT ("File buffer DOPES NOT MATCH editor text");
+	g_free (fb->buf);
+	fb->buf = newtext;
+
+	fb->line = ianjuta_editor_get_lineno (fb->te, NULL);
+#ifdef MANAGE_EOL
+	fb->separator_type = EOL_UNKNOWN;	/* log the EOL-type when finding lines */
+#endif
+	file_buffer_find_lines (fb, NULL);	/* get all line-ends data for file */
+	fb->len = file_buffer_get_char_offset (fb, -1);	/* character-length */
 }
 
-/* Create a file buffer structure from a TextEditor structure */
+/**
+ * file_buffer_new_from_te:
+ * @te: pointer to text editor data struct for an upen file
+ *
+ * Create a file buffer structure for an already-opened file
+ * The file text is copied into a newly-allocated buffer. This should already
+ * be encoded as UTF-8 by the normal opening process
+ *
+ * Return value: the new data struct
+ */
 FileBuffer *
 file_buffer_new_from_te (IAnjutaEditor *te)
 {
 	FileBuffer *fb;
-	gchar* uri;
-	gchar* path;
-	
-	g_return_val_if_fail(te, NULL);
-	fb = g_new0(FileBuffer, 1);
-	fb->type = FB_EDITOR;
+	gchar *uri;
+
+	g_return_val_if_fail (te, NULL);
+	fb = g_slice_new0 (FileBuffer);
+	fb->type = FB_BUFFER;
 	fb->te = te;
-	
-	uri = ianjuta_file_get_uri(IANJUTA_FILE(te), NULL);
-	path = gnome_vfs_get_local_path_from_uri(uri);
-	if (path)
-	{
-		fb->path = tm_get_real_path(path);
-		g_free (path);
-	}
-	fb->uri = uri;
-	fb->len = ianjuta_editor_get_length(te, NULL);
-	fb->buf = ianjuta_editor_get_text_all (fb->te, NULL);
-	fb->pos = ianjuta_editor_get_offset(fb->te, NULL);
-	fb->line = ianjuta_editor_get_lineno(fb->te, NULL);
-	
+
+	uri = ianjuta_file_get_uri (IANJUTA_FILE (te), NULL);
+	if (uri)
+	{
+		//CHECKME any escaping or other cleanup ?
+		fb->uri = gnome_vfs_make_uri_canonical (uri);
+		if (fb->uri == NULL)
+			fb->uri = uri;
+		else
+			g_free (uri);
+	}
+	/*CHECKME is NULL uri ok if uri was not found or conversion failed ?
+	else
+		fb->uri = ?; */
+	/* specific text length N/A as length returned by editor may be chars, not bytes */
+	/* can't yet efficiently check whether a local buffer is needed, as such check
+	   includes the byte-length of the text to search */
+/*	position_t hlen = length reported by editor
+	if editor uses char-positions, convert length to bytes
+	BUT line-ends not yet parsed
+	if (search_locally (SearchExpression *se, SearchDirection direction, position_t hlen)) */
+		fb->buf = ianjuta_editor_get_text_all (fb->te, NULL);
+	fb->line = ianjuta_editor_get_lineno (fb->te, NULL);
+	/* don't log the EOL-type when finding lines, in this context */
+	file_buffer_find_lines (fb, NULL);	/* get all line-ends data for file */
+	fb->len = file_buffer_get_char_offset (fb, -1);	/* character-length */
+
 	return fb;
 }
 
+/**
+ * file_buffer_new_from_uri:
+ * @sr: pointer to populated search/replace data struct
+ * @uri: uri of file to open
+ * @buf: buffer holding current contents of the file, or NULL to read the file
+ * @len: byte-size of non-NULL @buf, or -1 to get length of 0-terminated @buf
+ *
+ * Create and populate a file buffer for file with path @path.
+ * The file may be opened already.
+ * Symlinks in @path are reconciled.
+ * The contents of non-NULL @buf are copied.
+ * If the file is not open before, its contents are converted to UTF-8 if needed.
+ *
+ * Return value: the new data struct, or NULL upon error
+ */
 FileBuffer *
-file_buffer_new_from_path (const char *path, const char *buf, int len, int pos)
+file_buffer_new_from_uri (SearchReplace *sr,
+						  const gchar *uri,
+						  const gchar *buf,
+						  position_t len)
 {
 	FileBuffer *fb;
-	IAnjutaEditor *te;
-	IAnjutaDocument* doc;
-	char *real_path;
-	char *uri;
-	int i;
-	int lineno;
-
-	g_return_val_if_fail(path, NULL);
-	real_path = tm_get_real_path(path);
-	
-	/* There might be an already open TextEditor with this path */
-	uri = gnome_vfs_get_uri_from_local_path (real_path);
-	doc = ianjuta_document_manager_find_document_with_uri (sr->docman,
-														 uri, NULL);
-
-	if (doc && IANJUTA_IS_EDITOR (doc))
-	{
-		te = IANJUTA_EDITOR (doc);
-		g_free(real_path);
-		return file_buffer_new_from_te(te);
+	GnomeVFSURI *vfs_uri;
+	GnomeVFSHandle *vfs_read;
+	GnomeVFSResult result;
+	GnomeVFSFileInfo info;
+	GnomeVFSFileSize nchars;
+	gchar *buffer;
+	gchar *converted;
+	gchar *encoding;
+
+	g_return_val_if_fail (uri, NULL);
+
+	vfs_uri = gnome_vfs_uri_new (uri);
+
+	if (gnome_vfs_uri_is_local (vfs_uri))
+	{
+		result = gnome_vfs_get_file_info_uri (vfs_uri, &info, GNOME_VFS_FILE_INFO_DEFAULT);
+		if (result != GNOME_VFS_OK)
+		{
+			//FIXME warn user
+			gnome_vfs_uri_unref (vfs_uri);
+//			perror (path);
+			return NULL;
+		}
+
+		result = gnome_vfs_open_uri (&vfs_read, vfs_uri, GNOME_VFS_OPEN_READ);
+		if (result != GNOME_VFS_OK)
+		{
+			//FIXME warn user
+			gnome_vfs_uri_unref (vfs_uri);
+//			perror (path);
+			return NULL;
+		}
+
+		buffer = g_try_malloc (info.size + 1);
+		if (buffer == NULL && info.size != 0)
+		{
+			/* DEBUG_PRINT ("This file is too big. Unable to allocate memory."); */
+			gnome_vfs_close (vfs_read);
+			gnome_vfs_uri_unref (vfs_uri);
+//			perror (path);
+			return NULL;
+		}
+
+		result = gnome_vfs_read (vfs_read, buffer, info.size, &nchars);
+		if (result != GNOME_VFS_OK && !(result == GNOME_VFS_ERROR_EOF && info.size == 0))
+		{
+			//FIXME warn user
+			g_free (buffer);
+			gnome_vfs_close (vfs_read);
+			gnome_vfs_uri_unref (vfs_uri);
+//			perror (path);
+			return NULL;
+		}
+
+		gnome_vfs_close (vfs_read);
+		gnome_vfs_uri_unref (vfs_uri);
+
+		*(buffer + info.size) = '\0';
 	}
-	fb = g_new0(FileBuffer, 1);
+	else /* not a local uri*/
+	{
+	/* FIXME do async read, with gtk_main() until the completion callback */
+		g_return_val_if_reached (NULL);
+/*
+		GnomeVFSAsyncHandle *handle;
+
+		gnome_vfs_async_open_uri (&handle,
+								  vfs_uri,
+								  GNOME_VFS_OPEN_READ,
+								  GNOME_VFS_PRIORITY_MAX,
+								  (GnomeVFSAsyncOpenCallback) async_open_callback,
+								  fb);
+		gtk_main ();
+*/
+	}
+
+	if (info.size > 0)
+	{
+		GError *error;
+		/*  FIXME need to tell scintilla about EOL type
+			convert_to_utf8 (te->props_base, fb->buf, info.size, &te->encoding);
+		*/
+		error = NULL;
+		/* needs 0-terminated buffer */
+		converted = buffer; /*anjuta_convert_to_utf8 (buffer,
+											(gsize) info.size,
+											&encoding,
+											NULL,
+											&error);*/
+		if (error != NULL)
+		{
+			gchar *msg;
+			msg = g_strdup_printf (_("UTF-8 conversion failed for %s: %s"),
+									uri, error->message);
+			perror (msg);
+			g_free (msg);
+			g_error_free (error);
+			g_free (buffer);
+			if (converted != NULL)
+				g_free (converted);
+			return NULL;
+		}
+
+		if (converted != buffer)
+			g_free (buffer);
+	}
+	else	/* empty file */
+	{
+		converted = buffer;
+		encoding = NULL;	//no way to determine what this really is
+	}
+
+	fb = g_slice_new0 (FileBuffer);
 	fb->type = FB_FILE;
-	fb->path = real_path;
-	fb->uri = uri;
-	fb->name = strrchr(path, '/');
+	fb->buf = converted;
+	fb->encoding = encoding;
+	//CHECKME any escaping or other cleanup ?
+	fb->uri = gnome_vfs_make_uri_canonical (uri);
+/*	CHECKME is fb->name used anywhere? does it need to be utf-8 ?
+	fb->name = strrchr (fb->uri, '/');
 	if (fb->name)
 		++ fb->name;
 	else
-		fb->name = fb->path;
-	if (buf && len > 0)
+		fb->name = ?;
+*/
+	/* fb->len (char-length) is set upstream, after the line-ends are located */
+	fb->start_pos = 0;
+	fb->line = 0;	/* signal we want to find the current cursor position whne doing line-ends */
+#ifdef MANAGE_EOL
+	fb->separator_type = EOL_UNKNOWN;	/* log the EOL-type when finding lines */
+#endif
+	file_buffer_find_lines (fb, NULL);	/* get all line-ends data for buffer */
+	fb->len = file_buffer_get_char_offset (fb, -1);	/* character-length */
+
+	return fb;
+}
+
+/**
+ * file_buffer_free:
+ * @fb:
+ *
+ * Clear all data for @fb
+ *
+ * Return value: None
+ */
+void
+file_buffer_free (FileBuffer *fb)
+{
+	if (fb)
 	{
-		fb->buf = g_new(char, len + 1);
-		memcpy(fb->buf, buf, len);
-		fb->buf[len] = '\0';
-		fb->len = len;
+		if (fb->uri)
+			g_free (fb->uri);
+		if (fb->encoding)
+			g_free (fb->encoding);
+		if (fb->buf)
+			g_free (fb->buf);
+		/* the editor fb->te is removed from docman elsewhere, if it's not wanted */
+		if (fb->lines)
+		{
+			GList *node;
+			for (node = fb->lines; node != NULL; node = g_list_next (node))
+				g_slice_free1 (sizeof (EOLdata), node->data);
+			g_list_free (fb->lines);
+		}
+		g_slice_free1 (sizeof (FileBuffer), fb);
 	}
-	else
+}
+
+/* *
+ * file_buffer_set_byte_length:
+ * @fb: pointer to file-buffer data for file being processed
+ * @bytelength: length of file buffer
+ *
+ * Return value: None
+ */
+/*static void
+file_buffer_set_byte_length (FileBuffer *fb, position_t bytelength)
+{
+	GList *node;
+
+	node = g_list_last (fb->lines);
+	((EOLdata *)node->data)->offb = bytelength;
+}
+*/
+/**
+ * file_buffer_get_byte_offset:
+ * @fb: pointer to file-buffer data for file being processed
+ * @charoffset: offset into file buffer
+ *
+ * Get byte-offset corresonding to @charoffset in file associated with @fb
+ * This can handle fb->len offset which is past EOF
+ *
+ * Return value: The offset, or -1 after error
+ */
+position_t
+file_buffer_get_byte_offset (FileBuffer *fb, position_t charoffset)
+{
+	GList *node;
+
+	g_return_val_if_fail (fb->lines, -1);
+
+	if (charoffset > 0)
+	{
+		/* skip 1st entry with all-0 data */
+		for (node = g_list_next (fb->lines); node != NULL; node = g_list_next (node))
+		{
+			EOLdata *ed;
+
+			ed = (EOLdata *)node->data;
+			if (charoffset < ed->offc)
+			{
+				gchar *tmp;
+				position_t priorb, priorc;
+
+				node = g_list_previous (node);
+				priorb = ((EOLdata *)node->data)->offb;
+				priorc = ((EOLdata *)node->data)->offc;
+				tmp = g_utf8_offset_to_pointer (fb->buf + priorb,
+												charoffset - priorc);
+				return (tmp - fb->buf);
+			}
+			else if (charoffset == ed->offc)
+				return ((EOLdata *)node->data)->offb;
+		}
+		return -1;
+	}
+	else if (charoffset == 0)
+		return 0;
+	else /* charoffset < 0 */
 	{
-		struct stat s;
+		node = g_list_last (fb->lines);
+		return (((EOLdata *)node->data)->offb);
+	}
+}
+
+/**
+ * file_buffer_get_char_offset:
+ * @fb: pointer to file-buffer data for file being processed
+ * @byteoffset: offset into file buffer
+ *
+ * Get character-offset corresonding to @byteoffset in file associated with @fb
+ * This can handle offset == strlen(file) which is past EOF, or offset == -1
+ *
+ * Return value: the offset
+ */
+position_t
+file_buffer_get_char_offset (FileBuffer *fb, position_t byteoffset)
+{
+	GList *node;
+
+	g_return_val_if_fail (fb->lines, -1);
 
-		if ((0 == stat(fb->path, &s)) && (S_ISREG(s.st_mode)))
+	if (byteoffset > 0)
+	{
+		/* skip 1st entry with all-0 data */
+		for (node = g_list_next (fb->lines); node != NULL; node = g_list_next (node))
 		{
-			if ((fb->len = s.st_size) < 0) return NULL;
-			fb->buf = g_new(char, s.st_size + 1);
+			EOLdata *ed;
+
+			ed = (EOLdata *)node->data;
+			if (byteoffset < ed->offb)
 			{
-				int total_bytes = 0, bytes_read, fd;
-				if (0 > (fd = open(fb->path, O_RDONLY)))
-				{
-					perror(fb->path);
-					file_buffer_free(fb);
-					return NULL;
-				}
-				while (total_bytes < s.st_size)
+				position_t indx, priorb;
+
+				node = g_list_previous (node);
+				priorb = ((EOLdata *)node->data)->offb;
+				indx = (position_t) g_utf8_pointer_to_offset (fb->buf + priorb, fb->buf + byteoffset);
+				return (((EOLdata *)node->data)->offc + indx);
+			}
+			else if (byteoffset == ed->offb)
+				return ((EOLdata *)node->data)->offc;
+		}
+		return -1;
+	}
+	else if (byteoffset == 0)
+		return 0;
+	else /* byteoffset < 0 */
+	{
+		node = g_list_last (fb->lines);
+		return (((EOLdata *)node->data)->offc);
+	}
+}
+
+/**
+ * file_buffer_get_char_offset_pair:
+ * @fb: pointer to file-buffer data for file being processed
+ * @byteoffset1: pointer to store for offset into file buffer
+ * @byteoffset2: pointer to store for offset into file buffer, or NULL
+ *
+ * Get character-offsets corresonding to @byteoffset1 and @byteoffset2 in file
+ * associated with @fb
+ * This is a bit faster than finding 2 values separately
+ *
+ * Return value: None
+ */
+static void
+file_buffer_get_char_offset_pair (FileBuffer *fb,
+								 position_t *byteoffset1,
+								 position_t *byteoffset2)
+{
+	position_t real_start, real_end;
+	GList *node;
+
+	g_return_if_fail (byteoffset1 && byteoffset2);
+
+	if (byteoffset2 == NULL)
+	{
+		real_start = *byteoffset1;
+		*byteoffset1 = file_buffer_get_char_offset (fb, real_start);
+		return;
+	}
+	else if (byteoffset1 == NULL)
+	{
+		real_end = *byteoffset2;
+		*byteoffset2 = file_buffer_get_char_offset (fb, real_end);
+		return;
+	}
+	else if (*byteoffset2 > *byteoffset1)
+	{
+		if (*byteoffset1 != -1)
+		{
+			real_start = *byteoffset1;
+			real_end = *byteoffset2;
+		}
+		else
+		{
+			real_start = *byteoffset2;
+			real_end = *byteoffset1;
+		}
+	}
+	else if (*byteoffset2 < *byteoffset1)
+	{
+		if (*byteoffset2 != -1)
+		{
+			real_start = *byteoffset2;
+			real_end = *byteoffset1;
+		}
+		else
+		{
+			real_start = *byteoffset1;
+			real_end = *byteoffset2;
+		}
+	}
+	else /* *byteoffset2 == *byteoffset1 */
+	{
+		real_start = *byteoffset1;
+		*byteoffset1 = file_buffer_get_char_offset (fb, real_start);
+		*byteoffset2 = *byteoffset1;
+		return;
+	}
+
+	/* skip 1st entry with all-0 data */
+	for (node = g_list_next (fb->lines); node != NULL; node = g_list_next (node))
+	{
+		EOLdata *ed;
+
+		ed = (EOLdata *)node->data;
+		if (real_start <= ed->offb)
+		{
+			position_t indx, priorb;
+
+			if (real_start < ed->offb)
+			{
+				node = g_list_previous (node);
+				priorb = ((EOLdata *)node->data)->offb;
+				indx = (position_t) g_utf8_pointer_to_offset (fb->buf + priorb, fb->buf + real_start);
+				real_start = (((EOLdata *)node->data)->offc + indx); /* remember the start */
+			}
+			else
+				real_start = ((EOLdata *)node->data)->offc;
+
+			for (node = g_list_next (node); node != NULL; node = g_list_next (node))
+			{
+				ed = (EOLdata *)node->data;
+				if (real_end <= ed->offb)
 				{
-					if (0 > (bytes_read = read(fd, fb->buf + total_bytes
-					  , s.st_size - total_bytes)))
+					if (real_end < ed->offb)
 					{
-						perror(fb->path);
-						close(fd);
-						file_buffer_free(fb);
-						return NULL;
+						node = g_list_previous (node);
+						priorb = ((EOLdata *)node->data)->offb;
+						indx = (position_t) g_utf8_pointer_to_offset (fb->buf + priorb, fb->buf + real_end);
+						real_end = (((EOLdata *)node->data)->offc + indx); /* remember the end */
 					}
-					total_bytes += bytes_read;
+					else
+						real_end = ((EOLdata *)node->data)->offc;
+					break;
 				}
-				close(fd);
-				fb->buf[fb->len] = '\0';
 			}
+			if (node == NULL)
+			{
+				real_end = -1;
+				node = fb->lines;	/* prevent further assignment */
+			}
+			break;
 		}
 	}
-	if (pos <= 0 || pos > fb->len)
+	if (node == NULL)
+		real_start = -1;
+
+	if (*byteoffset1 < *byteoffset2)
 	{
-		fb->pos = 0;
-		fb->line = 0;
+		*byteoffset1 = real_start;
+		*byteoffset2 = real_end;
 	}
 	else
 	{
-		fb->pos = pos;
-		fb->line = 0;
+		*byteoffset2 = real_start;
+		*byteoffset1 = real_end;
+	}
+}
+
+/**
+ * file_buffer_find_lines:
+ * @fb: pointer to file-buffer data for file being processed
+ * @startpos: pointer to first list-member to be updated, or NULL for whole list
+ *
+ * Populate list of line-end offsets for whole or part of file associated with @fb
+ * NOTE ATM also sets fb->line value if fb->line == 0 upon arrival here
+ * The list length is one bigger than the no. of lines in the file.
+ * The first member of the list represents the start of the file (positions {0,0}),
+ * so that each other member's index represents the corresonding 1-based line no.
+ * Except that the last member represents the end of the file, with byte- and
+ * char-lengths of the file.
+ * This also records the "majority" EOL format in the buffer
+ *
+ * Return value: None
+ */
+static void
+file_buffer_find_lines (FileBuffer *fb, GList *startpos)
+{
+	position_t indx, current, priorb, priorc;
+	line_t lineno;
+	EOLdata *ed;
+	gchar *buf, *this;
+	GList *node;
+#ifdef MANAGE_EOL
+	guint cr, lf, crlf, unicr;
+#endif
+
+	g_return_if_fail (fb->buf);
+
+	if (fb->lines != NULL && startpos == NULL)
+	{
+doall:
+		for (node = fb->lines; node != NULL; node = g_list_next (node))
+			g_slice_free1 (sizeof (EOLdata), node->data);
+		g_list_free (fb->lines);
+		fb->lines = NULL;
 	}
-	/* First line starts at column 0 */
-	fb->lines = g_list_prepend(fb->lines, GINT_TO_POINTER(0));
-	lineno = 0;
-	for (i=0; i < fb->len; ++i)
+
+	if (fb->lines == NULL || fb->lines == startpos || startpos == NULL)
 	{
-		if ('\n' == fb->buf[i] && '\0' != fb->buf[i+1])
+		/* (re-)processing whole file buffer */
+		/* First line data corresponds to start of buffer */
+		ed = g_slice_new0 (EOLdata);
+		fb->lines = g_list_prepend (fb->lines, ed);
+		priorb = priorc = 0;
+		lineno = 1;
+	}
+	else if ((lineno = g_list_position (fb->lines, startpos)) != -1)
+	{
+		/* update trailing part of list */
+		if (lineno == 0)
+			goto doall;
+		for (node = startpos; node != NULL; node = g_list_next (node))
 		{
-			fb->lines = g_list_prepend(fb->lines, GINT_TO_POINTER(i + 1));
-			if (0 == fb->line && fb->pos > i)
-				fb->line = lineno;
-			++ lineno;
+			g_slice_free1 (sizeof (EOLdata), node->data);
+			node->data = NULL;
 		}
+//		fb->lines = g_list_remove_all (fb->lines, NULL);
+		g_list_previous (startpos)->next = NULL;
+		g_list_free (startpos);
+		fb->lines = g_list_reverse (fb->lines);
+		node = g_list_first (fb->lines);
+		priorb = ((EOLdata*)node->data)->offb;
+		priorc = ((EOLdata*)node->data)->offc;
+		lineno++;	/* adjust for 1st member of list */
 	}
-	fb->lines = g_list_reverse(fb->lines);
-	return fb;
+	else
+	{
+		//FIXME UI warning
+		//g_return_if_reached ();
+		g_warning ("Error in line-cacheing for %s", fb->uri);
+		return;
+	}
+
+#ifdef MANAGE_EOL
+	cr = lf = crlf = unicr = 0;
+#endif
+	buf = fb->buf;	/* for faster lookup */
+	current = (fb->line == 0) ?
+		(position_t) g_utf8_pointer_to_offset (buf, buf + fb->start_pos):	/* can't yet work from lines data */
+		0;	/* 0 for warning prevention */
+
+	for (indx = priorb, this = buf + priorb; ; indx++, this++)
+	{
+		guchar c;
+
+		c = *this;
+		//CHECKME assumes when EOL == \r\n, can simply ignore the \n
+		//CHECKME can any utf-8 char include \r or \n byte(s) ?
+		if (c == '\n' || c == '\r' || c == 0xb6 || c == 0)
+		{
+			ed = g_slice_new (EOLdata);
+			ed->offb = indx;
+
+			ed->offc = priorc + g_utf8_strlen (buf + priorb, indx - priorb);
+			priorb = indx;
+			priorc = ed->offc;
+
+			if (fb->line == 0 && current > indx)
+				fb->line = lineno;	/* current position is in this line */
+			fb->lines = g_list_prepend (fb->lines, ed);
+			if (c != 0)
+			{
+#ifdef MANAGE_EOL
+				switch (c)
+				{
+					case '\n':
+						lf++;
+						break;
+					case '\r':
+						if (*(this+1) != '\n')
+							cr++;
+						else
+						{
+							crlf++;
+							indx++;
+							this++;
+							ed->offb++;
+							ed->offc++;
+						}
+						break;
+					case 0xb6:
+						unicr++;
+					default:
+						break;
+				}
+#endif
+				lineno++;
+			}
+			else
+				break;
+		}
+	}
+
+	fb->lines = g_list_reverse (fb->lines);
+
+#ifdef MANAGE_EOL
+	if (fb->separator_type == EOL_UNKNOWN)
+	{
+		gboolean conform;
+		guint maxmode;
+
+		/* vote for the EOL-type */
+		maxmode = lf;
+		conform = FALSE;
+		if (cr > maxmode)
+		{
+			maxmode = cr;
+			conform = (lf > 0 || crlf > 0 || unicr > 0);
+		}
+		if (crlf > maxmode)
+		{
+			maxmode = crlf;
+			conform = (cr > 0 || lf > 0 || unicr > 0);
+		}
+		if (unicr > maxmode)
+		{
+			maxmode = unicr;
+			conform = (cr > 0 || lf > 0 || crlf > 0);
+		}
+
+		if (maxmode == lf)
+			fb->separator_type = EOL_LF;
+		else if (maxmode == crlf)
+			fb->separator_type = EOL_CRLF;
+		else if (maxmode == cr)
+			fb->separator_type = EOL_CR;
+		else /* max_mode == unicr */
+			fb->separator_type = EOL_UNI;
+		if (conform)
+		{
+			DEBUG_PRINT ("need to conform line-separators for %s",
+				(fb->uri == NULL) ? "<open file>" : fb->uri);
+/* FIXME	if (maxmode == crlf)
+				(cr + lf + unicr) expansion needed
+			else if (crlf > 0)
+				 crlf contraction needed
+			walk list and convert each bad separator, slide the trailing text and update list data if 1<>2 bytes
+*/
+		}
+	}
+#endif
 }
 
-static long
-file_buffer_line_from_pos(FileBuffer *fb, int pos)
+/**
+ * file_buffer_freshen_lines:
+ * @fb: pointer to file-buffer data for file being processed
+ * @startpos: pointer to first list-member to be updated, or NULL for whole list
+ *
+ * Repopulate list of line-end offsets for whole or part of file associated with @fb
+ *
+ * Return value: None
+ */
+static void
+file_buffer_freshen_lines (FileBuffer *fb, GList *startpos)
 {
-	GList *tmp;
-	int lineno = -1;
-	g_return_val_if_fail(fb && pos >= 0, 1);
-	if (FB_FILE == fb->type)
+	g_return_if_fail (fb->buf);
+
+	if (fb->lines == NULL || fb->lines == startpos || startpos == NULL) /* should never happen */
 	{
-		for (tmp = fb->lines; tmp; tmp = g_list_next(tmp))
+		file_buffer_find_lines (fb, NULL);
+		return;
+	}
+	else if (g_list_position (fb->lines, startpos) != -1)
+	{
+		position_t indx, priorb, priorc, /*nextb, nextc,*/ deltab, deltac, total;
+		EOLdata *ed;
+		gchar *buf, *this;
+		GList *node;
+
+		node = g_list_previous (startpos);
+		if (node == NULL)	/* ignore 1st member */
+			node = startpos;
+		priorb = ((EOLdata*)node->data)->offb;
+		priorc = ((EOLdata*)node->data)->offc;
+
+		buf = fb->buf;	/* for faster lookup */
+		for (indx = priorb, this = buf + priorb; ; indx++, this++)
 		{
-			if (pos < GPOINTER_TO_INT(tmp->data))
-				return lineno;
-			++ lineno;
+			gchar c;
+
+			c = *this;
+			//CHECKME assumes when EOL == \r\n, can simply ignore the \n
+			//CHECKME can any utf-8 char include \r or \n byte(s) ?
+			if (c == '\n' || c == '\r' || c == '\0')
+				break;
+		}
+		node = g_list_next (node);	/* must always be at least 1 more member */
+//		nextb = ((EOLdata*)node->data)->offb;
+//		nextc = ((EOLdata*)node->data)->offc;
+		deltab = indx - ((EOLdata*)node->data)->offb;
+		deltac = priorc + g_utf8_strlen (buf + priorb, indx - priorb)
+					- ((EOLdata*)node->data)->offc;
+		total = strlen (buf);
+
+		for (; node != NULL; node = g_list_next (node))
+		{
+			ed = (EOLdata*)node->data;
+			ed->offb += deltab;
+			ed->offc += deltac;
+
+			if (ed->offb > total)	/* fewer lines now */
+			{
+				for (; node != NULL; node = g_list_next (node))
+				{
+					g_slice_free1 (sizeof (EOLdata), node->data);
+					node->data = NULL;
+				}
+				fb->lines = g_list_remove_all (fb->lines, NULL);
+//				node = NULL;
+				break;
+			}
+		}
+		if (ed->offb < total)	/* more lines now */
+		{
+			/* append the rest */
+			file_buffer_find_lines (fb, g_list_last (fb->lines));
 		}
-		return lineno;
 	}
-	else if (FB_EDITOR == fb->type)
+	else
 	{
-		IAnjutaIterable *position;
-		position = ianjuta_editor_get_position_from_offset (fb->te, pos, NULL);
-		lineno = ianjuta_editor_get_line_from_position (fb->te, position, NULL);
-		g_object_unref (position);
-		return lineno;
+		//FIXME UI warning
+		g_warning ("Error in line-cache refresh for %s", fb->uri);
+		return;
+	}
+}
+
+/**
+ * file_buffer_freshen_lines_from_pos:
+ * @fb: pointer to file-buffer data for file being processed
+ * @offset: position in file buffer
+ * @offset_bytes: TRUE if @offset is bytes, FALSE if chars
+ *
+ * Repopulate list of line-end offsets for whole or part of file associated with @fb
+ *
+ * Return value: None
+ */
+void
+file_buffer_freshen_lines_from_pos (FileBuffer *fb, position_t offset, gboolean offset_bytes)
+{
+	GList *node;
+
+	g_return_if_fail (fb->lines);
+	/* 1st member of list is effectively before start of file */
+	if (offset_bytes)
+	{
+		for (node = g_list_next (fb->lines); node != NULL; node = g_list_next (node))
+		{
+			if (offset <= ((EOLdata *)node->data)->offb)
+			{
+				file_buffer_freshen_lines (fb, node);
+				return;
+			}
+		}
 	}
 	else
-		return -1;
+	{
+		for (node = g_list_next (fb->lines); node != NULL; node = g_list_next (node))
+		{
+			if (offset <= ((EOLdata *)node->data)->offc)
+			{
+				file_buffer_freshen_lines (fb, node);
+				return;
+			}
+		}
+	}
+	//FIXME UI warning
+	g_warning ("Error in line-cache refresh for %s", fb->uri);
+}
+/* unused ATM
+static position_t
+file_buffer_byte_len (FileBuffer *fb)
+{
+	if (fb->buf == NULL || *fb->buf == '\0')
+		return 0;
+	if (fb->lines != NULL)
+	{
+		GList *last;
+		last = g_list_last (fb->lines);
+		return ((EOLdata *)last->data)->offb;
+	}
+	else
+		return strlen (fb->buf);
+}
+*/
+
+/* *
+ * file_buffer_char_len:
+ * @fb: pointer to file-buffer data for file being processed
+ *
+ * Determine character-size of file buffer associated with @fb
+ *
+ * Return value: the length
+ */
+/* unused ATM
+static position_t
+file_buffer_char_len (FileBuffer *fb)
+{
+	if (fb->buf == NULL || *fb->buf == '\0')
+		return 0;
+	if (fb->lines)
+	{
+		GList *last;
+		last = g_list_last (fb->lines);
+		return ((EOLdata *)last->data)->offc;
+	}
+	else
+		return g_utf8_strlen (fb->buf, -1);
 }
+*/
+/**
+ * file_buffer_line_for_pos:
+ * @fb: pointer to file-buffer data for file being processed
+ * @pos: buffer position, in chars
+ * @pos_bytes: TRUE if @pos is byte-position, FALSE if char-position
+ *
+ * Find the line number of the text at @pos in file buffer associated with @fb
+ *
+ * Return value: the 1-based line-number for @pos, or -1
+ */
+static line_t
+file_buffer_line_for_pos (FileBuffer *fb, position_t pos, gboolean pos_bytes)
+{
+	g_return_val_if_fail (fb && pos >= 0, -1);
 
+	line_t lineno;
+	GList *node;
+
+	g_return_val_if_fail (fb->lines, -1);
+	/* 1st member of list is effectively before start of file */
+	if (pos_bytes)
+	{
+		for (node = g_list_next (fb->lines), lineno = 1; node != NULL; node = g_list_next(node), lineno++)
+		{
+			if (pos <= ((EOLdata *)node->data)->offb)
+				return lineno;
+		}
+	}
+	else
+	{
+		for (node = g_list_next (fb->lines), lineno = 1; node != NULL; node = g_list_next(node), lineno++)
+		{
+			if (pos <= ((EOLdata *)node->data)->offc)
+				return lineno;
+		}
+	}
+	return -1;
+}
+
+/* *
+ * file_buffer_get_linetext_for_pos:
+ * @fb: pointer to file-buffer data for file being processed
+ * @pos: buffer position, in chars
+ *
+ * Looks for strings separated by newline chars CHECKME all EOL's ok ?
+ *
+ * Return value: newly-allocated string which spans @pos, or NULL
+ */
+/*
 gchar *
-file_match_line_from_pos(FileBuffer *fb, int pos)
+file_buffer_get_linetext_for_pos (FileBuffer *fb, position_t pos)
+{
+	gchar *buf;
+	position_t indx;
+
+	g_return_val_if_fail (fb && pos >= 0, NULL);
+
+	buf = fb->buf;
+	indx = file_buffer_get_byte_offset (fb, pos);
+	if (indx >= 0)	/ * no error * /
+	{
+		gint length;
+		gchar *this;
+		register gchar c;
+
+		length = 1;
+		/ * use index instead of array cuz it's faster * /
+		/ * simple ascii scanning is ok cuz we want the whole line * /
+		for (this = buf + indx + sizeof (gchar); ; this++, length++)
+		{
+			c = *this;
+			if (c == '\n' || c == '\r' || c == '\0')
+				break;
+		}
+		for (this = buf + indx - sizeof (gchar); ; this--, length++)
+		{
+			if (this < buf)
+				break;
+			c = *this;
+			if (c =='\n' || c =='\r')
+				break;
+		}
+
+		return g_strndup (++this, length);
+	}
+	return NULL;
+}
+*/
+
+/**
+ * file_buffer_get_linetext_for_line:
+ * @fb: pointer to file-buffer data for file being processed
+ * @lineno: buffer line number, 1-based
+ *
+ * Looks for strings separated by newline chars CHECKME all EOL's ok ?
+ *
+ * Return value: newly-allocated string corresonding to line @lineno, or NULL
+ */
+gchar *
+file_buffer_get_linetext_for_line (FileBuffer *fb, line_t lineno)
+{
+	GList *node;
+
+	g_return_val_if_fail (fb && fb->lines, NULL);
+
+	node = g_list_nth (fb->lines, (guint) lineno);
+	if (node != NULL)
+	{
+		gchar *start, *end;
+
+		end = fb->buf + ((EOLdata *)node->data)->offb;
+		node = g_list_previous (node);
+		start = fb->buf + ((EOLdata *)node->data)->offb + 1;
+		while (start < end)
+		{
+			register gchar c;
+			c = *start;
+			if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
+				start++;
+			else
+				break;
+		}
+		return g_strndup (start, end - start);
+	}
+	return NULL;
+}
+
+/**
+ * save_file_buffer:
+ * @fb: pointer to file-buffer data for file being processed
+ *
+ * Save file buffer for @fb, after reverting its encoding if necessary
+ *
+ * Return value: TRUE if any conversion and the save were completed successfully
+ */
+gboolean
+save_file_buffer (FileBuffer *fb)
 {
-	gint length=1;
-	gint i;
-	g_return_val_if_fail(fb && pos >= 0, NULL);
+	position_t bytelength;
+	gsize bytes_new;
+	gchar *converted;
+	gchar *local_path;
+
+	/* revert to original encoding if possible */
+	/*CHECKME according to anj save-option ? revert EOL's too ? */
+	bytelength = file_buffer_get_byte_offset (fb, -1);
+	if (bytelength > 0)
+	{
+		GError *error;
+
+		error = NULL;
+		converted = fb->buf; /*anjuta_convert_from_utf8 (fb->buf,
+											(gsize) bytelength,
+											fb->encoding,
+											&bytes_new,
+											&error);*/
+		if (error != NULL)
+		{
+//			gchar *msg;
+			switch (error->code)
+			{
+				case G_CONVERT_ERROR_ILLEGAL_SEQUENCE:
+/* FIXME warn user
+					msg = g_strdup_printf (
+					_("Cannot save %s in its original encoding %s. Reverting to UTF-8"),
+						fb->uri, (fb->encoding) ? fb->encoding : "UNKNOWN");
+					perror (msg);
+					g_free (msg);
+*/
+					g_warning ("Cannot save %s in its original encoding %s. Reverting to UTF-8",
+								fb->uri, (fb->encoding) ? fb->encoding : "UNKNOWN");
+					g_error_free (error);
+					converted = fb->buf;
+					bytes_new = bytelength;
+					break;
+				default:
+/* FIXME warn user
+					msg = g_strdup_printf (
+					_("Encoding conversion failed for %s"), fb->uri);
+					perror (msg);
+					g_free (msg);
+*/
+					g_warning ("Encoding conversion failed for %s", fb->uri);
+					g_error_free (error);
+					return FALSE;
+			}
+		}
+	}
+	else
+	{
+		converted = fb->buf;
+		bytes_new = 0;
+	}
+
+	/* success */
 
-	for (i= pos+1; ((fb->buf[i] != '\n') && (fb->buf[i] != '\0')); i++, length++);
-	for (i= pos-1; (fb->buf[i] != '\n') && (i >= 0); i--, length++);
-	
-	return g_strndup (fb->buf + i + 1, length);
+	local_path = gnome_vfs_get_local_path_from_uri (fb->uri);
+	if (local_path != NULL)
+	{
+		GnomeVFSHandle* vfs_write;
+		GnomeVFSResult result;
+		GnomeVFSFileSize nchars;
+
+		g_free (local_path);
+
+		result = gnome_vfs_create (&vfs_write, fb->uri, GNOME_VFS_OPEN_WRITE,
+								   FALSE, 0664);	/* CHECKME this mode always ok ? */
+		if (result != GNOME_VFS_OK)
+			return FALSE;
+
+		result = gnome_vfs_write (vfs_write, converted, bytes_new, &nchars);
+
+		if (result == GNOME_VFS_OK)
+			result = gnome_vfs_close (vfs_write);
+		else
+			gnome_vfs_close (vfs_write);
+
+		if (converted != fb->buf)
+			g_free (converted);
+		return (result == GNOME_VFS_OK);
+	}
+	else
+	{
+		g_free (local_path);
+		/* FIXME do async save, with gtk_main() until the completion callback */
+		g_return_val_if_reached (FALSE);
+	}
+	return FALSE;
 }
 
-/* Generate a list of files to search in. Call with start = TRUE and
-** top_dir = sf->top_dir. This is used when the search range is specified as
-SR_FILES */
+/**
+ * replace_in_local_buffer:
+ * @fb: pointer to file-buffer data for file being processed
+ * @matchstart: byte-position of the start of the string to be replaced in the file-buffer
+ * @matchlen: byte-length of the matched string
+ * @repl_str: string to be substituted
+ *
+ * Replace some content of the the buffer associated with @fb
+ *
+ * Return value: TRUE if the update completed successfully
+ */
+gboolean
+replace_in_local_buffer (FileBuffer *fb,
+						 position_t matchstart,
+						 position_t matchlen,
+						 gchar *repl_str)
+{
+	position_t l, replen, buflen;
+	GList *node;
+
+	g_return_val_if_fail (repl_str != NULL, FALSE);
+
+	buflen = file_buffer_get_byte_offset (fb, -1);
+	replen = strlen (repl_str);
+	if (replen > matchlen)
+	{
+		/* new string is longer */
+		l = buflen - matchstart;
+		buflen = buflen + replen - matchlen;
+		if ( (fb->buf = g_try_realloc (fb->buf, buflen)) == NULL )
+			return FALSE;
+		/* make a hole */
+		memmove (fb->buf + matchstart + replen - matchlen, fb->buf + matchstart, l);
+	}
+	else if  (replen < matchlen)
+	{
+		/* new string is shorter */
+		l = buflen - matchstart - matchlen;
+		memmove (fb->buf + matchstart + replen, fb->buf + matchstart + matchlen, l);
+		buflen = buflen + replen - matchlen;
+		if ( (fb->buf = g_try_realloc (fb->buf, buflen)) == NULL)
+			return FALSE;
+	}
+
+	memcpy (fb->buf + matchstart, repl_str, replen);
+	/* update byte length, but don't bother with anything else in the lines-list */
+	node = g_list_last (fb->lines);
+	((EOLdata *)node->data)->offb += (replen - matchlen);
+
+	return TRUE;
+}
+
+/**
+ * get_search_files_list:
+ * @sf:
+ * @stop_uri:
+ *
+ * Generate a list of files to search in. This is used when the search range
+ * is specified as SR_FILES
+ * Call with start = TRUE and top_dir = sf->top_dir.
+ *
+ * Return value: the newly-allocated list of files, or NULL
+ */
 static GList *
-create_search_files_list(SearchFiles *sf, const char *top_dir)
+get_search_files_list (SearchFiles *sf, const gchar *top_uri)
 {
-	TMFileEntry *entry;
-	GList *files;
+	gchar *top_dir;
 
-	g_return_val_if_fail(sf && top_dir, NULL);
-	entry = tm_file_entry_new(top_dir, NULL, sf->recurse, sf->match_files
-	  , sf->ignore_files, sf->match_dirs, sf->ignore_dirs
-	  , sf->ignore_hidden_files, sf->ignore_hidden_dirs);
-	if (!entry)
-		return NULL;
-	files = tm_file_entry_list(entry, NULL);
-	tm_file_entry_free(entry);
-	return files;
+	g_return_val_if_fail (sf && top_uri, NULL);
+
+	top_dir = gnome_vfs_get_local_path_from_uri (top_uri);		//FIXME allow func to use uri
+	if (top_dir != NULL)
+	{
+		TMFileEntry *entry;
+		entry = tm_file_entry_new (top_dir, NULL, sf->recurse, sf->match_files,
+									sf->ignore_files, sf->match_dirs, sf->ignore_dirs,
+	  								sf->ignore_hidden_files, sf->ignore_hidden_dirs);
+		g_free (top_dir);
+		if (entry != NULL)
+		{
+			GList *files;
+			/* CHECKME want list of non-constant uri's */
+			files = tm_file_entry_list (entry, NULL);
+			tm_file_entry_free (entry);
+			return files;
+		}
+	}
+	else
+	{
+		g_warning ("Cannot create local path for requested uri");
+	}
+	return NULL;
 }
 
-/* Get a list of all project files */
+/**
+ * get_project_files_list:
+ * @sr: pointer to populated search/replace data struct
+ *
+ * Get a list of all project files from the project manager plugin
+ *
+ * Return value: the newly-allocated list of files, or NULL
+ */
 static GList *
-get_project_file_list(void)
+get_project_files_list (SearchReplace *sr)
 {
-	GList* list = NULL;
-	GList *files = NULL;
 	gchar *project_root_uri = NULL;
-	
-	anjuta_shell_get (ANJUTA_PLUGIN(sr->docman)->shell,
+
+//	anjuta_shell_get (ANJUTA_PLUGIN (sr->docman)->shell,
+	anjuta_shell_get (ANJUTA_PLUGIN (splugin)->shell,
 					  "project_root_uri", G_TYPE_STRING,
 					  &project_root_uri, NULL);
-	
+
 	if (project_root_uri)
 	{
+		GList *files;
 		IAnjutaProjectManager* prjman;
-		prjman = anjuta_shell_get_interface(ANJUTA_PLUGIN(sr->docman)->shell, 
-											IAnjutaProjectManager , NULL);
-		
-		list = ianjuta_project_manager_get_elements (prjman,
+
+//		prjman = anjuta_shell_get_interface (ANJUTA_PLUGIN (sr->docman)->shell,
+		prjman = anjuta_shell_get_interface (ANJUTA_PLUGIN (splugin)->shell,
+											IAnjutaProjectManager, NULL);
+		/* get a list of non-constant project-file uri's */
+		files = ianjuta_project_manager_get_elements (prjman,
 													 IANJUTA_PROJECT_MANAGER_SOURCE,
 													 NULL);
-		if (list)
-		{
-			const gchar *uri;
-			GList *node;
-			node = list;
-	
-			while (node)
-			{
-				gchar *file_path;
-		
-				uri = (const gchar *)node->data;
-				file_path = gnome_vfs_get_local_path_from_uri (uri);
-				if (file_path)
-				files = g_list_prepend (files, file_path);
-				node = g_list_next (node);
-			}
-			files = g_list_reverse (files);
-			g_list_free(list);
-		}
+		g_free (project_root_uri);
+		return files;
 	}
-	g_free (project_root_uri);
-	return files;
-}
 
+	g_warning ("OOPS, there's no known root-directory for the project");
+	return NULL;
+}
 
+/**
+ * isawordchar:
+ * @c: character to test
+ *
+ * Decide whether @c is a "word" character, not whitespace or punctuation
+ *
+ * Return value: TRUE if @c is letter, number or '_'
+ */
 static gboolean
-isawordchar (int c)
+isawordchar (gunichar c)
 {
-	return (isalnum(c) || '_' == c);
+	return (g_unichar_isalnum (c) || (gchar)c == '_');
 }
 
+/**
+ * extra_match:
+ * @fb: pointer to file-buffer data for file being processed
+ * @se: pointer to search data struct
+ * @start_pos: offset of possible-match start, >= 0, bytes or chars as used by the editor
+ * @end_pos: offset of possible-match end, may be -1 for EOF, bytes or chars as used by the editor
+ *
+ * Determine whether relevant extra search condition(s) (whole word etc) are
+ * satisfied for a non-regex seach operation
+ *
+ * Return value: TRUE if all extra conditiions are satisfied, or there are none
+ */
 static gboolean
-extra_match (FileBuffer *fb, SearchExpression *s, gint match_len)
+extra_match (FileBuffer *fb, SearchExpression *se, position_t start_pos, position_t end_pos)
 {
-	gchar b, e;
-	
-	b = fb->buf[fb->pos-1];
-	e = fb->buf[fb->pos+match_len];
-	
-	if (s->whole_line)
-		if ((fb->pos == 0 || b == '\n' || b == '\r') &&
-			(e == '\0'	|| e == '\n' || e == '\r'))
-			return TRUE;
+	gunichar b, e;
+	gchar *s;
+
+	if (!(se->word_start || se->whole_word || se->whole_line))
+		return TRUE;
+
+	if (start_pos == 0)
+	{
+		s = fb->buf;
+		b = (gunichar)' '; /* warning prevention only */
+	}
+	else
+	{
+/* ATM only local searching uses this, and it works with byte-positions
+		if (se->postype == SP_BYTES)
+		{ */
+			s = g_utf8_find_prev_char (fb->buf, fb->buf + start_pos);
+			if (s == NULL)
+				return FALSE;
+/*		}
 		else
+		{
+			s = fb->buf + file_buffer_get_byte_offset (fb, start_pos - 1);
+		}
+*/
+		b = g_utf8_get_char_validated (s, -1);
+		if (b == (gunichar)-1 || b == (gunichar)-2)
+			//FIXME warning
 			return FALSE;
-	else if (s->whole_word)
-		if ((fb->pos ==0 || !isawordchar(b)) && 
-			(e=='\0' || !isawordchar(e)))
+	}
+
+	if (se->word_start)
+	{
+		if (start_pos == 0 || !isawordchar(b))
 			return TRUE;
 		else
 			return FALSE;
-	else if (s->word_start)
-		if (fb->pos ==0 || !isawordchar(b))
-			return TRUE;
-		else
-			return FALSE;	
+	}
 	else
+	{
+		if (end_pos == -1)
+			e = (gunichar)'\n';	/* warning prevention only */
+		else
+		{
+//			if (se->postype == SP_BYTES)
+				s = fb->buf + end_pos + 1;
+//			else
+//				s = g_utf8_next_char (fb->buf + end_pos);
+			if (*s == '\0')
+				e = (gunichar) '\0';
+			else
+			{
+				e = g_utf8_get_char_validated (s, -1);
+				if (e == (gunichar)-1 || b == (gunichar)-2)
+					//FIXME warning
+					return FALSE;
+			}
+		}
+
+		if (se->whole_word)
+		{
+			if ((start_pos == 0 || !isawordchar(b))
+			 && (end_pos == -1 || e == (gunichar)'\0' || !isawordchar (e)))
+				return TRUE;
+			else
+				return FALSE;
+		}
+		else /*se->whole_line*/
+		{
+			if ((start_pos == 0 || b == (gunichar)'\n' || b == (gunichar)'\r')
+			 && (end_pos == -1 || e == (gunichar)'\0' || e == (gunichar)'\n' || e == (gunichar)'\r'))
+				return TRUE;
+			else
+				return FALSE;
+		}
+	}
+}
+
+/**
+ * search_locally:
+ * @se: search data struct
+ * @direction: enumerator of search-direction
+ * @hlen byte-length of target "haystack"
+ *
+ * Decide whether a local copy of file text is needed for searching
+ * As this test includes a review of advanced-search skip-table, that table is
+ * initialised if it wasn't already
+ *
+ * Return value: TRUE if a local buffer is needed
+ */
+/* UNUSED ATM
+static gboolean
+search_locally (SearchExpression *se, SearchDirection direction, position_t hlen)
+{
+	if (se->regex)
 		return TRUE;
+	/ * FIXME case insensitive searching needed too * /
+	if ( hlen < ADV_SRCH_MIN_LENGTH2
+	  || strlen (se->search_str) < ADV_SRCH_MIN_LENGTH	/ * short patterns use simple search * /
+//	  || direction == SD_BACKWARD
+	  || se->ignore_case	/ * native searching for any case is easier * /
+	  //etc ?
+		)
+		return FALSE;
+
+	if (se->skiptable == NULL)
+	{
+		/ * populate and check skip-table at se->skiptable * /
+		se->advanced = search_table_new (se, direction);
+		if (!se->advanced)
+		/ * freeable pointer to prevent repeated useless attempts to create table * /
+			se->skiptable = g_malloc (1);
+	}
+	return se->advanced;
 }
+*/
+
+/**
+ * get_next_match:
+ * @fb: pointer to file-buffer data for file being processed
+ * @direction: enumerator of search-direction
+ * @se: search data struct
+ * @mi: pointer to place to store data for the next match in the buffer related to @fb
+ *
+ * The search expression should be pre-compiled. ??
+ * After a match, fb->start_pos or fb->end_pos is updated to suit
+ * Pre-checking here for validity of start- and end-position, and some tweaking if needed
+ *
+ * Return value: TRUE if a match is found
+ */
+gboolean
+get_next_match (FileBuffer *fb, SearchDirection direction, SearchExpression *se, MatchInfo *mi)
+{
+	gboolean retval;
+
+	g_return_val_if_fail (fb && se && se->search_str, FALSE);
+
+	if (*se->search_str == '\0')
+		return FALSE;
+
+	/* CHECKME these tests are more relevant for forward search ?*/
+	if (fb->start_pos == -1)
+		fb->start_pos = 0;
+	if (fb->end_pos == -1)
+		fb->end_pos = fb->len - 1;
+	else if (fb->end_pos == fb->len)	/* this is another proxy for last position */
+		fb->end_pos--;
+	if (fb->start_pos >= fb->end_pos)
+		return FALSE;
+
+	retval = FALSE;
+
+	if (se->regex)
+	{
+		/* regular expression search */
+		gint options;
+		gint status;
+		position_t ps, pl;
+
+		if (se->re == NULL)
+		{
+			/* the pattern will be compiled with utf-8 support if that's available */
+			se->re = pcre_info_new (se);
+			if (se->re == NULL)
+				return FALSE;
+		}
 
-/* Returns the next match in the passed buffer. The search expression should
-   be pre-compiled. The returned pointer should be freed with match_info_free()
-   when no longer required. */
-MatchInfo *
-get_next_match(FileBuffer *fb, SearchDirection direction, SearchExpression *s)
-{
-	MatchInfo *mi = NULL;
-
-	g_return_val_if_fail(fb && s, NULL);
-	
-	if (s->regex)
-	{
-		/* Regular expression match */
-		int options = PCRE_NOTEMPTY;
-		int status;
-		if (NULL == s->re)
-		{
-			if (NULL == (s->re = pcre_info_new(s)))
-				return NULL;
-		}
-		status = pcre_exec (s->re->re, s->re->extra, fb->buf, fb->len, fb->pos,
-							options, s->re->ovector, 3 * (s->re->ovec_count + 1));
-		if (0 == status)
+		/* pcre takes/gives positions as byte-counts even if utf-8 is suppported */
+		ps = file_buffer_get_byte_offset (fb, fb->start_pos);
+		pl = file_buffer_get_byte_offset (fb, -1);
+
+		options = PCRE_NOTEMPTY;
+		status = pcre_exec (se->re->re, se->re->extra, fb->buf, pl, ps, options,
+							se->re->ovector, 3 * (se->re->ovec_count + 1));
+		if (status == 0)
 		{
 			/* ovector too small - this should never happen ! */
-			g_warning("BUG ! ovector found to be too small");
-			return NULL;
+			g_warning ("BUG ! ovector found to be too small");
+			return FALSE;
 		}
-		else if (0 > status && status != PCRE_ERROR_NOMATCH)
+		else if (status < 0 && status != PCRE_ERROR_NOMATCH)
 		{
 			/* match error - again, this should never happen */
-			g_warning("PCRE Match error");
-			return NULL;
+			g_warning ("PCRE Match error");
+			return FALSE;
 		}
-		else if (PCRE_ERROR_NOMATCH != status)
+		else if (status != PCRE_ERROR_NOMATCH)
 		{
-			mi = g_new0(MatchInfo, 1);
-			mi->pos = s->re->ovector[0];
-			mi->len = s->re->ovector[1] - s->re->ovector[0];
-			mi->line = file_buffer_line_from_pos(fb, mi->pos);
-			if (status > 1) /* Captured subexpressions */
+			position_t ms, mf;
+
+			retval = TRUE;
+			ms = (position_t) se->re->ovector[0];	/* pcre uses gint */
+			/* mf will be one-past last matched position */
+			mf = (position_t) se->re->ovector[1];
+			if (se->postype == SP_BYTES)
+			{
+				mi->pos = ms;
+				mi->len = mf - ms;
+			}
+			file_buffer_get_char_offset_pair (fb, &ms, &mf);
+			/* start-position for next time after end of this match, may be past EOF */
+			fb->start_pos =	mf;
+			mi->line = file_buffer_line_for_pos (fb, ms, FALSE);
+			if (se->postype == SP_CHARS)	/* want char-positions */
+			{
+				mi->pos = ms;
+				mi->len = mf - ms;
+			}
+			DEBUG_PRINT ("Match found at position %d (%s)", mi->pos,
+							(se->postype == SP_BYTES) ? "bytes":"chars");
+			if (status > 1) /* captured sub-expressions */
 			{
-				int i;
-				MatchSubStr *ms;
-				for (i=1; i < status; ++i)
+				gint i;
+				for (i = 1; i < status; i++)
 				{
-					ms = g_new0(MatchSubStr, 1);
-					ms->start = s->re->ovector[i * 2];
-					ms->len = s->re->ovector[i * 2 + 1] - ms->start;
-					mi->subs = g_list_prepend(mi->subs, ms);
+					MatchSubStr *mst;
+
+					mst = g_slice_new (MatchSubStr);
+					ms = (position_t) se->re->ovector[i * 2];
+					mf = (position_t) se->re->ovector[i * 2 + 1];	/* after end of match */
+					/* cuz backref replacements are done in local buffer,
+					   always want byte-positions as reported by pcre */
+					mst->start = ms;
+					mst->len = mf - ms;
+					mi->subs = g_list_prepend (mi->subs, mst);
 				}
-				mi->subs = g_list_reverse(mi->subs);
+				if (mi->subs != NULL)	/* should never fail */
+					mi->subs = g_list_reverse (mi->subs);
 			}
-			fb->pos = s->re->ovector[1];
-		}
-	}
+		} /* match found */
+	} /* regex-search */
 	else
 	{
-		/* Simple string search - this needs to be performance-tuned */
+		/* naive brute-force string scan
+		   more "advanced" algorithms have been investigated and found to be of
+		   no practical net benefit in this context */
+		gchar *needle, *haystack, *sc, *sf;
+		gunichar uc;
+		gchar c;
 		gboolean found;
-		gchar lc;
 		gint match_len;
+		position_t ps, pf;
 
-		match_len = strlen (s->search_str);
-		if (match_len == 0)
-			return NULL;
+		ps = file_buffer_get_byte_offset (fb, fb->start_pos);
+		pf = file_buffer_get_byte_offset (fb, fb->end_pos);
+
+		if (se->ignore_case)
+		{
+			needle = g_utf8_casefold (se->search_str, -1);
+			uc = g_utf8_get_char (se->search_str);
+			uc = g_unichar_tolower (uc);
+			c = (gchar) uc;
+		}
+		else
+		{
+			needle = se->search_str;
+			c = *needle;
+		}
+		match_len = strlen (se->search_str);
 
 		found = FALSE;
-		if (SD_BACKWARD == direction)
+		if (direction == SD_BACKWARD)
 		{
-			/* Backward matching. */
-			if (s->ignore_case)
+			/* backward scan */
+			sf = fb->buf + ps;
+			if (se->ignore_case)
 			{
-				/* FIXME support encodings with > 1 byte per char */
-				lc = tolower (s->search_str[0]);
-				for (; fb->pos != -1; --fb->pos)
+				sc = fb->buf + pf - match_len + 1;
+				uc = g_utf8_get_char_validated (sc, 1);
+				if (uc == (gunichar)-1 || uc == (gunichar)-2)
+					sc = g_utf8_find_prev_char (fb->buf, sc);
+				for ( ; sc >= sf; sc = g_utf8_prev_char (sc))
 				{
-					if (lc == tolower(fb->buf[fb->pos]))
+					uc = g_utf8_get_char (sc);
+					uc = g_unichar_tolower (uc);
+					if ((gchar)uc == c)
 					{
-						if (0 == g_strncasecmp(s->search_str, fb->buf + fb->pos,
-						    match_len) && extra_match (fb, s, match_len))
+						/* FIXME make this less repetitive while still knowing match position */
+						haystack = g_utf8_casefold (sc, match_len);
+						found = (strcmp (haystack, needle) == 0);
+						g_free (haystack);
+						if (found &&
+							extra_match (fb, se, sc - fb->buf, sc - fb->buf + match_len - 1))
 						{
-							found = TRUE;
+							//ps = sc - fb->buf;
+							//pf = ps + match_len - 1;
 							break;
 						}
+						else
+							found = FALSE;
 					}
 				}
 			}
-			else
+			else /* case-specific */
 			{
-				for (; fb->pos != -1; --fb->pos)
+				for (sc = fb->buf + pf - match_len + 1; sc >= sf; sc--)
 				{
-					if (s->search_str[0] == fb->buf[fb->pos])
+					if (*sc == c)
 					{
-						if (0 == strncmp(s->search_str, fb->buf + fb->pos,
-						  	match_len) && extra_match (fb, s, match_len))
+						if (strncmp (sc, needle, match_len) == 0 &&
+							extra_match (fb, se, sc - fb->buf, sc - fb->buf + match_len - 1))
 						{
 							found = TRUE;
+							//ps = sc - fb->buf;
+							//pf = ps + match_len - 1;
 							break;
 						}
 					}
@@ -540,34 +1809,44 @@
 		}
 		else
 		{
-			/* Forward match */
-			if (s->ignore_case)
+			/* forward scan */
+			sf = fb->buf + pf - match_len + 1;
+			if (se->ignore_case)
 			{
-				/* FIXME support encodings with > 1 byte per char */
-				lc = tolower (s->search_str[0]);
-				for (; fb->pos < fb->len; ++fb->pos)
+				for (sc = fb->buf + ps; sc <= sf; sc = g_utf8_next_char (sc))
 				{
-					if (lc == tolower(fb->buf[fb->pos]))
+					uc = g_utf8_get_char (sc);
+					uc = g_unichar_tolower (uc);
+					if ((gchar)uc == c)
 					{
-						if (0 == g_strncasecmp(s->search_str, fb->buf + fb->pos,
-						    match_len) && extra_match (fb, s, match_len))
+						/* FIXME make this less repetitive while still knowing match position */
+						haystack = g_utf8_casefold (sc, match_len);
+						found = (strcmp (haystack, needle) == 0);
+						g_free (haystack);
+						if (found &&
+							extra_match (fb, se, sc - fb->buf, sc - fb->buf + match_len - 1))
 						{
-							found = TRUE;
+							//ps = sc - fb->buf;
+							//pf = ps + match_len - 1;
 							break;
 						}
+						else
+							found = FALSE;
 					}
 				}
 			}
-			else
+			else /* case-specific */
 			{
-				for (; fb->pos < fb->len; ++fb->pos)
+				for (sc = fb->buf + ps; sc <= sf; sc++)
 				{
-					if (s->search_str[0] == fb->buf[fb->pos])
+					if (*sc == c)
 					{
-						if (0 == strncmp(s->search_str, fb->buf + fb->pos,
-						    match_len) && extra_match (fb, s, match_len))
+						if (strncmp (sc, needle, match_len) == 0 &&
+							extra_match (fb, se, sc - fb->buf, sc - fb->buf + match_len - 1))
 						{
 							found = TRUE;
+							//ps = sc - fb->buf;
+							//pf = ps + match_len - 1;
 							break;
 						}
 					}
@@ -576,307 +1855,524 @@
 		}
 		if (found)
 		{
-			mi = g_new0 (MatchInfo, 1);	//better to abort than silently fail to report match ?
-//			mi = g_try_new0 (MatchInfo, 1);
-//			if (mi)
-//			{
-				mi->pos = fb->pos;
-				mi->len = match_len;
-				mi->line = file_buffer_line_from_pos (fb, fb->pos);
-//			}
-//			else
-//				WARN USER ABOUT MEMORY ERROR
+			ps = sc - fb->buf;
+			//pf = ps + match_len - 1;
 			if (direction == SD_BACKWARD)
-				fb->pos -= match_len;
+			{
+				fb->end_pos = (ps > 0) ? file_buffer_get_char_offset (fb, ps - 1) : 0;
+			}
 			else
-				fb->pos += match_len;
+				fb->start_pos = file_buffer_get_char_offset (fb, ps + match_len);
+			mi->pos = (se->postype == SP_BYTES) ?
+				ps : file_buffer_get_char_offset (fb, ps);
+			DEBUG_PRINT ("Match found at position %d (%s)", mi->pos,
+							(se->postype == SP_BYTES) ? "bytes":"chars");
+			/* fixed length (==mf-ms) is set upstream */
+			mi->line = file_buffer_line_for_pos (fb, ps, TRUE);
+			retval = TRUE;
 		}
-	}
-	return mi;
+		if (se->ignore_case)
+		{
+			g_free (needle);
+		}
+	}	/* naive-search */
+
+	return retval;
 }
 
-/* Create list of search entries */
-GList *
-create_search_entries (Search *s)
+/**
+ * create_search_entries:
+ * @sr: pointer to populated search/replace data struct
+ *
+ * Create list of search entries, with a member for each buffer or file to be processed
+ * Open buffers are checked for being searchable before being added to the list
+ * Start and end positions are set, using editor-native offsets if not 0 or -1
+ * End position is -1 when searching forward to the end of buffer
+ * Unless end == -1, start > end regardless of search direction
+ * In general, there is no file-buffer yet to allow conversion from byte-positions
+ * if that's needed. So byte-postitions need to be converted to chars upstream
+ *
+ * Return value: None
+ */
+void
+create_search_entries (SearchReplace *sr)
 {
-	GList *entries = NULL;
-	GList *tmp;
-	GList *editors;
+	GList *entries;
+	GList *node;
+	GList *wids;
 	IAnjutaDocument *doc;
+	Search *s;
 	SearchEntry *se;
-	gint tmp_pos;
-	gint selstart;
+	position_t selstart;
+	position_t tmp_pos;
 
-	switch (s->range.type)
+	entries = NULL;
+	s = &(sr->search);
+	switch (s->range.target)
 	{
 		case SR_BUFFER:
+			/* scope is all of current buffer */
 			doc = ianjuta_document_manager_get_current_document (sr->docman, NULL);
-			if (doc && IANJUTA_IS_EDITOR (doc))
+			if (doc && IANJUTA_IS_EDITOR_SEARCH (doc))
 			{
-				se = g_new0 (SearchEntry, 1);
+				se = g_slice_new0 (SearchEntry);
 				se->type = SE_BUFFER;
 				se->te = IANJUTA_EDITOR (doc);
-				se->direction = s->range.direction;
-				if (SD_BEGINNING == se->direction)
+				/* backward search does not work for regular expressions, that's
+					probabley enforced by the GUI, but ... */
+				if (s->expr.regex && s->range.direction == SD_BACKWARD)
+					s->range.direction = SD_FORWARD;
+				if (s->range.direction == SD_WHOLE)	/* from start of buffer */
 				{
 					se->start_pos = 0;
 					se->end_pos = -1;
-					se->direction = SD_FORWARD;
+					se->direction = SD_FORWARD;	/* the actual direction to use */
 				}
 				else
-				{	
-					IAnjutaIterable *start;
-					/* forward-search from after beginning of selection, if any
-					   backwards-search from before beginning of selection, if any
-					   treat -ve positions except -1 as high +ve */
-					start = ianjuta_editor_selection_get_start
+				{
+					se->direction = s->range.direction;
+					if (ianjuta_editor_selection_has_selection
+						(IANJUTA_EDITOR_SELECTION (se->te), NULL))
+					{
+						IAnjutaIterable *x =
+						ianjuta_editor_selection_get_start
 							(IANJUTA_EDITOR_SELECTION (se->te), NULL);
-					if (start)
+						selstart = ianjuta_iterable_get_position (x, NULL);
+						g_object_unref (G_OBJECT (x));
+					}
+					else
+						selstart = -1;
+					if (selstart != -1)
 					{
-						selstart =
-							ianjuta_iterable_get_position (start, NULL);
 						if (se->direction == SD_BACKWARD)
 						{
 							se->start_pos = (selstart != 0) ?
 								 selstart - 1 : selstart;
 						}
 						else
-						{
-							se->start_pos =
-								(selstart != -2 &&
-								 selstart < ianjuta_editor_get_length (IANJUTA_EDITOR (se->te), NULL)) ?
-								 selstart + 1 : selstart;
-						}
-						g_object_unref (start);
+							se->start_pos = selstart;								
 					}
 					else
 					{
-						se->start_pos = ianjuta_editor_get_offset (se->te, NULL);
+						IAnjutaIterable *x =
+							ianjuta_editor_get_position (se->te, NULL);
+						se->start_pos = ianjuta_iterable_get_position (x, NULL);
+						g_object_unref (G_OBJECT (x));
+					}
+
+					if (se->direction == SD_BACKWARD)
+					{
+						se->end_pos = se->start_pos;
+						se->start_pos = 0;
 					}
-					se->end_pos = -1;	/* not actually used when backward searching */
+					else
+						se->end_pos = -1;
 				}
-				entries = g_list_prepend(entries, se);
+				entries = g_list_prepend (entries, se);
+			}
+			else if (doc)
+			{
+				g_warning ("Current buffer is not searchable");
 			}
 			break;
 		case SR_SELECTION:
 		case SR_BLOCK:
-		case SR_FUNCTION: 
+		case SR_FUNCTION:
+			/* scope is some of current buffer */
 			doc = ianjuta_document_manager_get_current_document (sr->docman, NULL);
-			if (doc && IANJUTA_IS_EDITOR (doc))
+			if (doc && IANJUTA_IS_EDITOR_SEARCH (doc))
 			{
-				gint selend;
-				
-				se = g_new0 (SearchEntry, 1);
+				position_t current;
+				position_t selend;
+
+				se = g_slice_new0 (SearchEntry);
 				se->type = SE_BUFFER;
 				se->te = IANJUTA_EDITOR (doc);
-				se->direction = s->range.direction;
-				if (se->direction == SD_BEGINNING)
+				if (s->range.direction == SD_WHOLE)	/* start of scope */
 					se->direction = SD_FORWARD;
+				else
+				/* Note that backward search does not work for regular expressions */
+					se->direction = s->range.direction;
 
-				if (s->range.type == SR_SELECTION)
+	//FIXME
+
+				if (s->range.target == SR_SELECTION)
 				{
-					selstart = selend = 0;	/* warning prevention only */
-				}				
+					if (selstart < 0)
+						break;
+					se->start_pos = selstart;
+					se->end_pos = selend;
+				}
 				else
 				{
-					IAnjutaIterable* end =
-						ianjuta_editor_selection_get_end (IANJUTA_EDITOR_SELECTION (se->te), NULL);
-					if (end)
-					{
-						selstart = selend = ianjuta_iterable_get_position (end, NULL);
-						g_object_unref (end);
-					}
-					else
+					if (s->range.target == SR_BLOCK)
+						ianjuta_editor_selection_select_block (IANJUTA_EDITOR_SELECTION (se->te), NULL);
+					else if (s->range.target == SR_FUNCTION)
+						ianjuta_editor_selection_select_function (IANJUTA_EDITOR_SELECTION (se->te), NULL);
+					IAnjutaIterable *x =
+						ianjuta_editor_selection_get_start
+							(IANJUTA_EDITOR_SELECTION (se->te), NULL);
+					se->start_pos = ianjuta_iterable_get_position (x, NULL);
+					IAnjutaIterable *y =
+						ianjuta_editor_selection_get_end
+							(IANJUTA_EDITOR_SELECTION (se->te), NULL);
+					se->start_pos = ianjuta_iterable_get_position (y, NULL);
+					ianjuta_editor_selection_set (IANJUTA_EDITOR_SELECTION (se->te),
+				       	                         x, y, NULL);
+					g_object_unref (x);
+					g_object_unref (y);
+					if (selstart < 0)
 					{
-						selstart = selend = 0;	/* warning prevention only */
-						g_assert ("No selection end position");
+						ianjuta_editor_goto_position (IANJUTA_EDITOR (se->te),
+														x, NULL);
 					}
 				}
 
-				if (s->range.type == SR_BLOCK)
-					ianjuta_editor_selection_select_block(IANJUTA_EDITOR_SELECTION (se->te), NULL);
-				if (s->range.type == SR_FUNCTION)
-					ianjuta_editor_selection_select_function(IANJUTA_EDITOR_SELECTION (se->te), NULL);
-				{
-					IAnjutaIterable *start, *end;
-					start = ianjuta_editor_selection_get_start (IANJUTA_EDITOR_SELECTION (se->te), NULL);
-					end = ianjuta_editor_selection_get_end(IANJUTA_EDITOR_SELECTION (se->te), NULL);
-					se->start_pos =  ianjuta_iterable_get_position (start, NULL);
-					se->end_pos = ianjuta_iterable_get_position (end, NULL);
-					g_object_unref (start);
-					g_object_unref (end);
-				}
-				if (se->direction == SD_BACKWARD)
-				{
-					tmp_pos = se->start_pos;
-					se->start_pos = se->end_pos;
-					se->end_pos = tmp_pos;
-				}	
-				entries = g_list_prepend (entries, se);
-				if (s->range.type != SR_SELECTION)
+				switch (s->range.direction)
 				{
-					IAnjutaIterable *start, *end;
-					start = ianjuta_editor_get_position_from_offset (se->te, selstart, NULL);
-					end = ianjuta_editor_get_position_from_offset (se->te, selend, NULL);
-					ianjuta_editor_selection_set(IANJUTA_EDITOR_SELECTION (se->te), 
-				                                 start, end, NULL);	
-					g_object_unref (start);
-					g_object_unref (end);
+					//case SD_WHOLE:
+					default:
+						/* start of scope forward to end, no change */
+						break;
+					case SD_FORWARD:
+						/* forward from current or start of selection if inside scope */
+						tmp_pos = (selstart < 0) ? /* no selection */
+							current : selstart + 1;
+						if (tmp_pos > se->start_pos && tmp_pos < se->end_pos)
+							se->start_pos = tmp_pos;
+						break;
+					case SD_BACKWARD:
+						/* backward from current or start of selection if inside scope */
+						tmp_pos = (selstart < 0) ? /* no selection */
+							current : selstart;
+						if (tmp_pos > se->start_pos && tmp_pos < se->end_pos)
+							se->end_pos = tmp_pos;
+						/* CHECKME with in-enditor searching * /
+						tmp_pos = se->start_pos;
+						se->start_pos = se->end_pos;
+						se->end_pos = tmp_pos;
+*/						break;
 				}
+
+				entries = g_list_prepend (entries, se);
+			}
+			else if (doc)
+			{
+				g_warning ("Current buffer is not searchable");
 			}
 			break;
 		case SR_OPEN_BUFFERS:
-			editors = ianjuta_document_manager_get_doc_widgets (sr->docman, NULL);
-			for (tmp = editors; tmp; tmp = g_list_next(tmp))
+			wids = ianjuta_document_manager_get_doc_widgets (sr->docman, NULL);
+			for (node = wids; node != NULL; node = g_list_next (node))
 			{
-				if (IANJUTA_IS_EDITOR (tmp->data))
+				if (IANJUTA_IS_EDITOR_SEARCH (node->data))
 				{
-					se = g_new0 (SearchEntry, 1);
-				se->type = SE_BUFFER;
-					se->te = IANJUTA_EDITOR (tmp->data);
-				se->direction = SD_FORWARD;
-				se->start_pos = 0;
-				se->end_pos = -1;
-				entries = g_list_prepend(entries, se);
-			}
+					se = g_slice_new0 (SearchEntry);
+					se->type = SE_BUFFER;
+					se->te = IANJUTA_EDITOR (node->data);
+					se->direction = SD_FORWARD;
+					se->start_pos = 0;
+					se->end_pos = -1;
+					entries = g_list_prepend (entries, se);
+				}
+				else
+				{
+					g_warning ("Skipping un-searchable file");
+				}
 			}
-			entries = g_list_reverse(entries);
-			g_list_free (editors);
+			if (entries != NULL)
+				entries = g_list_reverse (entries);
+			g_list_free (wids);
 			break;
 		case SR_FILES:
 		case SR_PROJECT:
 		{
 			GList *files = NULL;
-			gchar *dir = NULL;
-			gchar *dir_uri = NULL;		
-					
-			anjuta_shell_get (ANJUTA_PLUGIN(sr->docman)->shell,
+			gchar *dir_uri = NULL;
+			gchar *freeme;
+
+//			anjuta_shell_get (ANJUTA_PLUGIN (sr->docman)->shell,
+			anjuta_shell_get (ANJUTA_PLUGIN (splugin)->shell,
 							  "project_root_uri", G_TYPE_STRING,
 							  &dir_uri, NULL);
-			// FIXME : Replace Standard UNIX IO functions by gnome-vfs 
-			if (dir_uri)			
-				dir = gnome_vfs_get_local_path_from_uri(dir_uri);
-			
-			if (!dir)
-			{
-				if (SR_PROJECT == s->range.type)
-					s->range.type = SR_FILES;
-				dir = g_get_current_dir();
-			}
-
-			if (SR_FILES == s->range.type)
-				files = create_search_files_list(&(s->range.files), dir);
-			else /* if (SR_PROJECT == s->range.type) */
-				files = get_project_file_list();	
-			
+			if (dir_uri == NULL)
+			{
+				/* fallback to matching files in current dir */
+				dir_uri = gnome_vfs_get_uri_from_local_path (g_get_current_dir ());
+				if (dir_uri == NULL)
+				{
+					if (entries != NULL)
+						clear_search_entries (&entries);
+					g_return_if_fail (dir_uri);
+				}
+				if (s->range.target == SR_PROJECT)
+					s->range.target = SR_FILES;
+			}
+
+			freeme = dir_uri;
+			dir_uri = gnome_vfs_make_uri_canonical (dir_uri);
+			g_free (freeme);
+			if (dir_uri == NULL)
+			{
+				if (entries != NULL)
+					clear_search_entries (&entries);
+				g_return_if_fail (dir_uri);
+			}
+
+			if (s->range.target == SR_FILES)
+				files = get_search_files_list (&(s->range.files), dir_uri); //CHECKME what does this list contain ?
+			else /*  s->range.type == SR_PROJECT */
+				files = get_project_files_list (sr);
+
 			if (files)
 			{
-				for (tmp = files; tmp; tmp = g_list_next(tmp))
+				gint applen;
+				GList *node;
+				const gchar *check_mimes [7] =
 				{
-					se = g_new0(SearchEntry, 1);
-					se->type = SE_FILE;
-					se->path = (char *) tmp->data;
-					se->direction = SD_FORWARD;
-					se->type = SE_FILE;
-					se->start_pos = 0;
-					se->end_pos = -1;
-					entries = g_list_prepend(entries, se);
+					GNOME_VFS_MIME_TYPE_UNKNOWN,	/* for warnings */
+					"text/",	/* this is a prefix */
+					"application/x-", /* ditto */
+					"glade",	/* acceptable suffixes for application/x- */
+					"shellscript",
+					"perl",
+					"python",	/* unlikely as a source */
+				};
+
+				applen = strlen (check_mimes[2]);
+				for (node = files; node != NULL; node = g_list_next (node))
+				{
+					gchar *uri;
+
+					uri = (gchar *)node->data;
+					if (s->range.target == SR_FILES)	/* the returned list is paths, not uris */
+					{
+						gchar *real_uri;
+
+						real_uri =  gnome_vfs_get_uri_from_local_path (uri);
+						if (real_uri != NULL)
+						{
+							g_free (uri);
+							uri = real_uri;
+						}
+						else
+						{
+							if (entries != NULL)
+								clear_search_entries (&entries);
+							g_return_if_fail (real_uri);
+						}
+					}
+					if (uri)
+					{
+						gchar *mime_type;
+
+						mime_type = anjuta_util_get_uri_mime_type (uri);
+						if (mime_type)
+						{
+							if (g_str_has_prefix (mime_type, check_mimes [1])
+							 ||(g_str_has_prefix (mime_type, check_mimes [2]) &&
+								(  strcmp (mime_type + applen, check_mimes [3]) == 0
+								|| strcmp (mime_type + applen, check_mimes [4]) == 0
+								|| strcmp (mime_type + applen, check_mimes [5]) == 0
+								|| strcmp (mime_type + applen, check_mimes [6]) == 0
+								)))
+							{
+								gchar *canon_uri;
+
+								canon_uri = gnome_vfs_make_uri_canonical (uri);
+								//CHECKME any escaping or other cleanup ?
+								if (canon_uri != NULL)
+								{
+									/* there might be an already-open document with this uri */
+									doc = ianjuta_document_manager_find_document_with_uri
+											(sr->docman, canon_uri, NULL);
+									if (doc == NULL	/* not open now */
+										|| IANJUTA_IS_EDITOR_SEARCH (doc)) /* open and searchable CHECKME glade files ? */
+									{
+										se = g_slice_new0 (SearchEntry);
+										se->type = (doc) ? SE_BUFFER:SE_FILE;
+										if (doc)
+										{
+											g_free (canon_uri);
+											se->te = IANJUTA_EDITOR (doc);
+										}
+										else
+											se->uri = canon_uri;
+										se->direction = SD_FORWARD;	/* default scope, may change later */
+										se->start_pos = 0;
+										se->end_pos = -1;
+										entries = g_list_prepend (entries, se);
+									}
+									else
+									{
+										g_warning ("skipping open file %s which is not searchable",
+													uri);
+									}
+								}
+								else
+								{
+									//FIXME UI warning
+									g_warning ("Skipping %s, cannot get its real uri", uri);
+								}
+							}
+							else if (strcmp (mime_type, check_mimes [3]) == 0)
+							{
+								//FIXME UI warning
+								g_warning ("Skipping %s, unknown mime-type", uri);
+							}
+							g_free (mime_type);
+						}
+						else
+						{
+							//FIXME UI warning
+							g_warning ("Skipping %s, cannot get its mime-type", uri);
+						}
+						g_free (uri);
+					}
 				}
-				g_list_free(files);
-				entries = g_list_reverse(entries);
+				g_list_free (files);
+				if (entries != NULL)
+					entries = g_list_reverse (entries);
 			}
-			g_free(dir);
-			g_free(dir_uri);
+			g_free (dir_uri);
 			break;
 		}
-	}	
-	return entries;		
+	}
+	sr->search.candidates = entries;
 }
 
-gchar *
-regex_backref (MatchInfo *mi, FileBuffer *fb)
+/**
+ * clear_search_entries:
+ * @entries: pointer to store of list-pointer
+ *
+ * Cleanup list of search entries
+ *
+ * Return value: none
+ */
+void
+clear_search_entries (GList **entries)
 {
-#define REGX_BUFSIZE 1024
-	gint i, j, k;
-	gint nb_backref;
-	gint i_backref;
-	gint plen;
-	gint start, len;
-	gint backref[10] [2];	/* backref [0][2] unused */
-	gchar buf [REGX_BUFSIZE + 4];	/* usable space + word-sized space for trailing 0 */
-	GList *tmp;
-	
-	i = 1;
-	/* Extract back references */
-	tmp = mi->subs;
-	while (tmp && i < 10)
-	{
-		backref[i] [0] = ((MatchSubStr*)tmp->data)->start;
-		backref[i] [1] = ((MatchSubStr*)tmp->data)->len;
-		tmp= g_list_next(tmp);
-		i++;
-	}
-	nb_backref = i;
-	plen = strlen (sr->replace.repl_str);
-	for(i=0, j=0; i < plen && j < REGX_BUFSIZE; i++)
+	if (*entries != NULL)
 	{
-		if (sr->replace.repl_str[i] == '\\')
+		GList *node;
+
+		for (node = *entries; node != NULL; node = g_list_next (node))
 		{
-			i++;
-			if (sr->replace.repl_str[i] > '0' && sr->replace.repl_str[i] <= '9')
+			SearchEntry *se;
+			se = (SearchEntry *)node->data;
+			if (se != NULL)
 			{
-				i_backref = sr->replace.repl_str[i] - '0';
-				if (i_backref < nb_backref)
-				{
-					start = backref[i_backref] [0];
-					len = backref[i_backref] [1];
-					for (k=0; k < len && j < REGX_BUFSIZE; k++)
-						buf[j++] = fb->buf[start + k];	
-				}
-			}	
-		}	
-		else
-			buf[j++] = sr->replace.repl_str[i];				
+				g_free (se->uri);
+				g_free (se->regx_repl_str);
+				if (se->fb != NULL)
+					file_buffer_free (se->fb);
+				if (se->mi.subs != NULL)
+					match_info_free_subs (&(se->mi));
+				g_slice_free1 (sizeof (SearchEntry), se);
+			}
+		}
+		g_list_free (*entries);
+		*entries = NULL;
 	}
-	buf[j] = '\0';
+}
 
-	return g_strdup (buf);
+/**
+ * search_get_default_data:
+ *
+ * Get pointer to static data struct with search/replace data
+ *
+ * Return value: the data
+ */
+SearchReplace *
+search_get_default_data (void)
+{
+	if (def_sr == NULL)
+	{
+		def_sr = search_replace_data_new ();
+		g_return_val_if_fail (def_sr != NULL, NULL);
+	}
+	return def_sr;
 }
 
-#define FREE_FN(fn, v) if (v) { fn(v); v = NULL; }
+/**
+ * search_replace_data_new:
+ *
+ * Create new search/replace data struct with some generally-useful content
+ *
+ * Return value: pointer to the data struct
+ */
+SearchReplace *
+search_replace_data_new (void)
+{
+	SearchReplace *sr;
+
+	sr = g_slice_new0 (SearchReplace);
+	sr->docman = splugin->docman;
 
-void
-clear_search_replace_instance(void)
+	/* log whether pcre can handle utf-8 */
+	pcre_config (PCRE_CONFIG_UTF8, &sr->search.expr.utf8regex);
+
+	return sr;
+}
+
+#undef FREE_FN
+#define FREE_FN(fn,v) if (v) { fn(v); }
+
+/**
+ * clear_search_replace_instance:
+ * @sr: pointer to sr data struct to clear
+ *
+ * Clears allocated memory, and zero's all contents of @sr other than docman and sg
+ *
+ * Return value: none
+ */
+static void
+clear_search_replace_instance (SearchReplace *sr)
 {
 	g_free (sr->search.expr.search_str);
 	g_free (sr->search.expr.re);
 	FREE_FN(pcre_info_free, sr->search.expr.re);
-	if (SR_FILES == sr->search.range.type)
-	{
-		FREE_FN(anjuta_util_glist_strings_free, sr->search.range.files.match_files);
-		FREE_FN(anjuta_util_glist_strings_free, sr->search.range.files.ignore_files);
-		FREE_FN(anjuta_util_glist_strings_free, sr->search.range.files.match_dirs);
-		FREE_FN(anjuta_util_glist_strings_free, sr->search.range.files.ignore_dirs);
-	}
+	FREE_FN(anjuta_util_glist_strings_free, sr->search.range.files.match_files);
+	FREE_FN(anjuta_util_glist_strings_free, sr->search.range.files.ignore_files);
+	FREE_FN(anjuta_util_glist_strings_free, sr->search.range.files.match_dirs);
+	FREE_FN(anjuta_util_glist_strings_free, sr->search.range.files.ignore_dirs);
 	FREE_FN(anjuta_util_glist_strings_free, sr->search.expr_history);
 	g_free (sr->replace.repl_str);
 	FREE_FN(anjuta_util_glist_strings_free, sr->replace.expr_history);
+
+//	memset (&sr->search, 0, sizeof (Search));
+//	memset (&sr->replace, 0, sizeof (Replace));
 }
 
+/**
+ * search_replace_data_destroy:
+ * @sr: pointer to sr data struct to clear, or NULL for default
+ *
+ * Return value: none
+ */
 void
-clear_pcre(void)
+search_replace_data_destroy (SearchReplace *sr)
 {
-	FREE_FN(pcre_info_free, sr->search.expr.re);
+	if (sr == NULL)
+		sr = def_sr;
+	if (sr != NULL)
+	{
+		clear_search_replace_instance (sr);
+		g_slice_free1 (sizeof (SearchReplace), sr);
+	}
 }
 
-SearchReplace *
-create_search_replace_instance(IAnjutaDocumentManager *docman)
+/**
+ * search_replace_init:
+ * @plugin: pointer to plugin data struct
+ *
+ * Called when search plugin is activated.
+ *
+ * Return value: none
+ */
+void
+search_replace_init (AnjutaPlugin *plugin)
 {
-	if (NULL == sr) /* Create a new SearchReplace instance */
-		sr = g_new0(SearchReplace, 1);
-	else
-		clear_search_replace_instance ();
-	if (docman)
-		sr->docman = docman;
-	return sr;
+	/* make application data available to funcs here*/
+	splugin = ANJUTA_PLUGIN_SEARCH (plugin);
 }

Modified: trunk/plugins/search/search-replace_backend.h
==============================================================================
--- trunk/plugins/search/search-replace_backend.h	(original)
+++ trunk/plugins/search/search-replace_backend.h	Fri Apr 11 00:19:38 2008
@@ -1,19 +1,25 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
- * 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
+ * search-replace_backend.h: Header for Generic Search and Replace
+ * Copyright (C) 2004 Biswapesh Chattopadhyay
+ * Copyright (C) 2004-2007 Naba Kumar  <naba gnome org>
+ *
+ * This file is part of anjuta.
+ * Anjuta 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 2 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
+ *
+ * Anjuta 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 Library General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with anjuta; if not, contact the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
- 
+
 #ifndef _SEARCH_REPLACE_BACKEND_H
 #define _SEARCH_REPLACE_BACKEND_H
 
@@ -23,25 +29,54 @@
 #endif
 
 #include <pcre.h>
+#include <glade/glade.h>
 
 #include <libanjuta/interfaces/ianjuta-document-manager.h>
 #include <libanjuta/interfaces/ianjuta-editor.h>
-	
-	
+
+#include "plugin.h"
+
+/* FIXME make these global */
+typedef gint line_t;
+typedef gint position_t;
+#define POINTER_TO_LINE GPOINTER_TO_INT
+#define LINE_TO_POINTER GINT_TO_POINTER
+#define POINTER_TO_POSITION GPOINTER_TO_INT
+#define POSITION_TO_POINTER GINT_TO_POINTER
+
+/* define to include code for managing EOL chars in local file buffers */
+/*#define MANAGE_EOL */
+
 /* PCRE search compiled pattern and other info */
 typedef struct _PcreInfo
 {
-	gint ovec_count;;
-	gint *ovector;
+	gint ovec_count;
+	position_t *ovector;	/* note pcre always uses gint */
 	pcre *re;
 	pcre_extra *extra;
 } PcreInfo;
 
+/* Flags for type of position data available from a search-process */
+typedef enum _SearchPosType
+{
+	SP_UNKNOWN	= 0,
+	SP_BYTES	= 1,
+	SP_CHARS	= 2,
+	/* rest are unused ATM*/
+	SP_GINT		= 4,
+	SP_GUINT	= 8,
+	SP_GLONG	= 16,
+	SP_GULONG	= 32,
+	SP_GLLONG	= 64,
+	SP_GULLONG	= 128
+} SearchPosType;
+
 /* Search expression options */
 typedef struct _SearchExpression
 {
 	gchar *search_str;
 	gboolean regex;
+	gboolean utf8regex;	/* TRUE when pcre compiled with utf-8 support */
 	gboolean greedy;
 	gboolean ignore_case;
 	gboolean whole_word;
@@ -50,16 +85,16 @@
 	gboolean no_limit;
 	gint actions_max;
 	PcreInfo *re;
+	SearchPosType postype;
 } SearchExpression;
 
-
-/* Direction to search (only valid for the current buffer). Note that backward
-search does not work for regular expressions. */
+/* Direction to search (only valid for the current buffer).
+   Note that backward search does not work for regular expressions. */
 typedef enum _SearchDirection
 {
+	SD_WHOLE, /* From the beginning of the buffer|selection|function|block (0 == default) */
 	SD_FORWARD, /* Forward from the cursor */
-	SD_BACKWARD, /* Backward from the cursor */
-	SD_BEGINNING /* From the beginning of the buffer */
+	SD_BACKWARD /* Backward from the cursor */
 } SearchDirection;
 
 /* Where to search - type */
@@ -71,12 +106,13 @@
 	SR_FUNCTION, /* Current function */
 	SR_OPEN_BUFFERS, /* All open buffers */
 	SR_PROJECT, /* All project files */
-	SR_FILES /* A set of patterns specifying which files to search */
+//	SR_VARIABLE,	/* A nominated list of files */
+	SR_FILES	/* A series of patterns specifying which files to search */
 } SearchRangeType;
 
 /*
-** Search variable is a string which is expanded using the properties interface
-*/
+ * Search variable is a string which is expanded using the properties interface
+ */
 typedef gchar *SearchVar;
 
 /* Specify files to search in. Note that each GList is a list of strings which
@@ -88,42 +124,58 @@
 	GList *match_dirs;
 	GList *ignore_files;
 	GList *ignore_dirs;
-	gboolean ignore_hidden_files;
-	gboolean ignore_hidden_dirs;
 	gboolean recurse;
+	gboolean ignore_hidden_dirs;
+	gboolean ignore_hidden_files;
+//	gboolean ignore_binary_files;
 } SearchFiles;
 
-/* Search range - used to create search list of files */
+/* search range - used to create search list of files */
 typedef struct _SearchRange
 {
-	SearchRangeType type;
+	SearchRangeType target;
 	SearchDirection direction; /* type = SR_BUFFER */
 	gboolean whole;
 	SearchVar var; /* type = SR_VARIABLE */
 	SearchFiles files; /* type = SR_FILES */
 } SearchRange;
 
-/* What to do with the result of the search */
+/* What s/r operation to perform */
 typedef enum _SearchAction
 {
-	SA_SELECT, /* Jump to the next match and select it (current buffer only)*/
-	SA_BOOKMARK, /* Bookmark all lines containing a match (open buffers only) */
-	SA_HIGHLIGHT, /* Highlight all matched strings (open buffers only) */
-	SA_FIND_PANE, /* Show result in find pane */
-	SA_REPLACE, /* Replace next match with specified string */
-	SA_REPLACEALL /* Replace all matches with specified string */
+	SA_SELECT,		/* find the next/previos match and select it */
+	SA_BOOKMARK,	/* bookmark all lines containing a match */
+	SA_HIGHLIGHT,	/* mark/highlight all matched strings */
+	SA_UNLIGHT,		/* remove all highlights */
+	SA_FIND_PANE,	/* show result in find pane */
+	SA_REPLACE,		/* replace all with a check for each match */
+	SA_REPLACEALL	/* replace all matches without confirmation */
 } SearchAction;
 
-/* Search master option structure */
+typedef enum _ReplacePhase
+{
+	SA_REPL_FIRST,	/* beginning an interactive replace operation */
+	SA_REPL_SKIP,	/* during a replace operation, the user has decided to skip (keep) the current match */
+	SA_REPL_CONFIRM,/* during a replace operation, the user has decided to replace the current match */
+} ReplacePhase;
+
+/* search/replace master data structure */
 typedef struct _Search
 {
 	SearchExpression expr;
 	SearchRange range;
 	SearchAction action;
 	GList *expr_history;
-	gint incremental_pos;
+	position_t incremental_pos;	//want chars not bytes
 	gboolean incremental_wrap;
 	gboolean basic_search;
+	gboolean limited; /* TRUE when processing: block, function, selection */
+	gint stop_count;		/* count of stop-button clicks, or < 0 to abort operation */
+	/* non-file-specific data that needs to persist between phases of an interactive replacement */
+	GList *candidates;		/* list of SeacrchEntry's */
+	guint matches_sofar;	/* count of matches processed */
+	gboolean busy;			/* TRUE to block sr data changes (when a search is in progress
+								(a friendlier approach than de-sensitizing most widgets) */
 } Search;
 
 /* Contains information about replacement */
@@ -133,99 +185,139 @@
 	gboolean regex;
 	gboolean confirm;
 	gboolean load_file;
+//	gboolean interactive;	/* TRUE for the 2nd phase of a confirmed replacement */
+	ReplacePhase phase;		/* == SA_REPL_CONFIRM for the 2nd (replacement) phase of a replacement */
 	GList *expr_history;
 } Replace;
 
+typedef struct _MatchInfo
+{
+	position_t pos;	/* char- or byte-index (as neeeded by the editor) of match start */
+	position_t len;	/* char- or byte-length (as neeeded by the editor) of match */
+	line_t line;	/* 1-based no. of line in file-buffer containing start of match */
+	GList *subs;	/* list of <MatchSubStr *> sub-expression/backref data, if any */
+} MatchInfo;
+
 typedef struct _SearchReplace
 {
 	Search search;
 	Replace replace;
+	struct _SearchReplaceGUI *sg;	/* for cross-referencing */
 	IAnjutaDocumentManager *docman;
-	
 } SearchReplace;
 
 typedef enum _FileBufferType
 {
 	FB_NONE,
-	FB_FILE, /* File loaded from disk */
-	FB_EDITOR /* Corresponding to a TextEditor structure */
+	FB_FILE,	/* File not yet opened */
+	FB_BUFFER	/* File already open */
 } FileBufferType;
 
+/* this conforms to scintilla:
+#define SC_EOL_CRLF 0
+#define SC_EOL_CR 1
+#define SC_EOL_LF 2
+*/
+typedef enum _EOLType
+{
+	EOL_UNKNOWN = -1,
+	EOL_CRLF,
+	EOL_CR,
+	EOL_LF,
+	EOL_UNI, //unicode, GDK_paragraph,  0x0b6, scintilla should use SC_EOL_LF ?
+} EOLType;
+
 typedef struct _FileBuffer
 {
 	FileBufferType type;
-	/* The following are valid only for files loaded from disk */
-	gchar *name; /* Name of the file */
-	gchar *path; /* Full path to the file */
-	gchar *uri;  /* URI to the file */
-	gchar *buf; /* Contents of the file */
-	gint len; /* Length of the buffer */
-	gint pos; /* Current position */
-	gint endpos; /* Restrict action upto this position */
-	gint line; /* Current line */
-	GList *lines; /* List of integers specifying line start positions */
+	/* Some of the following are valid only for files loaded from disk */
+//UNUSED	const gchar *name;	/* name of the file, typically part of uri */
+	gchar *uri;			/* file  uri (may be NULL) */
+	gchar *encoding;	/* for fresh files */
+#ifdef MANAGE_EOL
+	EOLType separator_type;	/* for fresh files */
+#endif
+	gchar *buf;			/* contents of the file - free after use */
+	position_t len;		/* total chars (NOT bytes) in the buffer */
+	/* pos and endpos are char-offsets, NOT byte-offsets */
+	position_t start_pos;/* char-position to start a search */
+	position_t end_pos;	/* char-position to end a search, may be -1 for EOF or else always > start_pos */
+	line_t line;		/* Current line, 1-based index */
+	GList *lines;		/* list of EOLdata's specifying line-end byte-offsets and
+						   char-offsets (actually, they are offsets of '\n' chars)
+						   THe first member will be {0,0} implying position before
+						   start of text */
 	/* The following are valid only for files corresponding to a TextEditor */
 	IAnjutaEditor *te;
 } FileBuffer;
 
-
-/* A search entry is a file or buffer to search. This can be a file,
-a buffer or part of a buffer (such as selected text) */
 typedef enum _SearchEntryType
 {
 	SE_FILE,
 	SE_BUFFER,
 } SearchEntryType;
 
+/* A search entry holds data about a search. It can apply to a file not opened,
+   or to an open buffer or part of a buffer (such as selected text) */
 typedef struct _SearchEntry
 {
-	SearchEntryType type;
-	gchar *path;
-	IAnjutaEditor *te;
+	SearchEntryType type;	/* SE_BUFFER for item already open, else SE_FILE */
+	gchar *uri;				/* NULL for SE_BUFFER, canonical uri for SE_FILE */
+	IAnjutaEditor *te;		/* non-NULL for SE_BUFFER, NULL for SE_FILE */
+	FileBuffer *fb;			/* for retaining buffer between phases of a SA_REPLACE */
+	gboolean fresh;			/* for retaining status */
 	SearchDirection direction;
-	gint start_pos;
-	gint end_pos;
+	/* start_pos and end_pos are char-offsets, NOT byte-offsets */
+	position_t start_pos;	/* char-offset where to start the search (> end_pos for SD_BACKWARD direction) */
+	position_t end_pos;		/* char-offset where to end the search (-1 for EOF) */
+	/* data which needs to persist between phases of a confirmed replacement */
+	MatchInfo mi;
+	gchar *regx_repl_str;
+	line_t found_line;
+	/* selection-position often changes during a search, so these remember its initial position */
+	position_t sel_first_start;
+	position_t sel_first_end;
+//	position_t offset;			/ * differential length for current (maybe each) replacement, bytes or chars * /
+	position_t total_offset;	/* cumulative difference between searched buffer
+									and edited buffer with replacement(s),
+									bytes or chars to suit the editor */
 } SearchEntry;
-	
-typedef struct _MatchInfo
-{
-	gint pos;
-	gint len;
-	gint line;
-	GList *subs; /* <MatchSubStr *> */
-} MatchInfo;
-
-
-//  void search_and_replace_backend_init (AnjutaDocman *dm);
-
-void function_select (IAnjutaEditor *te);
-
-GList *create_search_entries(Search *s);
 
+void create_search_entries (SearchReplace *sr);
+void clear_search_entries (GList **entries);
+void editor_new_from_file_buffer (SearchEntry *se);
 FileBuffer *file_buffer_new_from_te (IAnjutaEditor *te);
-
-FileBuffer *
-file_buffer_new_from_path(const char *path, const char *buf, int len, int pos);
-
-FileBuffer *
-file_buffer_new_from_path(const char *path, const char *buf, int len, int pos);
-
-gchar *file_match_line_from_pos(FileBuffer *fb, int pos);
-
-MatchInfo *get_next_match(FileBuffer *fb, SearchDirection direction, SearchExpression *s);
-
-gchar *regex_backref(MatchInfo *mi, FileBuffer *fb);
-
-void match_info_free (MatchInfo *mi);
-
+FileBuffer *file_buffer_new_from_uri (SearchReplace *sr,
+									  const gchar *uri,
+									  const gchar *buf,
+									  position_t len);
+void file_buffer_freshen_lines_from_pos (FileBuffer *fb,
+										position_t offset,
+										gboolean offset_bytes);
+position_t file_buffer_get_byte_offset (FileBuffer *fb, position_t charoffset);
+position_t file_buffer_get_char_offset (FileBuffer *fb, position_t byteoffset);
+//gchar *file_buffer_get_linetext_for_pos (FileBuffer *fb, position_t pos);
+gchar *file_buffer_get_linetext_for_line (FileBuffer *fb, line_t lineno);
+gboolean get_next_match (FileBuffer *fb,
+						 SearchDirection direction,
+						 SearchExpression *se,
+						 MatchInfo *mi);
+gboolean save_file_buffer (FileBuffer *fb);
+gboolean replace_in_local_buffer (FileBuffer *fb,
+								  position_t matchstart,
+								  position_t matchlen,
+								  gchar *repl_str);
+gchar *regex_backref (SearchReplace *sr, MatchInfo *mi, FileBuffer *fb);
+void match_info_free_subs (MatchInfo *mi);
 void file_buffer_free (FileBuffer *fb);
-
-SearchReplace *create_search_replace_instance(IAnjutaDocumentManager *docman);
-
-void clear_pcre(void);
+SearchReplace *search_replace_data_new (void);
+SearchReplace *search_get_default_data (void);
+void search_replace_init (AnjutaPlugin *plugin);
+void search_replace_data_destroy (SearchReplace *sr);
+void pcre_info_free (PcreInfo *re);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* _SEARCH_REPLACE_H */
+#endif /* _SEARCH_REPLACE_BACKEND_H */



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