Updated Spanish translation
[anjuta-git-plugin.git] / plugins / search / plugin.c
blobc9db86b478821b8065501c00f9e2a7ebd9c0d9cf
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 plugin.c
4 Copyright (C) 2000 Naba Kumar
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <libanjuta/interfaces/ianjuta-editor.h>
22 #include <libanjuta/interfaces/ianjuta-editor-selection.h>
23 #include <libanjuta/interfaces/ianjuta-document-manager.h>
24 #include <libanjuta/anjuta-shell.h>
25 #include <libanjuta/anjuta-debug.h>
27 #include <libegg/menu/egg-entry-action.h>
29 #include "plugin.h"
30 #include "search-replace.h"
31 #include "search-replace_backend.h"
32 #include "config.h"
34 #define UI_FILE PACKAGE_DATA_DIR"/ui/anjuta-search.ui"
35 #define ICON_FILE "anjuta-search.png"
37 /* Find next occurence of expression in Editor
38 Caching of FileBuffer might be useful here to improve performance
39 Returns: TRUE = found, FALSE = not found
42 static gboolean find_incremental(IAnjutaEditor* te, gchar* expression,
43 SearchDirection dir)
45 FileBuffer* fb = file_buffer_new_from_te (te);
46 SearchExpression* se = g_new0(SearchExpression, 1);
47 MatchInfo* info;
48 gboolean ret;
50 se->search_str = expression;
51 se->regex = FALSE;
52 se->greedy = FALSE;
53 se->ignore_case = TRUE;
54 se->whole_word = FALSE;
55 se->whole_line = FALSE;
56 se->word_start = FALSE;
57 se->no_limit = FALSE;
58 se->actions_max = 1;
59 se->re = NULL;
61 info = get_next_match(fb, dir, se);
63 if (info != NULL)
65 gboolean backward;
66 backward = dir == SD_BACKWARD?TRUE:FALSE;
67 ianjuta_editor_selection_set (IANJUTA_EDITOR_SELECTION (te),
68 info->pos, info->pos + info->len, backward, NULL);
69 ret = TRUE;
71 else
72 ret = FALSE;
74 match_info_free(info);
75 file_buffer_free(fb);
76 g_free(se);
78 return ret;
81 static void
82 on_find1_activate (GtkAction * action, gpointer user_data)
84 anjuta_search_replace_activate(FALSE, FALSE);
87 static void
88 on_find_and_replace1_activate (GtkAction * action, gpointer user_data)
90 anjuta_search_replace_activate(TRUE, FALSE);
93 static void
94 on_find_in_files1_activate (GtkAction * action, gpointer user_data)
96 anjuta_search_replace_activate(FALSE, TRUE);
99 /* *user_data : TRUE=Forward False=Backward */
100 static void
101 on_findnext1_activate (GtkAction * action, gpointer user_data)
103 search_replace_next();
106 static void
107 on_findprevious1_activate (GtkAction * action, gpointer user_data)
109 search_replace_previous();
112 static void
113 on_enterselection (GtkAction * action, gpointer user_data)
115 GtkAction *entry_action;
116 AnjutaUI* ui;
117 IAnjutaEditor *te;
118 IAnjutaDocumentManager* docman;
119 SearchPlugin* plugin;
120 gchar *selectionText = NULL;
121 GSList *proxies;
123 plugin = ANJUTA_PLUGIN_SEARCH (user_data);
124 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN(plugin)->shell, NULL);
125 docman = anjuta_shell_get_interface(ANJUTA_PLUGIN(plugin)->shell,
126 IAnjutaDocumentManager, NULL);
127 te = ianjuta_document_manager_get_current_editor(docman, NULL);
128 if (!te) return;
130 entry_action = anjuta_ui_get_action (ui, "ActionGroupSearch",
131 "ActionEditSearchEntry");
132 g_return_if_fail (EGG_IS_ENTRY_ACTION (entry_action));
134 selectionText = ianjuta_editor_selection_get (IANJUTA_EDITOR_SELECTION (te),
135 NULL);
136 if (selectionText != NULL && selectionText[0] != '\0')
138 egg_entry_action_set_text (EGG_ENTRY_ACTION (entry_action), selectionText);
140 /* Which proxy to focus? For now just focus the first one */
141 proxies = gtk_action_get_proxies (GTK_ACTION (entry_action));
142 if (proxies)
144 GtkWidget *child;
145 child = gtk_bin_get_child (GTK_BIN (proxies->data));
146 gtk_widget_grab_focus (GTK_WIDGET (child));
148 g_free (selectionText);
151 static void
152 on_prev_occur(GtkAction * action, gpointer user_data)
154 IAnjutaEditor* te;
155 IAnjutaDocumentManager *docman;
156 SearchPlugin *plugin;
157 gint return_;
158 gchar *buffer = NULL;
160 plugin = ANJUTA_PLUGIN_SEARCH (user_data);
161 docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
162 IAnjutaDocumentManager, NULL);
163 te = ianjuta_document_manager_get_current_editor (docman, NULL);
164 if(!te) return;
165 if ((buffer = ianjuta_editor_selection_get (IANJUTA_EDITOR_SELECTION (te), NULL)))
167 g_strstrip(buffer);
168 if ('\0' == *buffer)
170 g_free(buffer);
171 buffer = NULL;
174 if (NULL == buffer)
176 buffer = ianjuta_editor_get_current_word(te, NULL);
177 if (!buffer)
178 return;
180 return_= find_incremental(te, buffer, SD_BACKWARD);
182 g_free(buffer);
185 static void
186 on_next_occur(GtkAction * action, gpointer user_data)
188 IAnjutaEditor* te;
189 IAnjutaDocumentManager *docman;
190 SearchPlugin *plugin;
191 gint return_;
192 gchar *buffer = NULL;
194 plugin = ANJUTA_PLUGIN_SEARCH (user_data);
195 docman = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
196 IAnjutaDocumentManager, NULL);
197 te = ianjuta_document_manager_get_current_editor (docman, NULL);
198 if(!te) return;
199 if ((buffer = ianjuta_editor_selection_get (IANJUTA_EDITOR_SELECTION (te), NULL)))
201 g_strstrip(buffer);
202 if ('\0' == *buffer)
204 g_free(buffer);
205 buffer = NULL;
208 if (NULL == buffer)
210 buffer = ianjuta_editor_get_current_word(te, NULL);
211 if (!buffer)
212 return;
214 return_= find_incremental(te, buffer, SD_FORWARD);
216 g_free(buffer);
219 /* Incremental search */
221 typedef struct
223 gint pos;
224 gboolean wrap;
225 gboolean end;
226 gchar* last;
228 } IncrementalSearch;
230 static void
231 on_incremental_entry_key_press (GtkWidget *entry, GdkEventKey *event,
232 SearchPlugin *plugin)
234 if (event->keyval == GDK_Escape)
236 IAnjutaEditor *te;
238 te = ianjuta_document_manager_get_current_editor(plugin->docman, NULL);
239 if (te)
240 ianjuta_editor_grab_focus (te, NULL);
244 static void on_toolbar_find_start_over(GtkAction * action, gpointer user_data);
246 /* FIXME: Wrapping does not yet work */
248 static void
249 on_toolbar_find_clicked (GtkAction *action, gpointer user_data)
251 const gchar *string;
252 gchar* expression;
253 gint ret;
254 IAnjutaEditor *te;
255 IAnjutaDocumentManager *docman;
256 SearchPlugin *plugin;
257 IncrementalSearch *search_params;
258 gboolean search_wrap = FALSE;
259 AnjutaStatus *status;
260 AnjutaUI* ui;
262 plugin = ANJUTA_PLUGIN_SEARCH (user_data);
263 docman = plugin->docman;
264 te = ianjuta_document_manager_get_current_editor(docman, NULL);
265 ui = anjuta_shell_get_ui (ANJUTA_PLUGIN(plugin)->shell, NULL);
267 if (!te)
268 return;
270 search_params = g_object_get_data (G_OBJECT (te), "incremental_search");
271 if (!search_params)
273 search_params = g_new0 (IncrementalSearch, 1);
274 g_object_set_data_full (G_OBJECT (te), "incremental_search",
275 search_params, (GDestroyNotify)g_free);
277 if (EGG_IS_ENTRY_ACTION (action))
279 string = egg_entry_action_get_text (EGG_ENTRY_ACTION (action));
281 else
283 GtkAction *entry_action;
284 entry_action = anjuta_ui_get_action (ui,
285 "ActionGroupSearch",
286 "ActionEditSearchEntry");
287 g_return_if_fail (EGG_IS_ENTRY_ACTION (entry_action));
288 string = egg_entry_action_get_text (EGG_ENTRY_ACTION (entry_action));
290 if (search_params->pos >= 0 && search_params->wrap)
292 /* If incremental search wrap requested, so wrap it. */
293 search_wrap = TRUE;
296 expression = g_strdup(string);
297 if (search_params->end &&
298 g_str_has_prefix(expression, search_params->last))
300 g_free(expression);
301 return;
303 else
304 search_params->end = FALSE;
305 if (search_wrap)
307 ianjuta_editor_goto_position(te, 0, NULL);
308 ret = find_incremental(te, expression, SD_FORWARD);
309 search_params->wrap = FALSE;
311 else
313 ret = find_incremental(te, expression, SD_FORWARD);
316 status = anjuta_shell_get_status (ANJUTA_PLUGIN (user_data)->shell, NULL);
318 if (ret == FALSE)
320 if (search_params->pos < 0)
322 GtkWindow *parent;
323 GtkWidget *dialog;
325 parent = GTK_WINDOW (ANJUTA_PLUGIN(user_data)->shell);
326 dialog = gtk_message_dialog_new (parent,
327 GTK_DIALOG_DESTROY_WITH_PARENT,
328 GTK_MESSAGE_QUESTION,
329 GTK_BUTTONS_YES_NO,
330 _("No matches. Wrap search around the document?"));
331 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES)
332 on_toolbar_find_start_over (action, user_data);
333 gtk_widget_destroy (dialog);
335 else
337 if (search_wrap == FALSE)
339 anjuta_status_push(status,
340 _("Incremental search for '%s' failed. Press Enter or click Find to continue searching at the top."),
341 string);
342 search_params->wrap = 1;
343 gdk_beep();
345 else
347 search_params->end = TRUE;
348 anjuta_status_push (status, _("Incremental search for '%s' (continued at top) failed."),
349 string);
350 search_params->wrap = 0;
354 else
355 anjuta_status_clear_stack (status);
356 g_free(search_params->last);
357 search_params->last = expression;
360 static void
361 on_toolbar_find_start_over (GtkAction * action, gpointer user_data)
363 IAnjutaEditor *te;
364 IAnjutaDocumentManager *docman;
365 SearchPlugin *plugin;
367 plugin = ANJUTA_PLUGIN_SEARCH (user_data);
368 docman = plugin->docman;
369 te = ianjuta_document_manager_get_current_editor(docman, NULL);
371 /* search from doc start */
372 ianjuta_editor_goto_position(te, 0, NULL);
373 on_toolbar_find_clicked (action, user_data);
376 static gboolean
377 on_toolbar_find_incremental_start (GtkAction *action, gpointer user_data)
379 IAnjutaEditor *te;
380 IAnjutaDocumentManager *docman;
381 SearchPlugin *plugin;
382 IncrementalSearch *search_params;
383 GSList *entries, *node;
384 static GHashTable *entries_connected = NULL;
386 plugin = ANJUTA_PLUGIN_SEARCH (user_data);
387 docman = plugin->docman;
388 te = ianjuta_document_manager_get_current_editor(docman, NULL);
390 if (!te) return FALSE;
392 /* Make sure we set up escape for getting out the focus to the editor */
393 if (entries_connected == NULL)
395 entries_connected = g_hash_table_new (g_direct_hash, g_direct_equal);
397 entries = gtk_action_get_proxies (action);
398 node = entries;
399 while (node)
401 GtkWidget *entry;
402 entry = GTK_WIDGET (node->data);
403 if (!g_hash_table_lookup (entries_connected, entry))
405 g_signal_connect (G_OBJECT (entry), "key-press-event",
406 G_CALLBACK (on_incremental_entry_key_press),
407 plugin);
408 g_hash_table_insert (entries_connected, entry, entry);
410 node = g_slist_next (node);
413 search_params = g_object_get_data (G_OBJECT (te), "incremental_search");
414 if (!search_params)
416 search_params = g_new0 (IncrementalSearch, 1);
417 g_object_set_data_full (G_OBJECT (te), "incremental_search",
418 search_params, (GDestroyNotify)g_free);
420 /* Prepare to begin incremental search */
421 search_params->pos = ianjuta_editor_get_position(te, NULL);
422 search_params->wrap = FALSE;
423 return FALSE;
426 static gboolean
427 on_toolbar_find_incremental_end (GtkAction *action, gpointer user_data)
429 IAnjutaEditor *te;
430 IAnjutaDocumentManager *docman;
431 SearchPlugin *plugin;
432 IncrementalSearch *search_params;
433 AnjutaStatus *status;
435 plugin = ANJUTA_PLUGIN_SEARCH (user_data);
436 docman = plugin->docman;
437 te = ianjuta_document_manager_get_current_editor(docman, NULL);
439 if (!te)
440 return FALSE;
442 status = anjuta_shell_get_status (ANJUTA_PLUGIN (user_data)->shell, NULL);
443 anjuta_status_clear_stack (status);
445 search_params = g_object_get_data (G_OBJECT (te), "incremental_search");
446 if (search_params)
448 search_params->pos = -1;
449 search_params->wrap = FALSE;
451 return FALSE;
454 static void
455 on_toolbar_find_incremental (GtkAction *action, gpointer user_data)
457 const gchar *entry_text;
458 IAnjutaEditor *te;
459 IAnjutaDocumentManager *docman;
460 SearchPlugin *plugin;
461 IncrementalSearch *search_params;
463 plugin = ANJUTA_PLUGIN_SEARCH (user_data);
464 docman = plugin->docman;
465 te = ianjuta_document_manager_get_current_editor(docman, NULL);
467 if (!te)
468 return;
470 search_params = g_object_get_data (G_OBJECT (te), "incremental_search");
471 if (!search_params)
473 search_params = g_new0 (IncrementalSearch, 1);
474 g_object_set_data_full (G_OBJECT (te), "incremental_search",
475 search_params, (GDestroyNotify)g_free);
478 if (search_params->pos < 0)
479 return;
481 if (EGG_IS_ENTRY_ACTION (action))
483 entry_text = egg_entry_action_get_text (EGG_ENTRY_ACTION (action));
485 else
487 AnjutaUI *ui;
488 GtkAction *entry_action;
490 ui = ANJUTA_UI (g_object_get_data (G_OBJECT (user_data), "ui"));
491 entry_action = anjuta_ui_get_action (ui, "ActionGroupSearch",
492 "ActionEditSearchEntry");
493 g_return_if_fail (EGG_IS_ENTRY_ACTION (entry_action));
494 entry_text =
495 egg_entry_action_get_text (EGG_ENTRY_ACTION (entry_action));
497 if (!entry_text || strlen(entry_text) < 1) return;
499 ianjuta_editor_goto_position(te, search_params->pos, NULL);
500 on_toolbar_find_clicked (NULL, user_data);
503 static GtkActionEntry actions_search[] = {
504 { "ActionMenuEditSearch", NULL, N_("_Search"), NULL, NULL, NULL},
505 { "ActionEditSearchFind", GTK_STOCK_FIND, N_("_Find..."), "<control>f",
506 N_("Search for a string or regular expression in the editor"),
507 G_CALLBACK (on_find1_activate)},
508 { "ActionEditSearchFindNext", GTK_STOCK_FIND, N_("Find _Next"), "<control>g",
509 N_("Repeat the last Find command"),
510 G_CALLBACK (on_findnext1_activate)},
511 { "ActionEditSearchFindPrevious", GTK_STOCK_FIND, N_("Find _Previous"),
512 "<control><shift>g",
513 N_("Repeat the last Find command"),
514 G_CALLBACK (on_findprevious1_activate)},
515 { "ActionEditSearchReplace", GTK_STOCK_FIND_AND_REPLACE, N_("Find and R_eplace..."),
516 "<control>h",
517 N_("Search for and replace a string or regular expression with another string"),
518 G_CALLBACK (on_find_and_replace1_activate)},
519 { "ActionEditAdvancedSearch", GTK_STOCK_FIND, N_("Advanced Search And Replace"),
520 NULL, N_("New advance search And replace stuff"),
521 G_CALLBACK (on_find1_activate)},
522 { "ActionEditSearchSelectionISearch", NULL, N_("_Enter Selection/I-Search"),
523 "<control>e",
524 N_("Enter the selected text as the search target"),
525 G_CALLBACK (on_enterselection)},
526 { "ActionEditSearchInFiles", NULL, N_("Fin_d in Files..."), "<shift><control>f",
527 N_("Search for a string in multiple files or directories"),
528 G_CALLBACK (on_find_in_files1_activate)},
529 { "ActionEditGotoOccuranceNext", GTK_STOCK_JUMP_TO,
530 N_("Ne_xt Occurrence"), NULL,
531 N_("Find the next occurrence of current word"),
532 G_CALLBACK (on_next_occur)},
533 { "ActionEditGotoOccurancePrev",GTK_STOCK_JUMP_TO,
534 N_("Pre_vious Occurrence"), NULL,
535 N_("Find the previous occurrence of current word"),
536 G_CALLBACK (on_prev_occur)},
539 gpointer parent_class;
541 static gboolean
542 activate_plugin (AnjutaPlugin *plugin)
544 AnjutaUI *ui;
545 GtkActionGroup* group;
546 GtkAction* action;
547 SearchPlugin* splugin = ANJUTA_PLUGIN_SEARCH (plugin);
548 IAnjutaDocumentManager* docman = anjuta_shell_get_interface(ANJUTA_PLUGIN(plugin)->shell,
549 IAnjutaDocumentManager, NULL);
552 ui = anjuta_shell_get_ui (plugin->shell, NULL);
553 anjuta_ui_add_action_group_entries (ui, "ActionGroupSearch",
554 _("Searching..."),
555 actions_search,
556 G_N_ELEMENTS (actions_search),
557 GETTEXT_PACKAGE, TRUE, plugin);
559 group = gtk_action_group_new ("ActionGroupSearch");
560 action = g_object_new (EGG_TYPE_ENTRY_ACTION,
561 "name", "ActionEditSearchEntry",
562 "label", _("Search"),
563 "tooltip", _("Incremental search"),
564 "stock_id", GTK_STOCK_JUMP_TO,
565 "width", 150,
566 NULL);
567 g_assert (EGG_IS_ENTRY_ACTION (action));
568 g_signal_connect (action, "activate",
569 G_CALLBACK (on_toolbar_find_clicked), plugin);
570 g_signal_connect (action, "changed",
571 G_CALLBACK (on_toolbar_find_incremental), plugin);
572 g_signal_connect (action, "focus-in",
573 G_CALLBACK (on_toolbar_find_incremental_start), plugin);
574 g_signal_connect (action, "focus-out",
575 G_CALLBACK (on_toolbar_find_incremental_end), plugin);
576 gtk_action_group_add_action (group, action);
578 /* FIXME: For some reason, if can_customize is set TRUE, AnjutaUI
579 * can't find this action
581 anjuta_ui_add_action_group(ui, "ActionGroupSearch", _("Search Toolbar"),
582 group, TRUE);
583 g_object_set (G_OBJECT (action), "sensitive", TRUE, NULL);
586 splugin->uiid = anjuta_ui_merge (ui, UI_FILE);
587 splugin->docman = docman;
588 search_and_replace_init(docman);
590 return TRUE;
593 static gboolean
594 deactivate_plugin (AnjutaPlugin *plugin)
597 return TRUE;
600 static void
601 dispose (GObject *obj)
603 //SearchPlugin *plugin = ANJUTA_PLUGIN_SEARCH (obj);
605 GNOME_CALL_PARENT (G_OBJECT_CLASS, dispose, (obj));
608 static void
609 search_plugin_instance_init (GObject *obj)
611 //SearchPlugin *plugin = ANJUTA_PLUGIN_SEARCH (obj);
614 static void
615 search_plugin_class_init (GObjectClass *klass)
617 AnjutaPluginClass *plugin_class = ANJUTA_PLUGIN_CLASS (klass);
619 parent_class = g_type_class_peek_parent (klass);
621 plugin_class->activate = activate_plugin;
622 plugin_class->deactivate = deactivate_plugin;
623 klass->dispose = dispose;
625 ANJUTA_PLUGIN_BEGIN (SearchPlugin, search_plugin);
626 ANJUTA_PLUGIN_END;
627 ANJUTA_SIMPLE_PLUGIN (SearchPlugin, search_plugin);