summaryrefslogtreecommitdiff
path: root/pluma/pluma-commands-search.c
diff options
context:
space:
mode:
Diffstat (limited to 'pluma/pluma-commands-search.c')
-rwxr-xr-xpluma/pluma-commands-search.c716
1 files changed, 716 insertions, 0 deletions
diff --git a/pluma/pluma-commands-search.c b/pluma/pluma-commands-search.c
new file mode 100755
index 00000000..5bdcd92d
--- /dev/null
+++ b/pluma/pluma-commands-search.c
@@ -0,0 +1,716 @@
+/*
+ * pluma-search-commands.c
+ * This file is part of pluma
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002-2006 Paolo Maggi
+ *
+ * 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the pluma Team, 1998-2006. See the AUTHORS file for a
+ * list of people on the pluma Team.
+ * See the ChangeLog files for a list of changes.
+ *
+ * $Id$
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "pluma-commands.h"
+#include "pluma-debug.h"
+#include "pluma-statusbar.h"
+#include "pluma-window.h"
+#include "pluma-window-private.h"
+#include "pluma-utils.h"
+#include "dialogs/pluma-search-dialog.h"
+
+#define PLUMA_SEARCH_DIALOG_KEY "pluma-search-dialog-key"
+#define PLUMA_LAST_SEARCH_DATA_KEY "pluma-last-search-data-key"
+
+typedef struct _LastSearchData LastSearchData;
+struct _LastSearchData
+{
+ gint x;
+ gint y;
+};
+
+static void
+last_search_data_free (LastSearchData *data)
+{
+ g_slice_free (LastSearchData, data);
+}
+
+static void
+last_search_data_restore_position (PlumaSearchDialog *dlg)
+{
+ LastSearchData *data;
+
+ data = g_object_get_data (G_OBJECT (dlg), PLUMA_LAST_SEARCH_DATA_KEY);
+
+ if (data != NULL)
+ {
+ gtk_window_move (GTK_WINDOW (dlg),
+ data->x,
+ data->y);
+ }
+}
+
+static void
+last_search_data_store_position (PlumaSearchDialog *dlg)
+{
+ LastSearchData *data;
+
+ data = g_object_get_data (G_OBJECT (dlg), PLUMA_LAST_SEARCH_DATA_KEY);
+
+ if (data == NULL)
+ {
+ data = g_slice_new (LastSearchData);
+
+ g_object_set_data_full (G_OBJECT (dlg),
+ PLUMA_LAST_SEARCH_DATA_KEY,
+ data,
+ (GDestroyNotify) last_search_data_free);
+ }
+
+ gtk_window_get_position (GTK_WINDOW (dlg),
+ &data->x,
+ &data->y);
+}
+
+/* Use occurences only for Replace All */
+static void
+text_found (PlumaWindow *window,
+ gint occurrences)
+{
+ if (occurrences > 1)
+ {
+ pluma_statusbar_flash_message (PLUMA_STATUSBAR (window->priv->statusbar),
+ window->priv->generic_message_cid,
+ ngettext("Found and replaced %d occurrence",
+ "Found and replaced %d occurrences",
+ occurrences),
+ occurrences);
+ }
+ else
+ {
+ if (occurrences == 1)
+ pluma_statusbar_flash_message (PLUMA_STATUSBAR (window->priv->statusbar),
+ window->priv->generic_message_cid,
+ _("Found and replaced one occurrence"));
+ else
+ pluma_statusbar_flash_message (PLUMA_STATUSBAR (window->priv->statusbar),
+ window->priv->generic_message_cid,
+ " ");
+ }
+}
+
+#define MAX_MSG_LENGTH 40
+static void
+text_not_found (PlumaWindow *window,
+ const gchar *text)
+{
+ gchar *searched;
+
+ searched = pluma_utils_str_end_truncate (text, MAX_MSG_LENGTH);
+
+ pluma_statusbar_flash_message (PLUMA_STATUSBAR (window->priv->statusbar),
+ window->priv->generic_message_cid,
+ /* Translators: %s is replaced by the text
+ entered by the user in the search box */
+ _("\"%s\" not found"), searched);
+ g_free (searched);
+}
+
+static gboolean
+run_search (PlumaView *view,
+ gboolean wrap_around,
+ gboolean search_backwards)
+{
+ PlumaDocument *doc;
+ GtkTextIter start_iter;
+ GtkTextIter match_start;
+ GtkTextIter match_end;
+ gboolean found = FALSE;
+
+ doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
+
+ if (!search_backwards)
+ {
+ gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
+ NULL,
+ &start_iter);
+
+ found = pluma_document_search_forward (doc,
+ &start_iter,
+ NULL,
+ &match_start,
+ &match_end);
+ }
+ else
+ {
+ gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
+ &start_iter,
+ NULL);
+
+ found = pluma_document_search_backward (doc,
+ NULL,
+ &start_iter,
+ &match_start,
+ &match_end);
+ }
+
+ if (!found && wrap_around)
+ {
+ if (!search_backwards)
+ found = pluma_document_search_forward (doc,
+ NULL,
+ NULL, /* FIXME: set the end_inter */
+ &match_start,
+ &match_end);
+ else
+ found = pluma_document_search_backward (doc,
+ NULL, /* FIXME: set the start_inter */
+ NULL,
+ &match_start,
+ &match_end);
+ }
+
+ if (found)
+ {
+ gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc),
+ &match_start);
+
+ gtk_text_buffer_move_mark_by_name (GTK_TEXT_BUFFER (doc),
+ "selection_bound",
+ &match_end);
+
+ pluma_view_scroll_to_cursor (view);
+ }
+ else
+ {
+ gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc),
+ &start_iter);
+ }
+
+ return found;
+}
+
+static void
+do_find (PlumaSearchDialog *dialog,
+ PlumaWindow *window)
+{
+ PlumaView *active_view;
+ PlumaDocument *doc;
+ gchar *search_text;
+ const gchar *entry_text;
+ gboolean match_case;
+ gboolean entire_word;
+ gboolean wrap_around;
+ gboolean search_backwards;
+ guint flags = 0;
+ guint old_flags = 0;
+ gboolean found;
+
+ /* TODO: make the dialog insensitive when all the tabs are closed
+ * and assert here that the view is not NULL */
+ active_view = pluma_window_get_active_view (window);
+ if (active_view == NULL)
+ return;
+
+ doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (active_view)));
+
+ entry_text = pluma_search_dialog_get_search_text (dialog);
+
+ match_case = pluma_search_dialog_get_match_case (dialog);
+ entire_word = pluma_search_dialog_get_entire_word (dialog);
+ search_backwards = pluma_search_dialog_get_backwards (dialog);
+ wrap_around = pluma_search_dialog_get_wrap_around (dialog);
+
+ PLUMA_SEARCH_SET_CASE_SENSITIVE (flags, match_case);
+ PLUMA_SEARCH_SET_ENTIRE_WORD (flags, entire_word);
+
+ search_text = pluma_document_get_search_text (doc, &old_flags);
+
+ if ((search_text == NULL) ||
+ (strcmp (search_text, entry_text) != 0) ||
+ (flags != old_flags))
+ {
+ pluma_document_set_search_text (doc, entry_text, flags);
+ }
+
+ g_free (search_text);
+
+ found = run_search (active_view,
+ wrap_around,
+ search_backwards);
+
+ if (found)
+ text_found (window, 0);
+ else
+ text_not_found (window, entry_text);
+
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
+ PLUMA_SEARCH_DIALOG_REPLACE_RESPONSE,
+ found);
+}
+
+/* FIXME: move in pluma-document.c and share it with pluma-view */
+static gboolean
+get_selected_text (GtkTextBuffer *doc,
+ gchar **selected_text,
+ gint *len)
+{
+ GtkTextIter start, end;
+
+ g_return_val_if_fail (selected_text != NULL, FALSE);
+ g_return_val_if_fail (*selected_text == NULL, FALSE);
+
+ if (!gtk_text_buffer_get_selection_bounds (doc, &start, &end))
+ {
+ if (len != NULL)
+ len = 0;
+
+ return FALSE;
+ }
+
+ *selected_text = gtk_text_buffer_get_slice (doc, &start, &end, TRUE);
+
+ if (len != NULL)
+ *len = g_utf8_strlen (*selected_text, -1);
+
+ return TRUE;
+}
+
+static void
+replace_selected_text (GtkTextBuffer *buffer,
+ const gchar *replace)
+{
+ g_return_if_fail (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL));
+ g_return_if_fail (replace != NULL);
+
+ gtk_text_buffer_begin_user_action (buffer);
+
+ gtk_text_buffer_delete_selection (buffer, FALSE, TRUE);
+
+ gtk_text_buffer_insert_at_cursor (buffer, replace, strlen (replace));
+
+ gtk_text_buffer_end_user_action (buffer);
+}
+
+static void
+do_replace (PlumaSearchDialog *dialog,
+ PlumaWindow *window)
+{
+ PlumaDocument *doc;
+ const gchar *search_entry_text;
+ const gchar *replace_entry_text;
+ gchar *unescaped_search_text;
+ gchar *unescaped_replace_text;
+ gchar *selected_text = NULL;
+ gboolean match_case;
+
+ doc = pluma_window_get_active_document (window);
+ if (doc == NULL)
+ return;
+
+ search_entry_text = pluma_search_dialog_get_search_text (dialog);
+ g_return_if_fail ((search_entry_text) != NULL);
+ g_return_if_fail ((*search_entry_text) != '\0');
+
+ /* replace text may be "", we just delete */
+ replace_entry_text = pluma_search_dialog_get_replace_text (dialog);
+ g_return_if_fail ((replace_entry_text) != NULL);
+
+ unescaped_search_text = pluma_utils_unescape_search_text (search_entry_text);
+
+ get_selected_text (GTK_TEXT_BUFFER (doc),
+ &selected_text,
+ NULL);
+
+ match_case = pluma_search_dialog_get_match_case (dialog);
+
+ if ((selected_text == NULL) ||
+ (match_case && (strcmp (selected_text, unescaped_search_text) != 0)) ||
+ (!match_case && !g_utf8_caselessnmatch (selected_text,
+ unescaped_search_text,
+ strlen (selected_text),
+ strlen (unescaped_search_text)) != 0))
+ {
+ do_find (dialog, window);
+ g_free (unescaped_search_text);
+ g_free (selected_text);
+
+ return;
+ }
+
+ unescaped_replace_text = pluma_utils_unescape_search_text (replace_entry_text);
+ replace_selected_text (GTK_TEXT_BUFFER (doc), unescaped_replace_text);
+
+ g_free (unescaped_search_text);
+ g_free (selected_text);
+ g_free (unescaped_replace_text);
+
+ do_find (dialog, window);
+}
+
+static void
+do_replace_all (PlumaSearchDialog *dialog,
+ PlumaWindow *window)
+{
+ PlumaView *active_view;
+ PlumaDocument *doc;
+ const gchar *search_entry_text;
+ const gchar *replace_entry_text;
+ gboolean match_case;
+ gboolean entire_word;
+ guint flags = 0;
+ gint count;
+
+ active_view = pluma_window_get_active_view (window);
+ if (active_view == NULL)
+ return;
+
+ doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (active_view)));
+
+ search_entry_text = pluma_search_dialog_get_search_text (dialog);
+ g_return_if_fail ((search_entry_text) != NULL);
+ g_return_if_fail ((*search_entry_text) != '\0');
+
+ /* replace text may be "", we just delete all occurrencies */
+ replace_entry_text = pluma_search_dialog_get_replace_text (dialog);
+ g_return_if_fail ((replace_entry_text) != NULL);
+
+ match_case = pluma_search_dialog_get_match_case (dialog);
+ entire_word = pluma_search_dialog_get_entire_word (dialog);
+
+ PLUMA_SEARCH_SET_CASE_SENSITIVE (flags, match_case);
+ PLUMA_SEARCH_SET_ENTIRE_WORD (flags, entire_word);
+
+ count = pluma_document_replace_all (doc,
+ search_entry_text,
+ replace_entry_text,
+ flags);
+
+ if (count > 0)
+ {
+ text_found (window, count);
+ }
+ else
+ {
+ text_not_found (window, search_entry_text);
+ }
+
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
+ PLUMA_SEARCH_DIALOG_REPLACE_RESPONSE,
+ FALSE);
+}
+
+static void
+search_dialog_response_cb (PlumaSearchDialog *dialog,
+ gint response_id,
+ PlumaWindow *window)
+{
+ pluma_debug (DEBUG_COMMANDS);
+
+ switch (response_id)
+ {
+ case PLUMA_SEARCH_DIALOG_FIND_RESPONSE:
+ do_find (dialog, window);
+ break;
+ case PLUMA_SEARCH_DIALOG_REPLACE_RESPONSE:
+ do_replace (dialog, window);
+ break;
+ case PLUMA_SEARCH_DIALOG_REPLACE_ALL_RESPONSE:
+ do_replace_all (dialog, window);
+ break;
+ default:
+ last_search_data_store_position (dialog);
+ gtk_widget_hide (GTK_WIDGET (dialog));
+ }
+}
+
+static gboolean
+search_dialog_delete_event_cb (GtkWidget *widget,
+ GdkEventAny *event,
+ gpointer user_data)
+{
+ pluma_debug (DEBUG_COMMANDS);
+
+ /* prevent destruction */
+ return TRUE;
+}
+
+static void
+search_dialog_destroyed (PlumaWindow *window,
+ PlumaSearchDialog *dialog)
+{
+ pluma_debug (DEBUG_COMMANDS);
+
+ g_object_set_data (G_OBJECT (window),
+ PLUMA_SEARCH_DIALOG_KEY,
+ NULL);
+ g_object_set_data (G_OBJECT (dialog),
+ PLUMA_LAST_SEARCH_DATA_KEY,
+ NULL);
+}
+
+static GtkWidget *
+create_dialog (PlumaWindow *window, gboolean show_replace)
+{
+ GtkWidget *dialog;
+
+ dialog = pluma_search_dialog_new (GTK_WINDOW (window), show_replace);
+
+ g_signal_connect (dialog,
+ "response",
+ G_CALLBACK (search_dialog_response_cb),
+ window);
+ g_signal_connect (dialog,
+ "delete-event",
+ G_CALLBACK (search_dialog_delete_event_cb),
+ NULL);
+
+ g_object_set_data (G_OBJECT (window),
+ PLUMA_SEARCH_DIALOG_KEY,
+ dialog);
+
+ g_object_weak_ref (G_OBJECT (dialog),
+ (GWeakNotify) search_dialog_destroyed,
+ window);
+
+ return dialog;
+}
+
+void
+_pluma_cmd_search_find (GtkAction *action,
+ PlumaWindow *window)
+{
+ gpointer data;
+ GtkWidget *search_dialog;
+ PlumaDocument *doc;
+ gboolean selection_exists;
+ gchar *find_text = NULL;
+ gint sel_len;
+
+ pluma_debug (DEBUG_COMMANDS);
+
+ data = g_object_get_data (G_OBJECT (window), PLUMA_SEARCH_DIALOG_KEY);
+
+ if (data == NULL)
+ {
+ search_dialog = create_dialog (window, FALSE);
+ }
+ else
+ {
+ g_return_if_fail (PLUMA_IS_SEARCH_DIALOG (data));
+
+ search_dialog = GTK_WIDGET (data);
+
+ /* turn the dialog into a find dialog if needed */
+ if (pluma_search_dialog_get_show_replace (PLUMA_SEARCH_DIALOG (search_dialog)))
+ pluma_search_dialog_set_show_replace (PLUMA_SEARCH_DIALOG (search_dialog),
+ FALSE);
+ }
+
+ doc = pluma_window_get_active_document (window);
+ g_return_if_fail (doc != NULL);
+
+ selection_exists = get_selected_text (GTK_TEXT_BUFFER (doc),
+ &find_text,
+ &sel_len);
+
+ if (selection_exists && find_text != NULL && sel_len < 80)
+ {
+ pluma_search_dialog_set_search_text (PLUMA_SEARCH_DIALOG (search_dialog),
+ find_text);
+ g_free (find_text);
+ }
+ else
+ {
+ g_free (find_text);
+ }
+
+ gtk_widget_show (search_dialog);
+ last_search_data_restore_position (PLUMA_SEARCH_DIALOG (search_dialog));
+ pluma_search_dialog_present_with_time (PLUMA_SEARCH_DIALOG (search_dialog),
+ GDK_CURRENT_TIME);
+}
+
+void
+_pluma_cmd_search_replace (GtkAction *action,
+ PlumaWindow *window)
+{
+ gpointer data;
+ GtkWidget *replace_dialog;
+ PlumaDocument *doc;
+ gboolean selection_exists;
+ gchar *find_text = NULL;
+ gint sel_len;
+
+ pluma_debug (DEBUG_COMMANDS);
+
+ data = g_object_get_data (G_OBJECT (window), PLUMA_SEARCH_DIALOG_KEY);
+
+ if (data == NULL)
+ {
+ replace_dialog = create_dialog (window, TRUE);
+ }
+ else
+ {
+ g_return_if_fail (PLUMA_IS_SEARCH_DIALOG (data));
+
+ replace_dialog = GTK_WIDGET (data);
+
+ /* turn the dialog into a find dialog if needed */
+ if (!pluma_search_dialog_get_show_replace (PLUMA_SEARCH_DIALOG (replace_dialog)))
+ pluma_search_dialog_set_show_replace (PLUMA_SEARCH_DIALOG (replace_dialog),
+ TRUE);
+ }
+
+ doc = pluma_window_get_active_document (window);
+ g_return_if_fail (doc != NULL);
+
+ selection_exists = get_selected_text (GTK_TEXT_BUFFER (doc),
+ &find_text,
+ &sel_len);
+
+ if (selection_exists && find_text != NULL && sel_len < 80)
+ {
+ pluma_search_dialog_set_search_text (PLUMA_SEARCH_DIALOG (replace_dialog),
+ find_text);
+ g_free (find_text);
+ }
+ else
+ {
+ g_free (find_text);
+ }
+
+ gtk_widget_show (replace_dialog);
+ last_search_data_restore_position (PLUMA_SEARCH_DIALOG (replace_dialog));
+ pluma_search_dialog_present_with_time (PLUMA_SEARCH_DIALOG (replace_dialog),
+ GDK_CURRENT_TIME);
+}
+
+static void
+do_find_again (PlumaWindow *window,
+ gboolean backward)
+{
+ PlumaView *active_view;
+ gboolean wrap_around = TRUE;
+ gpointer data;
+
+ active_view = pluma_window_get_active_view (window);
+ g_return_if_fail (active_view != NULL);
+
+ data = g_object_get_data (G_OBJECT (window), PLUMA_SEARCH_DIALOG_KEY);
+
+ if (data != NULL)
+ wrap_around = pluma_search_dialog_get_wrap_around (PLUMA_SEARCH_DIALOG (data));
+
+ run_search (active_view,
+ wrap_around,
+ backward);
+}
+
+void
+_pluma_cmd_search_find_next (GtkAction *action,
+ PlumaWindow *window)
+{
+ pluma_debug (DEBUG_COMMANDS);
+
+ do_find_again (window, FALSE);
+}
+
+void
+_pluma_cmd_search_find_prev (GtkAction *action,
+ PlumaWindow *window)
+{
+ pluma_debug (DEBUG_COMMANDS);
+
+ do_find_again (window, TRUE);
+}
+
+void
+_pluma_cmd_search_clear_highlight (GtkAction *action,
+ PlumaWindow *window)
+{
+ PlumaDocument *doc;
+
+ pluma_debug (DEBUG_COMMANDS);
+
+ doc = pluma_window_get_active_document (window);
+ pluma_document_set_search_text (PLUMA_DOCUMENT (doc),
+ "",
+ PLUMA_SEARCH_DONT_SET_FLAGS);
+}
+
+void
+_pluma_cmd_search_goto_line (GtkAction *action,
+ PlumaWindow *window)
+{
+ PlumaView *active_view;
+
+ pluma_debug (DEBUG_COMMANDS);
+
+ active_view = pluma_window_get_active_view (window);
+ if (active_view == NULL)
+ return;
+
+ /* Focus the view if needed: we need to focus the view otherwise
+ activating the binding for goto line has no effect */
+ gtk_widget_grab_focus (GTK_WIDGET (active_view));
+
+
+ /* goto line is builtin in PlumaView, just activate
+ * the corrisponding binding.
+ */
+ gtk_bindings_activate (GTK_OBJECT (active_view),
+ GDK_i,
+ GDK_CONTROL_MASK);
+}
+
+void
+_pluma_cmd_search_incremental_search (GtkAction *action,
+ PlumaWindow *window)
+{
+ PlumaView *active_view;
+
+ pluma_debug (DEBUG_COMMANDS);
+
+ active_view = pluma_window_get_active_view (window);
+ if (active_view == NULL)
+ return;
+
+ /* Focus the view if needed: we need to focus the view otherwise
+ activating the binding for incremental search has no effect */
+ gtk_widget_grab_focus (GTK_WIDGET (active_view));
+
+ /* incremental search is builtin in PlumaView, just activate
+ * the corrisponding binding.
+ */
+ gtk_bindings_activate (GTK_OBJECT (active_view),
+ GDK_k,
+ GDK_CONTROL_MASK);
+}