Updated Spanish translation
[anjuta-git-plugin.git] / plugins / search / search-replace.c
blob6e62f07c2b351c425496161db4707930f6886205
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
3 /*
4 ** search-replace.c: Generic Search and Replace
5 ** Author: Biswapesh Chattopadhyay
6 */
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <ctype.h>
17 #include <string.h>
18 #include <dirent.h>
19 #include <fnmatch.h>
20 #include <fcntl.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
24 #include <gnome.h>
25 #include <glade/glade.h>
27 #include <libanjuta/anjuta-utils.h>
28 #include <libanjuta/anjuta-plugin.h>
29 #include <libanjuta/anjuta-debug.h>
30 #include <libanjuta/interfaces/ianjuta-message-manager.h>
31 #include <libanjuta/interfaces/ianjuta-message-view.h>
32 #include <libanjuta/interfaces/ianjuta-editor.h>
33 #include <libanjuta/interfaces/ianjuta-editor-selection.h>
34 #include <libanjuta/interfaces/ianjuta-markable.h>
35 #include <libanjuta/interfaces/ianjuta-bookmark.h>
36 #include <libanjuta/interfaces/ianjuta-indicable.h>
38 #include <libegg/menu/egg-entry-action.h>
40 #include "search-replace_backend.h"
41 #include "search-replace.h"
42 #include "search_preferences.h"
44 #include <libanjuta/interfaces/ianjuta-project-manager.h>
45 #include <glib/gi18n.h>
47 #define GLADE_FILE_SEARCH_REPLACE PACKAGE_DATA_DIR"/glade/anjuta-search.glade"
49 /* LibGlade's auto-signal-connect will connect to these signals.
50 * Do not declare them static.
52 gboolean
53 on_search_dialog_key_press_event(GtkWidget *widget, GdkEventKey *event,
54 gpointer user_data);
55 void on_search_match_whole_word_toggled (GtkToggleButton *togglebutton,
56 gpointer user_data);
57 void on_search_match_whole_line_toggled (GtkToggleButton *togglebutton,
58 gpointer user_data);
59 void on_search_match_word_start_toggled (GtkToggleButton *togglebutton,
60 gpointer user_data);
61 gboolean on_search_replace_delete_event(GtkWidget *window, GdkEvent *event,
62 gboolean user_data);
63 void on_replace_regex_toggled (GtkToggleButton *togglebutton, gpointer user_data);
64 void on_search_regex_toggled (GtkToggleButton *togglebutton, gpointer user_data);
65 void on_search_action_changed (GtkComboBox *combo, gpointer user_data);
66 void on_search_target_changed(GtkComboBox *combo, gpointer user_data);
67 void on_search_expression_changed(GtkComboBox *combo, gpointer user_data);
68 void on_actions_no_limit_clicked(GtkButton *button, gpointer user_data);
69 void on_search_button_close_clicked(GtkButton *button, gpointer user_data);
70 void on_search_button_close_clicked(GtkButton *button, gpointer user_data);
71 void on_search_button_help_clicked(GtkButton *button, gpointer user_data);
72 void on_search_button_next_clicked(GtkButton *button, gpointer user_data);
73 void on_search_button_jump_clicked(GtkButton *button, gpointer user_data);
74 void on_search_expression_activate (GtkEditable *edit, gpointer user_data);
75 void on_search_button_save_clicked(GtkButton *button, gpointer user_data);
76 void on_search_button_stop_clicked(GtkButton *button, gpointer user_data);
78 void on_search_direction_changed (GtkComboBox *combo, gpointer user_data);
79 void on_search_full_buffer_toggled (GtkToggleButton *togglebutton,
80 gpointer user_data);
81 void on_search_forward_toggled (GtkToggleButton *togglebutton,
82 gpointer user_data);
83 void on_search_backward_toggled (GtkToggleButton *togglebutton,
84 gpointer user_data);
85 void on_setting_basic_search_toggled (GtkToggleButton *togglebutton,
86 gpointer user_data);
88 /* GUI dropdown option strings */
89 AnjutaUtilStringMap search_direction_strings[] = {
90 /* the order of these matters - it must match the order of the corresponding
91 radio buttons on another page */
92 {SD_BEGINNING, N_("Full Buffer")},
93 {SD_FORWARD, N_("Forward")},
94 {SD_BACKWARD, N_("Backward")},
95 {-1, NULL}
98 AnjutaUtilStringMap search_target_strings[] = {
99 {SR_BUFFER, N_("Current Buffer")},
100 {SR_SELECTION, N_("Current Selection")},
101 {SR_BLOCK, N_("Current Block")},
102 {SR_FUNCTION, N_("Current Function")},
103 {SR_OPEN_BUFFERS, N_("All Open Buffers")},
104 {SR_PROJECT, N_("All Project Files")},
105 /* {SR_VARIABLE, N_("Specify File List")},*/
106 {SR_FILES, N_("Specify File Patterns")},
107 {-1, NULL}
110 AnjutaUtilStringMap search_action_strings[] = {
111 {SA_SELECT, N_("Select next match")},
112 {SA_BOOKMARK, N_("Bookmark all matched lines")},
113 {SA_HIGHLIGHT, N_("Mark all matches")},
114 {SA_FIND_PANE, N_("List matches in find pane")},
115 {SA_REPLACE, N_("Replace next match")},
116 {SA_REPLACEALL, N_("Replace all matches")},
117 {-1, NULL}
121 typedef struct _SearchReplaceGUI
123 GladeXML *xml;
124 GtkWidget *dialog;
125 gboolean showing;
126 } SearchReplaceGUI;
129 static GladeWidget glade_widgets[] = {
130 /* CLOSE_BUTTON */
131 {GE_BUTTON, "button.close", NULL, NULL},
132 /* STOP_BUTTON */
133 {GE_BUTTON, "button.stop", NULL, NULL},
134 /* SEARCH_BUTTON */
135 {GE_BUTTON, "button.next", NULL, NULL},
136 /* JUMP_BUTTON */
137 {GE_BUTTON, "button.jump", NULL, NULL},
138 /* SEARCH_NOTEBOOK */
139 {GE_NONE, "search.notebook", NULL, NULL},
140 /* SEARCH_EXPR_FRAME */
141 {GE_NONE, "frame.search.expression", NULL, NULL},
142 /* SEARCH_TARGET_FRAME */
143 {GE_NONE, "frame.search.target", NULL, NULL},
144 /* SEARCH_VAR_FRAME */
145 {GE_NONE, "frame.search.var", NULL, NULL},
146 /* FILE_FILTER_FRAME */
147 {GE_NONE, "frame.file.filter", NULL, NULL},
148 /* FRAME_SEARCH_BASIC */
149 {GE_NONE, "frame.search.basic", NULL, NULL},
150 /* LABEL_REPLACE */
151 {GE_NONE, "label.replace", NULL, NULL},
152 /* SEARCH_STRING */
153 {GE_COMBO_ENTRY, "search.string.combo", NULL, NULL},
154 /* SEARCH_VAR */
155 {GE_COMBO_ENTRY, "search.var.combo", NULL, NULL},
156 /* MATCH_FILES */
157 {GE_COMBO_ENTRY, "file.filter.match.combo", NULL, NULL},
158 /* UNMATCH_FILES */
159 {GE_COMBO_ENTRY, "file.filter.unmatch.combo", NULL, NULL},
160 /* MATCH_DIRS */
161 {GE_COMBO_ENTRY, "dir.filter.match.combo", NULL, NULL},
162 /* UNMATCH_DIRS */
163 {GE_COMBO_ENTRY, "dir.filter.unmatch.combo", NULL, NULL},
164 /* REPLACE_STRING */
165 {GE_COMBO_ENTRY, "replace.string.combo", NULL, NULL},
166 /* ACTIONS_MAX */
167 {GE_TEXT, "actions.max", NULL, NULL},
168 /* SETTING_PREF_ENTRY */
169 {GE_TEXT, "setting.pref.entry", NULL, NULL},
170 /* SEARCH_REGEX */
171 {GE_BOOLEAN, "search.regex", NULL, NULL},
172 /* GREEDY */
173 {GE_BOOLEAN, "search.greedy", NULL, NULL},
174 /* IGNORE_CASE */
175 {GE_BOOLEAN, "search.ignore.case", NULL, NULL},
176 /* WHOLE_WORD */
177 {GE_BOOLEAN, "search.match.whole.word", NULL, NULL},
178 /* WORD_START */
179 {GE_BOOLEAN, "search.match.word.start", NULL, NULL},
180 /* WHOLE_LINE */
181 {GE_BOOLEAN, "search.match.whole.line", NULL, NULL},
182 /* IGNORE_HIDDEN_FILES */
183 {GE_BOOLEAN, "ignore.hidden.files", NULL, NULL},
184 /* IGNORE_BINARY_FILES */
185 {GE_BOOLEAN, "ignore.binary.files", NULL, NULL},
186 /* IGNORE_HIDDEN_DIRS */
187 {GE_BOOLEAN, "ignore.hidden.dirs", NULL, NULL},
188 /* SEARCH_RECURSIVE */
189 {GE_BOOLEAN, "search.dir.recursive", NULL, NULL},
190 /* REPLACE_REGEX */
191 {GE_BOOLEAN, "replace.regex", NULL, NULL},
192 /* ACTIONS_NO_LIMIT */
193 {GE_BOOLEAN, "actions.no_limit", NULL, NULL},
194 /* SEARCH_FULL_BUFFER */
195 {GE_BOOLEAN, "search.full_buffer", NULL, NULL},
196 /* SEARCH_FORWARD */
197 {GE_BOOLEAN, "search.forward", NULL, NULL},
198 /* SEARCH_BACKWARD */
199 {GE_BOOLEAN, "search.backward", NULL, NULL},
200 /* SEARCH_BASIC */
201 {GE_BOOLEAN, "search.basic", NULL, NULL},
202 /* SEARCH_STRING_COMBO */
203 {GE_COMBO, "search.string.combo", NULL, NULL},
204 /* SEARCH_TARGET_COMBO */
205 {GE_COMBO, "search.target.combo", search_target_strings, NULL},
206 /* SEARCH_ACTION_COMBO */
207 {GE_COMBO, "search.action.combo", search_action_strings, NULL},
208 /* SEARCH_VAR_COMBO */
209 {GE_COMBO, "search.var.combo", NULL, NULL},
210 /* MATCH_FILES_COMBO */
211 {GE_COMBO, "file.filter.match.combo", NULL, NULL},
212 /* UNMATCH_FILES_COMBO */
213 {GE_COMBO, "file.filter.unmatch.combo", NULL, NULL},
214 /* MATCH_DIRS_COMBO */
215 {GE_COMBO, "dir.filter.match.combo", NULL, NULL},
216 /* UNMATCH_DIRS_COMBO */
217 {GE_COMBO, "dir.filter.unmatch.combo", NULL, NULL},
218 /* REPLACE_STRING_COMBO */
219 {GE_COMBO, "replace.string.combo", NULL, NULL},
220 /* SEARCH_DIRECTION_COMBO */
221 {GE_COMBO, "search.direction.combo", search_direction_strings, NULL},
222 /* SETTING_PREF_TREEVIEW */
223 {GE_NONE, "setting.pref.treeview", NULL, NULL},
224 {GE_NONE, NULL, NULL, NULL}
227 /***********************************************************/
229 static void
230 write_message_pane(IAnjutaMessageView* view, FileBuffer *fb, SearchEntry *se, MatchInfo *mi);
231 static gboolean on_message_clicked (GObject* object, gchar* message, gpointer data);
232 static void on_message_buffer_flush (IAnjutaMessageView *view, const gchar *one_line, gpointer data);
233 static void save_not_opened_files(FileBuffer *fb);
234 static gboolean replace_in_not_opened_files(FileBuffer *fb, MatchInfo *mi, gchar *repl_str);
235 static void search_set_action(SearchAction action);
236 static void search_set_target(SearchRangeType target);
237 static void search_set_direction(SearchDirection dir);
238 static void populate_value(GladeWidgetId id, gpointer val_ptr);
239 static void reset_flags(void);
240 static void reset_flags_and_search_button (void);
241 static void search_start_over (SearchDirection direction);
242 static void search_end_alert (gchar *string);
243 static void max_results_alert (void);
244 static void nb_results_alert (gint nb);
245 static void search_show_replace(gboolean hide);
246 static void modify_label_image_button(GladeWidgetId button_name, gchar *name, char *stock_image);
247 static void show_jump_button (gboolean show);
248 static gboolean create_dialog(void);
249 static void show_dialog(void);
250 static gboolean word_in_list(GList *list, gchar *word);
251 static GList* list_max_items(GList *list, guint nb_max);
252 static void search_update_combos (void);
253 static void replace_update_combos (void);
254 static void search_direction_changed(SearchDirection dir);
255 static void search_set_direction(SearchDirection dir);
256 static void search_set_toggle_direction(SearchDirection dir);
257 static void search_disconnect_set_toggle_connect(GladeWidgetId id,
258 GCallback function, gboolean active);
259 static void search_replace_next_previous(SearchDirection dir);
260 static void basic_search_toggled(void);
262 static SearchReplaceGUI *sg = NULL;
264 static SearchReplace *sr = NULL;
266 static gboolean flag_select = FALSE;
267 static gboolean interactive = FALSE;
268 static gboolean end_activity = FALSE;
269 static gboolean labels_translated = FALSE;
271 /***********************************************************/
273 void
274 search_and_replace_init (IAnjutaDocumentManager *dm)
276 sr = create_search_replace_instance (dm);
279 void
280 search_and_replace (void)
282 GList *entries;
283 GList *tmp;
284 SearchEntry *se;
285 FileBuffer *fb;
286 static MatchInfo *mi;
287 Search *s;
288 gint offset;
289 gint found_line = 0;
290 static gint os = 0;
291 gint nb_results;
292 static long start_sel = 0;
293 static long end_sel = 0;
294 static gchar *ch = NULL;
295 gchar *regx_pattern;
296 gboolean save_file = FALSE;
297 IAnjutaMessageManager* msgman;
298 IAnjutaMessageView* view = NULL;
299 gboolean backward;
301 g_return_if_fail(sr);
302 s = &(sr->search);
304 if (s->expr.search_str == NULL)
305 return;
307 entries = create_search_entries(s);
308 if (!entries)
309 return;
311 end_activity = FALSE;
312 backward = (s->range.direction == SD_BACKWARD);
314 search_update_combos ();
315 if (s->action == SA_REPLACE || s->action == SA_REPLACEALL)
316 replace_update_combos ();
318 if (SA_FIND_PANE == s->action)
320 gchar* name = g_strconcat(_("Find: "), s->expr.search_str, NULL);
321 AnjutaShell* shell;
322 g_object_get(G_OBJECT(sr->docman), "shell", &shell, NULL);
323 msgman = anjuta_shell_get_interface(shell,
324 IAnjutaMessageManager, NULL);
325 g_return_if_fail(msgman != NULL);
327 view = ianjuta_message_manager_get_view_by_name(msgman, name, NULL);
328 if (view == NULL)
330 // FIXME: Put a nice icon here:
331 view = ianjuta_message_manager_add_view(msgman, name,
332 GTK_STOCK_FIND_AND_REPLACE, NULL);
333 g_return_if_fail(view != NULL);
334 g_signal_connect (G_OBJECT(view), "buffer_flushed",
335 G_CALLBACK (on_message_buffer_flush), NULL);
336 g_signal_connect (G_OBJECT(view), "message_clicked",
337 G_CALLBACK (on_message_clicked), NULL);
339 else
340 ianjuta_message_view_clear(view, NULL);
341 ianjuta_message_manager_set_current_view(msgman, view, NULL);
343 gtk_widget_set_sensitive (sr_get_gladewidget(STOP_BUTTON)->widget, TRUE);
344 nb_results = 0;
345 for (tmp = entries; tmp && (nb_results <= s->expr.actions_max);
346 tmp = g_list_next(tmp))
348 if (end_activity)
349 break;
350 while(gtk_events_pending())
351 gtk_main_iteration();
353 /*to eliminate un-needed moves, when not bookmarking, this could be
354 current line i.e. ianjuta_editor_get_lineno (IANJUTA_EDITOR (se->te), NULL);
355 or sometimes last-line ? */
356 found_line = (s->action == SA_BOOKMARK) ? -1 : 1;
358 se = (SearchEntry *) tmp->data;
359 if (flag_select)
361 se->start_pos = start_sel;
362 se->end_pos = end_sel;
364 else
365 end_sel = se->end_pos;
366 if (SE_BUFFER == se->type)
367 fb = file_buffer_new_from_te(se->te);
368 else /* if (SE_FILE == se->type) */
369 fb = file_buffer_new_from_path(se->path, NULL, -1, 0);
371 if (fb)
373 fb->pos = se->start_pos;
374 offset = 0;
375 /* NO - there's no reason for user to expect existing marks to be removed.
376 And that can easily be done manually by user if so desired.
377 if (s->action == SA_BOOKMARK && IANJUTA_IS_MARKABLE (fb->te))
378 ianjuta_markable_delete_all_markers(IANJUTA_MARKABLE(fb->te),
379 IANJUTA_MARKABLE_LINEMARKER, NULL);
381 //FIXME enable clearing of marks by some means other than a 0-match search
382 if (s->action == SA_HIGHLIGHT)
383 ianjuta_indicable_clear (IANJUTA_INDICABLE(fb->te), NULL);
385 while (interactive ||
386 NULL != (mi = get_next_match(fb, s->range.direction, &(s->expr))))
388 if ((s->range.direction == SD_BACKWARD) && (mi->pos < se->end_pos))
389 break;
390 if ((s->range.direction != SD_BACKWARD) && ((se->end_pos != -1) &&
391 (mi->pos+mi->len > se->end_pos)))
392 break;
393 nb_results++;
394 if (nb_results > sr->search.expr.actions_max)
395 break;
397 /* NOTE - mi->line is "editor-style" 1-based, but some things
398 here use/expect 0-base, so adjustments are made as needed */
400 switch (s->action)
402 case SA_HIGHLIGHT:
403 found_line = mi->line;
405 if (fb->te == NULL)
406 fb->te =
407 IANJUTA_EDITOR (ianjuta_document_manager_get_current_document
408 (sr->docman, NULL));
410 if (IANJUTA_INDICABLE (fb->te))
411 /* end-location is correct for sourceview, 1-too-big for scintilla */
412 ianjuta_indicable_set (IANJUTA_INDICABLE(fb->te),
413 mi->pos, mi->pos + mi->len,
414 IANJUTA_INDICABLE_IMPORTANT, NULL);
415 break;
417 case SA_BOOKMARK:
418 if (found_line != mi->line)
420 found_line = mi->line;
422 if (fb->te == NULL)
423 fb->te =
424 IANJUTA_EDITOR (ianjuta_document_manager_get_current_document
425 (sr->docman, NULL));
427 if (IANJUTA_IS_MARKABLE (fb->te) &&
428 !ianjuta_markable_is_marker_set (
429 IANJUTA_MARKABLE(fb->te),
430 mi->line,
431 IANJUTA_MARKABLE_BOOKMARK,
432 NULL))
434 ianjuta_bookmark_toggle (IANJUTA_BOOKMARK(fb->te),
435 mi->line, FALSE, NULL);
438 break;
440 case SA_SELECT:
441 if (found_line != mi->line || fb->te == NULL)
443 if (fb->te)
444 ianjuta_editor_goto_line (fb->te, mi->line, NULL);
445 else
446 fb->te = ianjuta_document_manager_goto_file_line_mark
447 (sr->docman, fb->path, mi->line, FALSE, NULL);
448 found_line = mi->line;
451 IAnjutaIterable* start = ianjuta_editor_get_cell_iter (fb->te, mi->pos, NULL);
452 IAnjutaIterable* end = ianjuta_editor_get_cell_iter (fb->te, mi->pos + mi->len, NULL);
453 ianjuta_editor_selection_set(IANJUTA_EDITOR_SELECTION (fb->te),
454 start,
455 end,
456 NULL);
457 g_object_unref (start);
458 g_object_unref (end);
459 break;
462 case SA_FIND_PANE:
463 write_message_pane(view, fb, se, mi);
464 break;
466 case SA_REPLACE:
467 if (found_line != mi->line || fb->te == NULL)
469 if (fb->te)
470 ianjuta_editor_goto_line (fb->te, mi->line, NULL);
471 else
472 fb->te = ianjuta_document_manager_goto_file_line_mark
473 (sr->docman, fb->path, mi->line, FALSE, NULL);
474 found_line = mi->line;
477 if (!interactive)
479 IAnjutaIterable* start = ianjuta_editor_get_cell_iter (fb->te, mi->pos - offset, NULL);
480 IAnjutaIterable* end = ianjuta_editor_get_cell_iter (fb->te, mi->pos - offset + mi->len, NULL);
481 ianjuta_editor_selection_set(IANJUTA_EDITOR_SELECTION (fb->te),
482 start,
483 end,
484 NULL);
485 g_object_unref (start);
486 g_object_unref (end);
487 interactive = TRUE;
488 os = offset;
489 modify_label_image_button(SEARCH_BUTTON, _("Replace"),
490 GTK_STOCK_FIND_AND_REPLACE);
491 show_jump_button(TRUE);
492 if (sr->replace.regex && sr->search.expr.regex)
494 g_free (ch);
495 ch = regex_backref (mi, fb);
498 else
500 if (ch && sr->replace.regex && sr->search.expr.regex)
502 g_free (sr->replace.repl_str);
503 sr->replace.repl_str = g_strdup (ch);
504 g_free (ch);
505 ch = NULL;
508 IAnjutaIterable* start = ianjuta_editor_get_cell_iter (fb->te, mi->pos - os, NULL);
509 IAnjutaIterable* end = ianjuta_editor_get_cell_iter (fb->te, mi->pos + mi->len - os, NULL);
510 ianjuta_editor_selection_set(IANJUTA_EDITOR_SELECTION (fb->te),
511 start,
512 end,
513 NULL);
514 ianjuta_editor_selection_replace(IANJUTA_EDITOR_SELECTION (fb->te),
515 sr->replace.repl_str,
516 strlen(sr->replace.repl_str),
517 NULL);
518 g_object_unref (start);
519 g_object_unref (end);
521 if (se->direction != SD_BACKWARD)
522 offset += mi->len - (sr->replace.repl_str?strlen(sr->replace.repl_str):0);
524 interactive = FALSE;
526 break;
528 case SA_REPLACEALL:
529 if (sr->replace.regex && sr->search.expr.regex)
531 regx_pattern = sr->replace.repl_str; /* preserve for later matches */
532 sr->replace.repl_str = regex_backref (mi, fb);
534 else
535 regx_pattern = NULL;
536 if (fb->te == NULL) /* NON OPENED FILES */
538 if (replace_in_not_opened_files(fb, mi, sr->replace.repl_str))
539 save_file = TRUE;
541 else
543 IAnjutaIterable* start = ianjuta_editor_get_cell_iter (fb->te, mi->pos - offset, NULL);
544 IAnjutaIterable* end = ianjuta_editor_get_cell_iter (fb->te, mi->pos + mi->len - offset, NULL);
545 ianjuta_editor_selection_set(IANJUTA_EDITOR_SELECTION (fb->te),
546 start,
547 end,
548 NULL);
549 ianjuta_editor_selection_replace(IANJUTA_EDITOR_SELECTION (fb->te),
550 sr->replace.repl_str,
551 strlen(sr->replace.repl_str),
552 NULL);
553 g_object_unref (start);
554 g_object_unref (end);
556 if (se->direction != SD_BACKWARD)
557 offset += mi->len - (sr->replace.repl_str?strlen(sr->replace.repl_str):0);
558 if (regx_pattern)
560 g_free (sr->replace.repl_str);
561 sr->replace.repl_str = regx_pattern;
563 break;
565 default:
566 g_warning ("Not implemented - File %s - Line %d\n", __FILE__, __LINE__);
567 break;
568 } // switch
570 if (se->direction != SD_BACKWARD)
571 start_sel = mi->pos + mi->len - offset;
572 else
573 start_sel = mi->pos - offset;
575 if (SA_REPLACE != s->action || !interactive)
576 match_info_free(mi);
578 if (SA_SELECT == s->action ||
579 ((SA_REPLACE == s->action || SA_REPLACEALL == s->action) && interactive))
580 break;
581 } // while
582 /* NO - leave the current position unchanged when marking-all
583 if (nb_results > 0)
585 switch (s->action)
587 case SA_HIGHLIGHT:
588 case SA_BOOKMARK:
589 ianjuta_editor_goto_line (fb->te, found_line, NULL);
590 default:
591 break;
595 if (save_file)
597 save_not_opened_files (fb);
598 save_file = FALSE;
601 file_buffer_free (fb);
602 } // if (fb)
604 g_free (se->path);
605 g_free (se);
607 if (SA_SELECT == s->action && nb_results > 0)
608 break;
611 gtk_widget_set_sensitive (sr_get_gladewidget(STOP_BUTTON)->widget, FALSE);
613 if (s->range.type == SR_BLOCK || s->range.type == SR_FUNCTION ||
614 s->range.type == SR_SELECTION)
615 flag_select = TRUE;
617 if (entries)
618 g_list_free (entries);
620 if (s->action == SA_FIND_PANE)
622 ianjuta_message_view_append (view, IANJUTA_MESSAGE_VIEW_TYPE_INFO,
623 _("Search complete"), "", NULL);
626 if (nb_results == 0)
628 search_end_alert(sr->search.expr.search_str);
630 else if (nb_results > sr->search.expr.actions_max)
631 max_results_alert();
632 else if (s->action == SA_REPLACEALL)
633 nb_results_alert(nb_results);
635 if ((s->range.direction == SD_BEGINNING) &&
636 ((s->action == SA_SELECT) || (s->action == SA_REPLACE)) )
638 search_set_direction(SD_FORWARD);
642 static void
643 write_message_pane(IAnjutaMessageView* view, FileBuffer *fb, SearchEntry *se,
644 MatchInfo *mi)
646 gchar *match_line;
647 char buf[BUFSIZ];
648 gchar *tmp;
650 match_line = file_match_line_from_pos(fb, mi->pos);
652 if (SE_BUFFER == se->type)
654 /* DEBUG_PRINT ("FBPATH %s\n", fb->path); */
655 const gchar* filename = ianjuta_document_get_filename(IANJUTA_DOCUMENT(se->te), NULL);
656 tmp = g_strrstr(fb->path, "/");
657 tmp = g_strndup(fb->path, tmp + 1 -(fb->path));
658 snprintf(buf, BUFSIZ, "%s%s:%d:%s\n", tmp, filename,
659 mi->line, match_line);
660 g_free(tmp);
662 else /* if (SE_FILE == se->type) */
664 snprintf(buf, BUFSIZ, "%s:%d:%s\n", se->path, mi->line + 1, match_line);
666 g_free(match_line);
667 ianjuta_message_view_buffer_append (view, buf, NULL);
670 static void
671 on_message_buffer_flush (IAnjutaMessageView *view, const gchar *one_line,
672 gpointer data)
674 ianjuta_message_view_append (view, IANJUTA_MESSAGE_VIEW_TYPE_NORMAL,
675 one_line, "", NULL);
678 static gboolean
679 on_message_clicked (GObject* object, gchar* message, gpointer data)
681 gchar *ptr, *ptr2;
682 gchar *path, *nline;
683 gint line;
685 if (!(ptr = g_strstr_len(message, strlen(message), ":")) )
686 return FALSE;
687 path = g_strndup(message, ptr - message);
689 ptr++;
690 if (!(ptr2 = g_strstr_len(ptr, strlen(ptr), ":")) )
691 return FALSE;
692 nline = g_strndup(ptr, ptr2 - ptr);
693 line = atoi(nline);
695 ianjuta_document_manager_goto_file_line_mark (sr->docman, path, line, TRUE, NULL);
696 g_free(path);
697 g_free(nline);
698 return FALSE;
701 static void
702 save_not_opened_files(FileBuffer *fb)
704 FILE *fp;
706 fp = fopen(fb->path, "wb");
707 if (!fp)
708 return;
709 fwrite(fb->buf, fb->len, 1, fp);
710 fclose(fp);
713 static gboolean
714 replace_in_not_opened_files(FileBuffer *fb, MatchInfo *mi, gchar *repl_str)
716 gint l;
717 g_return_val_if_fail (repl_str != NULL, FALSE);
719 if (strlen(repl_str) > mi->len)
721 l = fb->len - mi->pos;
722 fb->len = fb->len + strlen(repl_str) - mi->len;
723 if ( (fb->buf = g_realloc(fb->buf, fb->len)) == NULL )
724 return FALSE;
725 memmove((fb->buf) + mi->pos + strlen(repl_str) - mi->len, fb->buf + mi->pos,l);
727 if (strlen(repl_str) < mi->len)
729 l = fb->len - mi->pos - mi->len ;
730 memmove((fb->buf) + mi->pos + strlen(repl_str), fb->buf + mi->pos + mi->len,l);
731 fb->len = fb->len + strlen(repl_str) - mi->len;
732 if ( (fb->buf = g_realloc(fb->buf, fb->len)) == NULL)
733 return FALSE;
736 for (l=0; l < strlen(repl_str); l++)
737 (fb->buf)[(mi->pos)+l] = repl_str [l];
739 return TRUE;
743 static void
744 search_replace_next_previous(SearchDirection dir)
746 SearchDirection save_direction;
747 SearchAction save_action;
748 SearchRangeType save_type;
750 if (sr)
752 save_action = sr->search.action;
753 save_type = sr->search.range.type;
754 save_direction = sr->search.range.direction;
755 sr->search.range.direction = dir;
756 if (save_type == SR_OPEN_BUFFERS || save_type == SR_PROJECT ||
757 save_type == SR_FILES)
758 sr->search.range.direction = SR_BUFFER;
759 sr->search.action = SA_SELECT;
761 search_and_replace();
763 sr->search.action = save_action;
764 sr->search.range.type = save_type;
765 sr->search.range.direction = save_direction;
767 else
769 DEBUG_PRINT ("sr null\n");
773 void
774 search_replace_next(void)
776 search_replace_next_previous(SD_FORWARD);
779 void
780 search_replace_previous(void)
782 search_replace_next_previous(SD_BACKWARD);
785 /****************************************************************/
787 GladeWidget *
788 sr_get_gladewidget(GladeWidgetId id)
790 return &glade_widgets[id];
793 static void
794 search_set_popdown_strings (GtkComboBoxEntry *combo, GList* strings)
796 GtkListStore *store;
797 gboolean init;
799 init = gtk_combo_box_get_model (GTK_COMBO_BOX(combo)) == NULL;
801 store = gtk_list_store_new (1, G_TYPE_STRING);
802 for (; strings != NULL; strings = g_list_next(strings))
804 GtkTreeIter iter;
806 gtk_list_store_append (store, &iter);
807 gtk_list_store_set (store, &iter, 0, strings->data, -1);
809 gtk_combo_box_set_model (GTK_COMBO_BOX(combo), GTK_TREE_MODEL (store));
810 g_object_unref (store);
812 if (init) gtk_combo_box_entry_set_text_column (combo, 0);
815 static void
816 search_set_popdown_map (GtkComboBox *combo, AnjutaUtilStringMap *map)
818 GtkListStore *store;
819 gboolean init;
820 gint i;
822 init = gtk_combo_box_get_model (combo) == NULL;
824 store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
825 for (i = 0; map[i].type != -1; ++i)
827 GtkTreeIter iter;
829 gtk_list_store_append (store, &iter);
830 gtk_list_store_set (store, &iter, 0, map[i].name, 1, map[i].type, -1);
832 gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
833 g_object_unref (store);
834 gtk_combo_box_set_active (combo, 0);
836 if (init)
838 GtkCellRenderer *cell;
840 cell = gtk_cell_renderer_text_new ();
841 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
842 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
843 "text", 0, NULL);
847 static void
848 search_select_item(GtkComboBox* combo, gint item)
850 GtkTreeModel *model;
851 GtkTreeIter iter;
852 gboolean search;
854 model = gtk_combo_box_get_model(combo);
856 /* Find item corresponding to command */
857 for (search = gtk_tree_model_get_iter_first(model, &iter); search;
858 gtk_tree_model_iter_next (model, &iter))
860 gint id;
862 gtk_tree_model_get (model, &iter, 1, &id, -1);
864 if (id == item)
866 /* Find command */
867 gtk_combo_box_set_active_iter(combo, &iter);
868 break;
874 static void
875 search_set_combo(GladeWidgetId id_combo, gint command)
877 GtkComboBox *combo;
879 combo = GTK_COMBO_BOX(sr_get_gladewidget(id_combo)->widget);
880 search_select_item (combo, command);
883 static void
884 search_set_action(SearchAction action)
886 search_set_combo(SEARCH_ACTION_COMBO, action);
889 static void
890 search_set_target(SearchRangeType target)
892 search_set_combo(SEARCH_TARGET_COMBO, target);
895 static void
896 search_set_direction(SearchDirection dir)
898 search_set_combo(SEARCH_DIRECTION_COMBO, dir);
901 static gint
902 search_get_item_combo(GtkComboBox *combo)
904 gint item;
905 GtkTreeModel *model;
906 GtkTreeIter iter;
907 gboolean sel;
909 sel = gtk_combo_box_get_active_iter (combo, &iter);
910 model = gtk_combo_box_get_model (combo);
911 gtk_tree_model_get (model, &iter, 1, &item, -1);
913 return item;
916 static gint
917 search_get_item_combo_name(GladeWidgetId id)
919 GtkWidget *combo = sr_get_gladewidget(id)->widget;
920 return search_get_item_combo(GTK_COMBO_BOX(combo));
923 static void
924 search_direction_changed(SearchDirection dir)
926 SearchEntryType tgt;
927 SearchAction act;
929 tgt = search_get_item_combo_name(SEARCH_TARGET_COMBO);
930 if (dir != SD_BEGINNING)
932 if (tgt == SR_OPEN_BUFFERS || tgt == SR_PROJECT
933 || tgt == SR_FILES)
934 search_set_target(SR_BUFFER);
936 else
938 if (tgt == SR_BUFFER ||tgt == SR_SELECTION || tgt == SR_BLOCK ||
939 tgt == SR_FUNCTION)
940 search_set_target(SR_BUFFER);
941 else
943 act = search_get_item_combo_name(SEARCH_ACTION_COMBO);
944 if (act == SA_SELECT)
945 search_set_action(SA_BOOKMARK);
946 if (act == SA_REPLACE)
947 search_set_action(SA_REPLACEALL);
952 static void
953 populate_value(GladeWidgetId id, gpointer val_ptr)
955 GladeWidget *gw;
957 g_return_if_fail(id && val_ptr);
959 gw = sr_get_gladewidget(id);
960 g_return_if_fail(gw);
961 switch(gw->type)
963 case GE_COMBO_ENTRY:
964 case GE_TEXT:
965 if (*((char **) val_ptr))
966 g_free(* ((char **) val_ptr));
967 *((char **) val_ptr) = gtk_editable_get_chars(
968 GTK_EDITABLE(gw->widget), 0, -1);
969 break;
970 case GE_BOOLEAN:
971 * ((gboolean *) val_ptr) = gtk_toggle_button_get_active(
972 GTK_TOGGLE_BUTTON(gw->widget));
973 break;
974 case GE_COMBO:
975 g_return_if_fail (gw->extra != NULL);
977 *((int *) val_ptr) = search_get_item_combo (GTK_COMBO_BOX(gw->widget));
978 break;
979 default:
980 g_warning("Bad option %d to populate_value", gw->type);
981 break;
985 static void
986 reset_flags(void)
988 flag_select = FALSE;
989 interactive = FALSE;
992 static void
993 reset_flags_and_search_button(void)
995 reset_flags();
996 if (sr->search.action != SA_REPLACEALL)
997 modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
999 else
1000 modify_label_image_button(SEARCH_BUTTON, _("Replace All"),
1001 GTK_STOCK_FIND_AND_REPLACE);
1003 show_jump_button(FALSE);
1006 static void
1007 search_start_over (SearchDirection direction)
1009 IAnjutaDocument* doc = ianjuta_document_manager_get_current_document(sr->docman,
1010 NULL);
1011 IAnjutaEditor *te = NULL;
1012 if (IANJUTA_IS_EDITOR(doc))
1013 te = IANJUTA_EDITOR(doc);
1014 long length;
1016 if (te)
1018 length = ianjuta_editor_get_length(te, NULL);;
1020 if (direction != SD_BACKWARD)
1021 /* search from doc start */
1022 ianjuta_editor_goto_position(te, 0, NULL);
1023 else
1024 /* search from doc end */
1025 ianjuta_editor_goto_position (te, length, NULL);
1029 static void
1030 search_end_alert(gchar *string)
1032 GtkWidget *dialog;
1034 if (sr->search.range.direction != SD_BEGINNING && !flag_select)
1036 // Ask if user wants to wrap around the doc
1037 // Dialog to be made HIG compliant.
1038 dialog = gtk_message_dialog_new (GTK_WINDOW (sg->dialog),
1039 GTK_DIALOG_DESTROY_WITH_PARENT,
1040 GTK_MESSAGE_QUESTION,
1041 GTK_BUTTONS_YES_NO,
1042 _("The match \"%s\" was not found. Wrap search around the document?"),
1043 string);
1045 gtk_dialog_set_default_response (GTK_DIALOG (dialog),
1046 GTK_RESPONSE_YES);
1047 g_signal_connect(G_OBJECT(dialog), "key-press-event",
1048 G_CALLBACK(on_search_dialog_key_press_event), NULL);
1049 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES)
1051 search_start_over (sr->search.range.direction);
1052 gtk_widget_destroy(dialog);
1053 reset_flags();
1054 search_and_replace ();
1055 return;
1058 else
1060 dialog = gtk_message_dialog_new(GTK_WINDOW (sg->dialog),
1061 GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
1062 _("The match \"%s\" was not found."),
1063 string);
1064 g_signal_connect(G_OBJECT(dialog), "key-press-event",
1065 G_CALLBACK(on_search_dialog_key_press_event), NULL);
1066 gtk_dialog_run(GTK_DIALOG(dialog));
1068 gtk_widget_destroy(dialog);
1069 reset_flags();
1072 static void
1073 max_results_alert(void)
1075 GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW (sg->dialog),
1076 GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
1077 _("The maximum number of results has been reached."));
1078 g_signal_connect(G_OBJECT(dialog), "key-press-event",
1079 G_CALLBACK(on_search_dialog_key_press_event), NULL);
1080 gtk_dialog_run(GTK_DIALOG(dialog));
1081 gtk_widget_destroy(dialog);
1082 reset_flags();
1085 static void
1086 nb_results_alert(gint nb)
1088 GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW (sg->dialog),
1089 GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
1090 _("%d matches have been replaced."), nb);
1091 g_signal_connect(G_OBJECT(dialog), "key-press-event",
1092 G_CALLBACK(on_search_dialog_key_press_event), NULL);
1093 gtk_dialog_run(GTK_DIALOG(dialog));
1094 gtk_widget_destroy(dialog);
1095 reset_flags();
1098 static void
1099 search_show_replace(gboolean hide)
1101 static GladeWidgetId hide_widgets[] = {
1102 REPLACE_REGEX, REPLACE_STRING_COMBO, LABEL_REPLACE
1104 int i;
1105 GtkWidget *widget;
1107 for (i=0; i < sizeof(hide_widgets)/sizeof(hide_widgets[0]); ++i)
1109 widget = sr_get_gladewidget(hide_widgets[i])->widget;
1110 if (NULL != widget)
1112 if (hide)
1113 gtk_widget_show(widget);
1114 else
1115 gtk_widget_hide(widget);
1120 static void
1121 modify_label_image_button(GladeWidgetId button_id, gchar *name, char *stock_image)
1123 GList *list, *l;
1124 GtkHBox *hbox;
1125 GtkWidget *alignment;
1126 GtkWidget *button = sr_get_gladewidget(button_id)->widget;
1128 list = gtk_container_get_children(GTK_CONTAINER (button));
1129 alignment = GTK_WIDGET(list->data);
1130 g_list_free(list);
1131 list = gtk_container_get_children(GTK_CONTAINER (alignment));
1132 hbox = GTK_HBOX(list->data);
1133 g_list_free(list);
1134 list = gtk_container_get_children(GTK_CONTAINER (hbox));
1135 for (l=list; l; l = g_list_next(l))
1137 if (GTK_IS_LABEL(l->data))
1138 gtk_label_set_text(GTK_LABEL(l->data), name);
1139 if (GTK_IS_IMAGE(l->data))
1140 gtk_image_set_from_stock(GTK_IMAGE(l->data), stock_image,
1141 GTK_ICON_SIZE_BUTTON);
1143 g_list_free(list);
1147 /********************************************************************/
1149 #define POP_LIST(str, var) populate_value(str, &s);\
1150 if (s) \
1152 sr->search.range.files.var = anjuta_util_glist_from_string(s);\
1155 /********************************************************************/
1157 void
1158 search_replace_populate(void)
1160 char *s = NULL;
1161 char *max = NULL;
1163 /* Now, populate the instance with values from the GUI */
1164 populate_value(SEARCH_STRING, &(sr->search.expr.search_str));
1165 populate_value(SEARCH_REGEX, &(sr->search.expr.regex));
1166 populate_value(GREEDY, &(sr->search.expr.greedy));
1167 populate_value(IGNORE_CASE, &(sr->search.expr.ignore_case));
1168 populate_value(WHOLE_WORD, &(sr->search.expr.whole_word));
1169 populate_value(WHOLE_LINE, &(sr->search.expr.whole_line));
1170 populate_value(WORD_START, &(sr->search.expr.word_start));
1171 populate_value(SEARCH_TARGET_COMBO, &(sr->search.range.type));
1172 populate_value(SEARCH_DIRECTION_COMBO, &(sr->search.range.direction));
1173 populate_value(ACTIONS_NO_LIMIT, &(sr->search.expr.no_limit));
1175 populate_value(SEARCH_BASIC, &(sr->search.basic_search));
1177 if (sr->search.expr.no_limit)
1178 sr->search.expr.actions_max = G_MAXINT;
1179 else
1181 populate_value(ACTIONS_MAX, &(max));
1182 sr->search.expr.actions_max = atoi(max);
1183 if (sr->search.expr.actions_max <= 0)
1184 sr->search.expr.actions_max = 200;
1185 g_free(max);
1188 switch (sr->search.range.type)
1190 case SR_FUNCTION:
1191 case SR_BLOCK:
1192 if (flag_select)
1193 sr->search.range.type = SR_SELECTION;
1194 break;
1195 case SR_FILES:
1196 POP_LIST(MATCH_FILES, match_files);
1197 POP_LIST(UNMATCH_FILES, ignore_files);
1198 POP_LIST(MATCH_DIRS, match_dirs);
1199 POP_LIST(UNMATCH_DIRS, ignore_dirs);
1200 populate_value(IGNORE_HIDDEN_FILES, &(sr->search.range.files.ignore_hidden_files));
1201 populate_value(IGNORE_HIDDEN_DIRS, &(sr->search.range.files.ignore_hidden_dirs));
1202 populate_value(SEARCH_RECURSIVE, &(sr->search.range.files.recurse));
1203 break;
1204 default:
1205 break;
1207 populate_value(SEARCH_ACTION_COMBO, &(sr->search.action));
1208 switch (sr->search.action)
1210 case SA_REPLACE:
1211 case SA_REPLACEALL:
1212 populate_value(REPLACE_STRING, &(sr->replace.repl_str));
1213 populate_value(REPLACE_REGEX, &(sr->replace.regex));
1214 break;
1215 default:
1216 break;
1220 static void
1221 show_jump_button (gboolean show)
1223 GtkWidget *jump_button = sr_get_gladewidget(JUMP_BUTTON)->widget;
1224 if (show)
1225 gtk_widget_show(jump_button);
1226 else
1227 gtk_widget_hide(jump_button);
1230 static
1231 void translate_dialog_strings (AnjutaUtilStringMap labels[])
1233 guint i = 0;
1234 while (labels[i].name != NULL)
1236 labels[i].name = gettext (labels[i].name);
1237 i++;
1241 static gboolean
1242 create_dialog(void)
1244 GladeWidget *w;
1245 GtkWidget *widget;
1246 int i;
1248 g_return_val_if_fail(NULL != sr, FALSE);
1249 if (NULL != sg) return TRUE;
1250 sg = g_new0(SearchReplaceGUI, 1);
1252 if (NULL == (sg->xml = glade_xml_new(GLADE_FILE_SEARCH_REPLACE,
1253 SEARCH_REPLACE_DIALOG, NULL)))
1255 anjuta_util_dialog_error(NULL, _("Unable to build user interface for Search And Replace"));
1256 g_free(sg);
1257 sg = NULL;
1258 return FALSE;
1260 sg->dialog = glade_xml_get_widget(sg->xml, SEARCH_REPLACE_DIALOG);
1261 /* gtk_window_set_transient_for (GTK_WINDOW(sg->dialog)
1262 , GTK_WINDOW(app->widgets.window)); */
1264 if (!labels_translated)
1266 labels_translated = TRUE;
1267 translate_dialog_strings (search_direction_strings);
1268 translate_dialog_strings (search_target_strings);
1269 translate_dialog_strings (search_action_strings);
1272 for (i=0; NULL != glade_widgets[i].name; ++i)
1274 w = &(glade_widgets[i]);
1275 w->widget = glade_xml_get_widget(sg->xml, w->name);
1276 if (GE_COMBO_ENTRY == w->type)
1278 /* Get child of GtkComboBoxEntry */
1279 w->widget = GTK_BIN(w->widget)->child;
1281 gtk_widget_ref(w->widget);
1282 if (GE_COMBO == w->type && NULL != w->extra)
1284 search_set_popdown_map(GTK_COMBO_BOX(w->widget), (AnjutaUtilStringMap *)w->extra);
1288 widget = sr_get_gladewidget(SEARCH_STRING_COMBO)->widget;
1289 g_signal_connect (widget, "changed", G_CALLBACK (on_search_expression_changed), NULL);
1290 widget = sr_get_gladewidget(SEARCH_STRING)->widget;
1291 g_signal_connect (widget, "activate", G_CALLBACK (on_search_expression_activate), NULL);
1292 widget = sr_get_gladewidget(REPLACE_STRING)->widget;
1293 g_signal_connect (widget, "activate", G_CALLBACK (on_search_expression_activate), NULL);
1294 widget = sr_get_gladewidget(SEARCH_ACTION_COMBO)->widget;
1295 g_signal_connect (widget, "changed", G_CALLBACK (on_search_action_changed), NULL);
1296 widget = sr_get_gladewidget(SEARCH_DIRECTION_COMBO)->widget;
1297 g_signal_connect (widget, "changed", G_CALLBACK (on_search_direction_changed), NULL);
1298 widget = sr_get_gladewidget(SEARCH_TARGET_COMBO)->widget;
1299 g_signal_connect (widget, "changed", G_CALLBACK (on_search_target_changed), NULL);
1302 search_preferences_initialize_setting_treeview(sg->dialog);
1303 search_preferences_init();
1305 glade_xml_signal_autoconnect(sg->xml);
1306 return TRUE;
1309 static void
1310 show_dialog(void)
1312 gtk_window_present (GTK_WINDOW (sg->dialog));
1313 sg->showing = TRUE;
1316 static gboolean
1317 word_in_list(GList *list, gchar *word)
1319 GList *l = list;
1321 while (l != NULL)
1323 if (strcmp(l->data, word) == 0)
1324 return TRUE;
1325 l = g_list_next(l);
1327 return FALSE;
1330 /* Remove last item of the list if > nb_max */
1332 static GList*
1333 list_max_items(GList *list, guint nb_max)
1335 GList *last;
1337 if (g_list_length(list) > nb_max)
1339 last = g_list_last(list);
1340 g_free(last->data);
1341 list = g_list_delete_link (list, last);
1343 return list;
1346 #define MAX_ITEMS_SEARCH_COMBO 16
1348 void
1349 search_toolbar_set_text(gchar *search_text)
1351 AnjutaUI *ui;
1352 GtkAction *action;
1354 AnjutaShell* shell;
1355 g_object_get(G_OBJECT(sr->docman), "shell", &shell, NULL);
1357 ui = anjuta_shell_get_ui (shell, NULL);
1358 action = anjuta_ui_get_action (ui, "ActionGroupNavigation",
1359 "ActionEditSearchEntry");
1360 egg_entry_action_set_text (EGG_ENTRY_ACTION(action), search_text);
1363 static void
1364 search_update_combos(void)
1366 GtkWidget *search_entry = NULL;
1367 gchar *search_word = NULL;
1368 IAnjutaDocument* doc = ianjuta_document_manager_get_current_document(sr->docman,
1369 NULL);
1370 IAnjutaEditor *te = NULL;
1371 if (IANJUTA_IS_EDITOR(doc))
1372 te = IANJUTA_EDITOR(doc);
1374 search_entry = sr_get_gladewidget(SEARCH_STRING)->widget;
1375 if (search_entry && te)
1377 search_word = g_strdup(gtk_entry_get_text(GTK_ENTRY (search_entry)));
1378 if (search_word && strlen(search_word) > 0)
1380 if (!word_in_list(sr->search.expr_history, search_word))
1382 GtkWidget *search_list =
1383 sr_get_gladewidget(SEARCH_STRING_COMBO)->widget;
1384 sr->search.expr_history = g_list_prepend(sr->search.expr_history,
1385 search_word);
1386 sr->search.expr_history = list_max_items(sr->search.expr_history,
1387 MAX_ITEMS_SEARCH_COMBO);
1388 search_set_popdown_strings(GTK_COMBO_BOX_ENTRY (search_list),
1389 sr->search.expr_history);
1391 //search_toolbar_set_text(search_word);
1392 // FIXME comboentry instead of entry
1393 //~ entry_set_text_n_select (app->widgets.toolbar.main_toolbar.find_entry,
1394 //~ search_word, FALSE);
1400 static void
1401 replace_update_combos(void)
1403 GtkWidget *replace_entry = NULL;
1404 gchar *replace_word = NULL;
1405 IAnjutaDocument* doc = ianjuta_document_manager_get_current_document(sr->docman,
1406 NULL);
1407 IAnjutaEditor *te = NULL;
1408 if (IANJUTA_IS_EDITOR(doc))
1409 te = IANJUTA_EDITOR(doc);
1411 replace_entry = sr_get_gladewidget(REPLACE_STRING)->widget;
1412 if (replace_entry && te)
1414 replace_word = g_strdup(gtk_entry_get_text(GTK_ENTRY (replace_entry)));
1415 if (replace_word && strlen(replace_word) > 0)
1417 if (!word_in_list(sr->replace.expr_history, replace_word))
1419 GtkWidget *replace_list =
1420 sr_get_gladewidget(REPLACE_STRING_COMBO)->widget;
1421 sr->replace.expr_history = g_list_prepend(sr->replace.expr_history,
1422 replace_word);
1423 sr->replace.expr_history = list_max_items(sr->replace.expr_history,
1424 MAX_ITEMS_SEARCH_COMBO);
1425 search_set_popdown_strings(GTK_COMBO_BOX_ENTRY (replace_list),
1426 sr->replace.expr_history);
1432 void
1433 search_update_dialog(void)
1435 GtkWidget *widget;
1436 Search *s;
1438 s = &(sr->search);
1439 widget = sr_get_gladewidget(SEARCH_REGEX)->widget;
1440 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.regex);
1441 widget = sr_get_gladewidget(GREEDY)->widget;
1442 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.greedy);
1443 widget = sr_get_gladewidget(IGNORE_CASE)->widget;
1444 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.ignore_case);
1445 widget = sr_get_gladewidget(WHOLE_WORD)->widget;
1446 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.whole_word);
1447 widget = sr_get_gladewidget(WHOLE_LINE)->widget;
1448 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.whole_line);
1449 widget = sr_get_gladewidget(WORD_START)->widget;
1450 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.word_start);
1452 widget = sr_get_gladewidget(ACTIONS_NO_LIMIT)->widget;
1453 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.no_limit);
1454 widget = sr_get_gladewidget(ACTIONS_MAX)->widget;
1455 gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), s->expr.actions_max);
1457 widget = sr_get_gladewidget(REPLACE_REGEX)->widget;
1458 gtk_widget_set_sensitive(widget, sr->search.expr.regex);
1460 widget = sr_get_gladewidget(SEARCH_BUTTON)->widget;
1461 gtk_widget_set_sensitive (widget, (s->expr.search_str != NULL) && (*s->expr.search_str != '\0'));
1463 widget = sr_get_gladewidget(SEARCH_STRING)->widget;
1464 if (s->expr.search_str)
1465 gtk_entry_set_text(GTK_ENTRY(widget), s->expr.search_str);
1467 widget = sr_get_gladewidget(SEARCH_DIRECTION_COMBO)->widget;
1468 search_select_item (GTK_COMBO_BOX(widget), s->range.direction);
1470 widget = sr_get_gladewidget(SEARCH_ACTION_COMBO)->widget;
1471 search_select_item (GTK_COMBO_BOX(widget), s->action);
1473 search_show_replace(s->action == SA_REPLACE || s->action == SA_REPLACEALL);
1475 widget = sr_get_gladewidget(SEARCH_TARGET_COMBO)->widget;
1476 search_select_item (GTK_COMBO_BOX(widget), s->range.type);
1478 widget = sr_get_gladewidget(SEARCH_BASIC)->widget;
1479 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->basic_search);
1481 widget = sr_get_gladewidget(STOP_BUTTON)->widget;
1482 gtk_widget_set_sensitive (widget, FALSE);
1484 basic_search_toggled();
1487 /* -------------- Callbacks --------------------- */
1489 gboolean
1490 on_search_replace_delete_event(GtkWidget *window, GdkEvent *event,
1491 gboolean user_data)
1493 if (sg->showing)
1495 gtk_widget_hide(sg->dialog);
1496 sg->showing = FALSE;
1498 return TRUE;
1501 gboolean
1502 on_search_dialog_key_press_event(GtkWidget *widget, GdkEventKey *event,
1503 gpointer user_data)
1505 if (event->keyval == GDK_Escape)
1507 if (user_data)
1509 /* Escape pressed in Find window */
1510 gtk_widget_hide(widget);
1511 sg->showing = FALSE;
1513 else
1515 /* Escape pressed in wrap yes/no window */
1516 gtk_dialog_response (GTK_DIALOG (widget), GTK_RESPONSE_NO);
1518 return TRUE;
1520 else
1522 if ( (event->state & GDK_CONTROL_MASK) &&
1523 ((event->keyval & 0x5F) == GDK_G))
1525 if (event->state & GDK_SHIFT_MASK)
1526 search_replace_previous();
1527 else
1528 search_replace_next();
1530 return FALSE;
1534 static void
1535 search_disconnect_set_toggle_connect(GladeWidgetId id, GCallback function,
1536 gboolean active)
1538 GtkWidget *button;
1540 button = sr_get_gladewidget(id)->widget;
1541 g_signal_handlers_disconnect_by_func(G_OBJECT(button), function, NULL);
1542 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
1543 g_signal_connect(G_OBJECT(button), "toggled", function, NULL);
1547 void
1548 on_search_match_whole_word_toggled (GtkToggleButton *togglebutton,
1549 gpointer user_data)
1551 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)))
1553 search_disconnect_set_toggle_connect(WHOLE_LINE, (GCallback)
1554 on_search_match_whole_line_toggled, FALSE);
1555 search_disconnect_set_toggle_connect(WORD_START, (GCallback)
1556 on_search_match_word_start_toggled, FALSE);
1560 void
1561 on_search_match_whole_line_toggled (GtkToggleButton *togglebutton,
1562 gpointer user_data)
1564 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)))
1566 search_disconnect_set_toggle_connect(WHOLE_WORD, (GCallback)
1567 on_search_match_whole_word_toggled, FALSE);
1568 search_disconnect_set_toggle_connect(WORD_START, (GCallback)
1569 on_search_match_word_start_toggled, FALSE);
1573 void
1574 on_search_match_word_start_toggled (GtkToggleButton *togglebutton,
1575 gpointer user_data)
1577 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)))
1579 search_disconnect_set_toggle_connect(WHOLE_WORD, (GCallback)
1580 on_search_match_whole_word_toggled, FALSE);
1581 search_disconnect_set_toggle_connect(WHOLE_LINE, (GCallback)
1582 on_search_match_whole_line_toggled, FALSE);
1587 static void
1588 search_make_sensitive(gboolean sensitive)
1590 static char *widgets[] = {
1591 SEARCH_EXPR_FRAME, SEARCH_TARGET_FRAME, CLOSE_BUTTON, SEARCH_BUTTON,
1592 JUMP_BUTTON
1594 gint i;
1595 GtkWidget *widget;
1597 for (i=0; i < sizeof(widgets)/sizeof(widgets[0]); ++i)
1599 widget = sr_get_gladewidget(widgets[i])->widget;
1600 if (NULL != widget)
1601 gtk_widget_set_sensitive(widget, sensitive);
1606 void
1607 on_search_regex_toggled (GtkToggleButton *togglebutton, gpointer user_data)
1609 static GladeWidgetId dependent_widgets[] = {
1610 GREEDY, IGNORE_CASE, WHOLE_WORD, WHOLE_LINE, WORD_START
1612 int i;
1613 GtkWidget *dircombo = sr_get_gladewidget(SEARCH_DIRECTION_COMBO)->widget;
1614 GtkWidget *repl_regex = sr_get_gladewidget(REPLACE_REGEX)->widget;
1615 GtkWidget *widget;
1616 gboolean state = gtk_toggle_button_get_active(togglebutton);
1618 if (state)
1620 search_set_direction(SD_FORWARD);
1623 gtk_widget_set_sensitive(dircombo, !state);
1624 gtk_widget_set_sensitive(repl_regex, state);
1626 for (i=0; i < sizeof(dependent_widgets)/sizeof(dependent_widgets[0]); ++i)
1628 widget = sr_get_gladewidget(dependent_widgets[i])->widget;
1629 if (NULL != widget)
1631 gtk_widget_set_sensitive(widget, !state);
1632 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
1637 static void
1638 search_set_toggle_direction(SearchDirection dir)
1640 switch (dir)
1642 case SD_FORWARD :
1643 search_disconnect_set_toggle_connect(SEARCH_FORWARD, (GCallback)
1644 on_search_forward_toggled, TRUE);
1645 break;
1646 case SD_BACKWARD :
1647 search_disconnect_set_toggle_connect(SEARCH_BACKWARD, (GCallback)
1648 on_search_backward_toggled, TRUE);
1649 break;
1650 case SD_BEGINNING :
1651 search_disconnect_set_toggle_connect(SEARCH_FULL_BUFFER, (GCallback)
1652 on_search_full_buffer_toggled, TRUE);
1653 break;
1657 void
1658 on_search_direction_changed (GtkComboBox *combo, gpointer user_data)
1660 SearchDirection dir;
1662 dir = search_get_item_combo(combo);
1663 search_set_toggle_direction(dir);
1664 search_direction_changed(dir);
1667 void
1668 on_search_action_changed (GtkComboBox *combo, gpointer user_data)
1670 SearchAction act;
1671 SearchRangeType rt;
1673 reset_flags();
1674 act = search_get_item_combo(combo);
1675 rt = search_get_item_combo_name(SEARCH_TARGET_COMBO);
1676 show_jump_button (FALSE);
1677 switch(act)
1679 case SA_SELECT:
1680 search_show_replace(FALSE);
1681 modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
1682 if (rt == SR_OPEN_BUFFERS || rt == SR_PROJECT ||
1683 rt == SR_FILES)
1684 search_set_target(SR_BUFFER);
1685 break;
1686 case SA_REPLACE:
1687 search_show_replace(TRUE);
1688 modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
1689 if (rt == SR_OPEN_BUFFERS || rt == SR_PROJECT ||
1690 rt == SR_FILES)
1691 search_set_target(SR_BUFFER);
1692 break;
1693 case SA_REPLACEALL:
1694 search_show_replace(TRUE);
1695 modify_label_image_button(SEARCH_BUTTON, _("Replace All"),
1696 GTK_STOCK_FIND_AND_REPLACE);
1697 break;
1698 default:
1699 search_show_replace(FALSE);
1700 modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
1701 break;
1705 void
1706 on_search_target_changed(GtkComboBox *combo, gpointer user_data)
1708 SearchRangeType tgt;
1709 SearchDirection dir;
1710 SearchAction act;
1711 GtkWidget *search_var_frame = sr_get_gladewidget(SEARCH_VAR_FRAME)->widget;
1712 GtkWidget *file_filter_frame = sr_get_gladewidget(FILE_FILTER_FRAME)->widget;
1714 tgt = search_get_item_combo(combo);
1715 switch(tgt)
1717 case SR_FILES:
1718 gtk_widget_hide(search_var_frame);
1719 gtk_widget_show(file_filter_frame);
1720 break;
1721 default:
1722 gtk_widget_hide(search_var_frame);
1723 gtk_widget_hide(file_filter_frame);
1724 break;
1727 dir = search_get_item_combo_name(SEARCH_DIRECTION_COMBO);
1729 if (tgt == SR_SELECTION || tgt == SR_BLOCK || tgt == SR_FUNCTION)
1732 if (dir == SD_BEGINNING)
1734 search_set_direction(SD_FORWARD);
1737 if (tgt == SR_OPEN_BUFFERS || tgt == SR_PROJECT ||
1738 tgt == SR_FILES)
1740 search_set_direction(SD_BEGINNING);
1742 act = search_get_item_combo_name(SEARCH_ACTION_COMBO);
1743 if (act != SA_REPLACE && act != SA_REPLACEALL)
1745 if (tgt == SR_OPEN_BUFFERS)
1746 search_set_action(SA_BOOKMARK);
1747 else
1748 search_set_action(SA_FIND_PANE);
1750 else
1752 search_set_action(SA_REPLACEALL);
1753 sr->search.action = SA_REPLACEALL;
1756 reset_flags_and_search_button();
1757 /* Resize dialog */
1758 gtk_window_resize(GTK_WINDOW(sg->dialog), 10, 10);
1761 void
1762 on_search_expression_changed(GtkComboBox *combo, gpointer user_data)
1764 GtkWidget *search_entry = sr_get_gladewidget(SEARCH_STRING)->widget;
1765 GtkWidget *widget = sr_get_gladewidget(SEARCH_BUTTON)->widget;
1766 gboolean sensitive;
1768 sensitive = *gtk_entry_get_text (GTK_ENTRY (search_entry)) == '\0' ? FALSE: TRUE;
1769 gtk_widget_set_sensitive (widget, sensitive);
1773 void
1774 on_actions_no_limit_clicked(GtkButton *button, gpointer user_data)
1776 GtkWidget *actions_max = sr_get_gladewidget(ACTIONS_MAX)->widget;
1778 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
1779 gtk_widget_set_sensitive (actions_max, FALSE);
1780 else
1781 gtk_widget_set_sensitive (actions_max, TRUE);
1784 void
1785 on_search_button_close_clicked(GtkButton *button, gpointer user_data)
1787 if (sg->showing)
1789 gtk_widget_hide(sg->dialog);
1790 sg->showing = FALSE;
1794 void
1795 on_search_button_stop_clicked(GtkButton *button, gpointer user_data)
1797 end_activity = TRUE;
1800 void
1801 on_search_button_next_clicked(GtkButton *button, gpointer user_data)
1803 clear_pcre();
1804 search_replace_populate();
1806 search_and_replace();
1809 void search_replace_find_usage(const gchar *symbol)
1811 gchar *project_root_uri = NULL;
1812 SearchReplace *old_sr = sr;
1813 AnjutaShell* shell;
1815 sr = g_new (SearchReplace, 1);
1817 sr->search.expr.search_str = g_strdup (symbol);
1818 sr->search.expr.regex = FALSE;
1819 sr->search.expr.greedy = FALSE;
1820 sr->search.expr.ignore_case = FALSE;
1821 sr->search.expr.whole_word = TRUE;
1822 sr->search.expr.whole_line = FALSE;
1823 sr->search.expr.word_start = FALSE;
1824 sr->search.expr.no_limit = TRUE;
1825 sr->search.expr.actions_max = G_MAXINT;
1826 sr->search.expr.re = NULL;
1828 g_object_get(G_OBJECT(sr->docman), "shell", &shell, NULL);
1830 anjuta_shell_get (shell,
1831 "project_root_uri", G_TYPE_STRING,
1832 &project_root_uri, NULL);
1834 sr->search.range.type =
1835 project_root_uri != NULL ? SR_PROJECT : SR_OPEN_BUFFERS;
1836 g_free (project_root_uri);
1838 sr->search.range.direction = SD_BEGINNING;
1840 sr->search.range.var = NULL;
1842 sr->search.range.files.top_dir = NULL;
1843 sr->search.range.files.match_files = NULL;
1844 sr->search.range.files.match_dirs = NULL;
1845 sr->search.range.files.ignore_files = NULL;
1846 sr->search.range.files.ignore_dirs = NULL;
1847 sr->search.range.files.ignore_hidden_files = TRUE;
1848 sr->search.range.files.ignore_hidden_dirs = TRUE;
1849 sr->search.range.files.recurse = TRUE;
1851 sr->search.action = SA_FIND_PANE;
1853 sr->search.expr_history = NULL;
1854 sr->search.incremental_pos = 0;
1855 sr->search.incremental_wrap = TRUE;
1857 create_dialog ();
1859 search_and_replace();
1860 g_free (sr);
1861 sr = old_sr;
1864 void
1865 on_search_button_jump_clicked(GtkButton *button, gpointer user_data)
1867 if (sr)
1868 interactive = FALSE;
1869 gtk_widget_hide(GTK_WIDGET(button));
1871 search_replace_populate();
1872 search_and_replace();
1875 void
1876 on_search_expression_activate (GtkEditable *edit, gpointer user_data)
1878 GtkWidget *combo;
1880 search_replace_populate();
1882 search_and_replace();
1883 combo = GTK_WIDGET(edit)->parent;
1884 reset_flags_and_search_button();
1888 void
1889 on_search_full_buffer_toggled (GtkToggleButton *togglebutton,
1890 gpointer user_data)
1892 if (gtk_toggle_button_get_active(togglebutton))
1894 search_set_direction(SD_BEGINNING);
1898 void
1899 on_search_forward_toggled (GtkToggleButton *togglebutton,
1900 gpointer user_data)
1902 if (gtk_toggle_button_get_active(togglebutton))
1904 search_set_direction(SD_FORWARD);
1908 void
1909 on_search_backward_toggled (GtkToggleButton *togglebutton,
1910 gpointer user_data)
1912 if (gtk_toggle_button_get_active(togglebutton))
1914 search_set_direction(SD_BACKWARD);
1918 void
1919 on_setting_basic_search_toggled (GtkToggleButton *togglebutton,
1920 gpointer user_data)
1922 SearchAction act;
1923 GtkWidget *frame_basic = sr_get_gladewidget(FRAME_SEARCH_BASIC)->widget;
1925 if (gtk_toggle_button_get_active(togglebutton))
1927 gtk_widget_show(frame_basic);
1928 search_set_target(SR_BUFFER);
1929 search_set_direction(SD_FORWARD);
1931 act = search_get_item_combo_name(SEARCH_ACTION_COMBO);
1932 if (act == SA_REPLACE || act == SA_REPLACEALL)
1933 search_set_action(SA_REPLACE);
1934 else
1935 search_set_action(SA_SELECT);
1937 else
1938 gtk_widget_hide(frame_basic);
1942 static void
1943 basic_search_toggled(void)
1945 GtkToggleButton *togglebutton;
1947 togglebutton = GTK_TOGGLE_BUTTON(sr_get_gladewidget(SEARCH_BASIC)->widget);
1949 on_setting_basic_search_toggled (togglebutton, NULL);
1952 /***********************************************************************/
1954 #define MAX_LENGTH_SEARCH 64
1956 void
1957 anjuta_search_replace_activate (gboolean replace, gboolean project)
1959 GtkWidget *notebook;
1960 GtkWidget *search_entry;
1961 IAnjutaDocument *doc;
1962 IAnjutaEditor *te;
1964 create_dialog ();
1966 search_update_dialog();
1968 search_replace_populate();
1970 reset_flags_and_search_button();
1972 search_entry = sr_get_gladewidget(SEARCH_STRING)->widget;
1973 doc = ianjuta_document_manager_get_current_document(sr->docman, NULL);
1974 te = (IANJUTA_IS_EDITOR (doc)) ? IANJUTA_EDITOR (doc) : NULL;
1975 if (te && search_entry && sr->search.range.type != SR_SELECTION)
1977 /* Set properties */
1978 gchar *current_word;
1980 current_word = ianjuta_editor_selection_get
1981 (IANJUTA_EDITOR_SELECTION (te), NULL);
1982 if (current_word == NULL)
1983 current_word = ianjuta_editor_get_current_word (te, NULL);
1985 if (current_word && strlen(current_word) > 0 )
1987 if (strlen(current_word) > MAX_LENGTH_SEARCH)
1988 current_word[MAX_LENGTH_SEARCH] = '\0';
1989 gtk_entry_set_text(GTK_ENTRY (search_entry), current_word);
1990 g_free(current_word);
1994 if (replace)
1996 if ( !(sr->search.action == SA_REPLACE ||
1997 sr->search.action == SA_REPLACEALL))
1999 search_set_action(SA_REPLACE);
2000 sr->search.action = SA_REPLACE;
2001 search_show_replace(TRUE);
2004 else
2006 if (sr->search.action == SA_REPLACE || sr->search.action == SA_REPLACEALL)
2008 search_set_action(SA_SELECT);
2009 sr->search.action = SA_SELECT;
2010 search_show_replace(FALSE);
2013 if (sr->search.action != SA_REPLACEALL)
2014 modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
2016 if (project)
2018 search_set_target(SR_PROJECT);
2019 if (!replace)
2021 search_set_action (SA_FIND_PANE);
2022 search_set_direction (SD_BEGINNING);
2025 show_jump_button(FALSE);
2027 notebook = sr_get_gladewidget(SEARCH_NOTEBOOK)->widget;
2028 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0);
2030 /* Show the dialog */
2031 if (search_entry)
2032 gtk_widget_grab_focus (search_entry);
2033 show_dialog();