anjuta r3845 - in trunk: . plugins/file-loader plugins/search
- From: jhs svn gnome org
- To: svn-commits-list gnome org
- Subject: anjuta r3845 - in trunk: . plugins/file-loader plugins/search
- Date: Fri, 11 Apr 2008 00:19:38 +0100 (BST)
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 & 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 & 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"><b>Action:</b></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 "the search expression" (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"><b>Parameters</b></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"><b>Scope</b></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"><b>Options</b></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"><b>Expression:</b></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 "the search expression" (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"><b>Options</b></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"><b>Scope</b></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"><b>Actions</b></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"><b>Search variable</b></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"><b>File Filter</b></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 & 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"><b>Scope:</b></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]