Integrate adding files with the file manager
[anjuta-git-plugin.git] / plugins / search / search-replace.c
blob1f9ce8220293badb427b6cc9796a9f5bf4991dc3
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>
26 #include <libgnomevfs/gnome-vfs.h>
28 #include <libanjuta/anjuta-utils.h>
29 #include <libanjuta/anjuta-plugin.h>
30 #include <libanjuta/anjuta-debug.h>
31 #include <libanjuta/interfaces/ianjuta-message-manager.h>
32 #include <libanjuta/interfaces/ianjuta-message-view.h>
33 #include <libanjuta/interfaces/ianjuta-editor.h>
34 #include <libanjuta/interfaces/ianjuta-editor-selection.h>
35 #include <libanjuta/interfaces/ianjuta-markable.h>
36 #include <libanjuta/interfaces/ianjuta-bookmark.h>
37 #include <libanjuta/interfaces/ianjuta-indicable.h>
39 #include "search-replace_backend.h"
40 #include "search-replace.h"
41 #include "search_preferences.h"
43 #include <libanjuta/interfaces/ianjuta-project-manager.h>
44 #include <glib/gi18n.h>
46 #define GLADE_FILE_SEARCH_REPLACE PACKAGE_DATA_DIR"/glade/anjuta-search.glade"
48 /* LibGlade's auto-signal-connect will connect to these signals.
49 * Do not declare them static.
51 gboolean
52 on_search_dialog_key_press_event(GtkWidget *widget, GdkEventKey *event,
53 gpointer user_data);
54 void on_search_match_whole_word_toggled (GtkToggleButton *togglebutton,
55 gpointer user_data);
56 void on_search_match_whole_line_toggled (GtkToggleButton *togglebutton,
57 gpointer user_data);
58 void on_search_match_word_start_toggled (GtkToggleButton *togglebutton,
59 gpointer user_data);
60 gboolean on_search_replace_delete_event(GtkWidget *window, GdkEvent *event,
61 gboolean user_data);
62 void on_replace_regex_toggled (GtkToggleButton *togglebutton, gpointer user_data);
63 void on_search_regex_toggled (GtkToggleButton *togglebutton, gpointer user_data);
64 void on_search_action_changed (GtkComboBox *combo, gpointer user_data);
65 void on_search_target_changed(GtkComboBox *combo, gpointer user_data);
66 void on_search_expression_changed(GtkComboBox *combo, gpointer user_data);
67 void on_actions_no_limit_clicked(GtkButton *button, gpointer user_data);
68 void on_search_button_close_clicked(GtkButton *button, gpointer user_data);
69 void on_search_button_close_clicked(GtkButton *button, gpointer user_data);
70 void on_search_button_help_clicked(GtkButton *button, gpointer user_data);
71 void on_search_button_next_clicked(GtkButton *button, gpointer user_data);
72 void on_search_button_jump_clicked(GtkButton *button, gpointer user_data);
73 void on_search_expression_activate (GtkEditable *edit, gpointer user_data);
74 void on_search_button_save_clicked(GtkButton *button, gpointer user_data);
75 void on_search_button_stop_clicked(GtkButton *button, gpointer user_data);
77 void on_search_direction_changed (GtkComboBox *combo, gpointer user_data);
78 void on_search_full_buffer_toggled (GtkToggleButton *togglebutton,
79 gpointer user_data);
80 void on_search_forward_toggled (GtkToggleButton *togglebutton,
81 gpointer user_data);
82 void on_search_backward_toggled (GtkToggleButton *togglebutton,
83 gpointer user_data);
84 void on_setting_basic_search_toggled (GtkToggleButton *togglebutton,
85 gpointer user_data);
87 /* GUI dropdown option strings */
88 AnjutaUtilStringMap search_direction_strings[] = {
89 /* the order of these matters - it must match the order of the corresponding
90 radio buttons on another page */
91 {SD_BEGINNING, N_("Full Buffer")},
92 {SD_FORWARD, N_("Forward")},
93 {SD_BACKWARD, N_("Backward")},
94 {-1, NULL}
97 AnjutaUtilStringMap search_target_strings[] = {
98 {SR_BUFFER, N_("Current Buffer")},
99 {SR_SELECTION, N_("Current Selection")},
100 {SR_BLOCK, N_("Current Block")},
101 {SR_FUNCTION, N_("Current Function")},
102 {SR_OPEN_BUFFERS, N_("All Open Buffers")},
103 {SR_PROJECT, N_("All Project Files")},
104 /* {SR_VARIABLE, N_("Specify File List")},*/
105 {SR_FILES, N_("Specify File Patterns")},
106 {-1, NULL}
109 AnjutaUtilStringMap search_action_strings[] = {
110 {SA_SELECT, N_("Select next match")},
111 {SA_BOOKMARK, N_("Bookmark all matched lines")},
112 {SA_HIGHLIGHT, N_("Mark all matches")},
113 {SA_FIND_PANE, N_("List matches in find pane")},
114 {SA_REPLACE, N_("Replace next match")},
115 {SA_REPLACEALL, N_("Replace all matches")},
116 {-1, NULL}
120 typedef struct _SearchReplaceGUI
122 GladeXML *xml;
123 GtkWidget *dialog;
124 gboolean showing;
125 } SearchReplaceGUI;
128 static GladeWidget glade_widgets[] = {
129 /* CLOSE_BUTTON */
130 {GE_BUTTON, "button.close", NULL, NULL},
131 /* STOP_BUTTON */
132 {GE_BUTTON, "button.stop", NULL, NULL},
133 /* SEARCH_BUTTON */
134 {GE_BUTTON, "button.next", NULL, NULL},
135 /* JUMP_BUTTON */
136 {GE_BUTTON, "button.jump", NULL, NULL},
137 /* SEARCH_NOTEBOOK */
138 {GE_NONE, "search.notebook", NULL, NULL},
139 /* SEARCH_EXPR_FRAME */
140 {GE_NONE, "frame.search.expression", NULL, NULL},
141 /* SEARCH_TARGET_FRAME */
142 {GE_NONE, "frame.search.target", NULL, NULL},
143 /* SEARCH_VAR_FRAME */
144 {GE_NONE, "frame.search.var", NULL, NULL},
145 /* FILE_FILTER_FRAME */
146 {GE_NONE, "frame.file.filter", NULL, NULL},
147 /* FRAME_SEARCH_BASIC */
148 {GE_NONE, "frame.search.basic", NULL, NULL},
149 /* LABEL_REPLACE */
150 {GE_NONE, "label.replace", NULL, NULL},
151 /* SEARCH_STRING */
152 {GE_COMBO_ENTRY, "search.string.combo", NULL, NULL},
153 /* SEARCH_VAR */
154 {GE_COMBO_ENTRY, "search.var.combo", NULL, NULL},
155 /* MATCH_FILES */
156 {GE_COMBO_ENTRY, "file.filter.match.combo", NULL, NULL},
157 /* UNMATCH_FILES */
158 {GE_COMBO_ENTRY, "file.filter.unmatch.combo", NULL, NULL},
159 /* MATCH_DIRS */
160 {GE_COMBO_ENTRY, "dir.filter.match.combo", NULL, NULL},
161 /* UNMATCH_DIRS */
162 {GE_COMBO_ENTRY, "dir.filter.unmatch.combo", NULL, NULL},
163 /* REPLACE_STRING */
164 {GE_COMBO_ENTRY, "replace.string.combo", NULL, NULL},
165 /* ACTIONS_MAX */
166 {GE_TEXT, "actions.max", NULL, NULL},
167 /* SETTING_PREF_ENTRY */
168 {GE_TEXT, "setting.pref.entry", NULL, NULL},
169 /* SEARCH_REGEX */
170 {GE_BOOLEAN, "search.regex", NULL, NULL},
171 /* GREEDY */
172 {GE_BOOLEAN, "search.greedy", NULL, NULL},
173 /* IGNORE_CASE */
174 {GE_BOOLEAN, "search.ignore.case", NULL, NULL},
175 /* WHOLE_WORD */
176 {GE_BOOLEAN, "search.match.whole.word", NULL, NULL},
177 /* WORD_START */
178 {GE_BOOLEAN, "search.match.word.start", NULL, NULL},
179 /* WHOLE_LINE */
180 {GE_BOOLEAN, "search.match.whole.line", NULL, NULL},
181 /* IGNORE_HIDDEN_FILES */
182 {GE_BOOLEAN, "ignore.hidden.files", NULL, NULL},
183 /* IGNORE_BINARY_FILES */
184 {GE_BOOLEAN, "ignore.binary.files", NULL, NULL},
185 /* IGNORE_HIDDEN_DIRS */
186 {GE_BOOLEAN, "ignore.hidden.dirs", NULL, NULL},
187 /* SEARCH_RECURSIVE */
188 {GE_BOOLEAN, "search.dir.recursive", NULL, NULL},
189 /* REPLACE_REGEX */
190 {GE_BOOLEAN, "replace.regex", NULL, NULL},
191 /* ACTIONS_NO_LIMIT */
192 {GE_BOOLEAN, "actions.no_limit", NULL, NULL},
193 /* SEARCH_FULL_BUFFER */
194 {GE_BOOLEAN, "search.full_buffer", NULL, NULL},
195 /* SEARCH_FORWARD */
196 {GE_BOOLEAN, "search.forward", NULL, NULL},
197 /* SEARCH_BACKWARD */
198 {GE_BOOLEAN, "search.backward", NULL, NULL},
199 /* SEARCH_BASIC */
200 {GE_BOOLEAN, "search.basic", NULL, NULL},
201 /* SEARCH_STRING_COMBO */
202 {GE_COMBO, "search.string.combo", NULL, NULL},
203 /* SEARCH_TARGET_COMBO */
204 {GE_COMBO, "search.target.combo", search_target_strings, NULL},
205 /* SEARCH_ACTION_COMBO */
206 {GE_COMBO, "search.action.combo", search_action_strings, NULL},
207 /* SEARCH_VAR_COMBO */
208 {GE_COMBO, "search.var.combo", NULL, NULL},
209 /* MATCH_FILES_COMBO */
210 {GE_COMBO, "file.filter.match.combo", NULL, NULL},
211 /* UNMATCH_FILES_COMBO */
212 {GE_COMBO, "file.filter.unmatch.combo", NULL, NULL},
213 /* MATCH_DIRS_COMBO */
214 {GE_COMBO, "dir.filter.match.combo", NULL, NULL},
215 /* UNMATCH_DIRS_COMBO */
216 {GE_COMBO, "dir.filter.unmatch.combo", NULL, NULL},
217 /* REPLACE_STRING_COMBO */
218 {GE_COMBO, "replace.string.combo", NULL, NULL},
219 /* SEARCH_DIRECTION_COMBO */
220 {GE_COMBO, "search.direction.combo", search_direction_strings, NULL},
221 /* SETTING_PREF_TREEVIEW */
222 {GE_NONE, "setting.pref.treeview", NULL, NULL},
223 {GE_NONE, NULL, NULL, NULL}
226 /***********************************************************/
228 static void
229 write_message_pane(IAnjutaMessageView* view, FileBuffer *fb, SearchEntry *se, MatchInfo *mi);
230 static gboolean on_message_clicked (GObject* object, gchar* message, gpointer data);
231 static void on_message_view_destroyed (gpointer unused, GObject* where_the_object_was);
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 view = ianjuta_message_manager_add_view(msgman, name,
331 GTK_STOCK_FIND_AND_REPLACE, NULL);
332 g_return_if_fail(view != NULL);
333 g_signal_connect (G_OBJECT(view), "buffer_flushed",
334 G_CALLBACK (on_message_buffer_flush), NULL);
335 g_signal_connect (G_OBJECT(view), "message_clicked",
336 G_CALLBACK (on_message_clicked), NULL);
337 g_object_weak_ref (G_OBJECT(view), on_message_view_destroyed, 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 && fb->buf)
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))
412 IAnjutaIterable *start_pos, *end_pos;
413 /* end-location is correct for sourceview, 1-too-big for scintilla */
414 start_pos = ianjuta_editor_get_position_from_offset (fb->te, mi->pos, NULL);
415 end_pos = ianjuta_editor_get_position_from_offset (fb->te, mi->pos + mi->len, NULL);
416 ianjuta_indicable_set (IANJUTA_INDICABLE(fb->te),
417 start_pos, end_pos,
418 IANJUTA_INDICABLE_IMPORTANT, NULL);
419 g_object_unref (start_pos);
420 g_object_unref (end_pos);
422 break;
424 case SA_BOOKMARK:
425 if (found_line != mi->line)
427 found_line = mi->line;
429 if (fb->te == NULL)
430 fb->te =
431 IANJUTA_EDITOR (ianjuta_document_manager_get_current_document
432 (sr->docman, NULL));
434 if (IANJUTA_IS_MARKABLE (fb->te) &&
435 !ianjuta_markable_is_marker_set (
436 IANJUTA_MARKABLE(fb->te),
437 mi->line,
438 IANJUTA_MARKABLE_BOOKMARK,
439 NULL))
441 ianjuta_bookmark_toggle (IANJUTA_BOOKMARK(fb->te),
442 mi->line, FALSE, NULL);
445 break;
447 case SA_SELECT:
448 if (found_line != mi->line || fb->te == NULL)
450 if (fb->te)
451 ianjuta_editor_goto_line (fb->te, mi->line, NULL);
452 else
454 GFile* file = g_file_new_for_uri (fb->uri);
455 fb->te = ianjuta_document_manager_goto_file_line_mark
456 (sr->docman, file, mi->line, FALSE, NULL);
457 g_object_unref (file);
459 found_line = mi->line;
462 IAnjutaIterable* start = ianjuta_editor_get_position_from_offset (fb->te, mi->pos, NULL);
463 IAnjutaIterable* end = ianjuta_editor_get_position_from_offset (fb->te, mi->pos + mi->len, NULL);
464 ianjuta_editor_selection_set(IANJUTA_EDITOR_SELECTION (fb->te),
465 start,
466 end,
467 NULL);
468 g_object_unref (start);
469 g_object_unref (end);
470 break;
473 case SA_FIND_PANE:
474 write_message_pane(view, fb, se, mi);
475 break;
477 case SA_REPLACE:
478 if (found_line != mi->line || fb->te == NULL)
480 if (fb->te)
481 ianjuta_editor_goto_line (fb->te, mi->line, NULL);
482 else
484 GFile* file = g_file_new_for_uri (fb->uri);
485 fb->te = ianjuta_document_manager_goto_file_line_mark
486 (sr->docman, file, mi->line, FALSE, NULL);
487 g_object_unref (file);
489 found_line = mi->line;
492 if (!interactive)
494 IAnjutaIterable* start = ianjuta_editor_get_position_from_offset (fb->te, mi->pos - offset, NULL);
495 IAnjutaIterable* end = ianjuta_editor_get_position_from_offset (fb->te, mi->pos - offset + mi->len, NULL);
496 ianjuta_editor_selection_set(IANJUTA_EDITOR_SELECTION (fb->te),
497 start,
498 end,
499 NULL);
500 g_object_unref (start);
501 g_object_unref (end);
502 interactive = TRUE;
503 os = offset;
504 modify_label_image_button(SEARCH_BUTTON, _("Replace"),
505 GTK_STOCK_FIND_AND_REPLACE);
506 show_jump_button(TRUE);
507 if (sr->replace.regex && sr->search.expr.regex)
509 g_free (ch);
510 ch = regex_backref (mi, fb);
513 else
515 if (ch && sr->replace.regex && sr->search.expr.regex)
517 g_free (sr->replace.repl_str);
518 sr->replace.repl_str = g_strdup (ch);
519 g_free (ch);
520 ch = NULL;
523 IAnjutaIterable* start = ianjuta_editor_get_position_from_offset (fb->te, mi->pos - os, NULL);
524 IAnjutaIterable* end = ianjuta_editor_get_position_from_offset (fb->te, mi->pos + mi->len - os, NULL);
525 ianjuta_editor_selection_set(IANJUTA_EDITOR_SELECTION (fb->te),
526 start,
527 end,
528 NULL);
529 ianjuta_editor_selection_replace(IANJUTA_EDITOR_SELECTION (fb->te),
530 sr->replace.repl_str,
531 strlen(sr->replace.repl_str),
532 NULL);
533 g_object_unref (start);
534 g_object_unref (end);
536 if (se->direction != SD_BACKWARD)
537 offset += mi->len - (sr->replace.repl_str?strlen(sr->replace.repl_str):0);
539 interactive = FALSE;
541 break;
543 case SA_REPLACEALL:
544 if (sr->replace.regex && sr->search.expr.regex)
546 regx_pattern = sr->replace.repl_str; /* preserve for later matches */
547 sr->replace.repl_str = regex_backref (mi, fb);
549 else
550 regx_pattern = NULL;
551 if (fb->te == NULL) /* NON OPENED FILES */
553 if (replace_in_not_opened_files(fb, mi, sr->replace.repl_str))
554 save_file = TRUE;
556 else
558 IAnjutaIterable* start = ianjuta_editor_get_position_from_offset (fb->te, mi->pos - offset, NULL);
559 IAnjutaIterable* end = ianjuta_editor_get_position_from_offset (fb->te, mi->pos + mi->len - offset, NULL);
560 ianjuta_editor_selection_set(IANJUTA_EDITOR_SELECTION (fb->te),
561 start,
562 end,
563 NULL);
564 ianjuta_editor_selection_replace(IANJUTA_EDITOR_SELECTION (fb->te),
565 sr->replace.repl_str,
566 strlen(sr->replace.repl_str),
567 NULL);
568 g_object_unref (start);
569 g_object_unref (end);
571 if (se->direction != SD_BACKWARD)
572 offset += mi->len - (sr->replace.repl_str?strlen(sr->replace.repl_str):0);
573 if (regx_pattern)
575 g_free (sr->replace.repl_str);
576 sr->replace.repl_str = regx_pattern;
578 break;
580 default:
581 g_warning ("Not implemented - File %s - Line %d\n", __FILE__, __LINE__);
582 break;
583 } // switch
585 if (se->direction != SD_BACKWARD)
586 start_sel = mi->pos + mi->len - offset;
587 else
588 start_sel = mi->pos - offset;
590 if (SA_REPLACE != s->action || !interactive)
591 match_info_free(mi);
593 if (SA_SELECT == s->action ||
594 ((SA_REPLACE == s->action || SA_REPLACEALL == s->action) && interactive))
595 break;
597 if (save_file)
599 save_not_opened_files (fb);
600 save_file = FALSE;
604 file_buffer_free (fb);
605 g_free (se->path);
606 g_free (se);
608 if (SA_SELECT == s->action && nb_results > 0)
609 break;
612 gtk_widget_set_sensitive (sr_get_gladewidget(STOP_BUTTON)->widget, FALSE);
614 if (s->range.type == SR_BLOCK || s->range.type == SR_FUNCTION ||
615 s->range.type == SR_SELECTION)
616 flag_select = TRUE;
618 if (entries)
619 g_list_free (entries);
621 if (s->action == SA_FIND_PANE)
623 ianjuta_message_view_append (view, IANJUTA_MESSAGE_VIEW_TYPE_INFO,
624 _("Search complete"), "", NULL);
627 if (nb_results == 0)
629 search_end_alert(sr->search.expr.search_str);
631 else if (nb_results > sr->search.expr.actions_max)
632 max_results_alert();
633 else if (s->action == SA_REPLACEALL)
634 nb_results_alert(nb_results);
636 if ((s->range.direction == SD_BEGINNING) &&
637 ((s->action == SA_SELECT) || (s->action == SA_REPLACE)) )
639 search_set_direction(SD_FORWARD);
643 static void
644 write_message_pane(IAnjutaMessageView* view, FileBuffer *fb, SearchEntry *se,
645 MatchInfo *mi)
647 gchar *match_line;
648 char buf[BUFSIZ];
649 gchar *tmp;
651 match_line = file_match_line_from_pos(fb, mi->pos);
653 if (SE_BUFFER == se->type)
655 /* DEBUG_PRINT ("FBPATH %s\n", fb->path); */
656 const gchar* filename = ianjuta_document_get_filename(IANJUTA_DOCUMENT(se->te), NULL);
657 tmp = g_strrstr(fb->path, "/");
658 tmp = g_strndup(fb->path, tmp + 1 -(fb->path));
659 snprintf(buf, BUFSIZ, "%s%s:%d:%s\n", tmp, filename,
660 mi->line, match_line);
661 g_free(tmp);
663 else /* if (SE_FILE == se->type) */
665 snprintf(buf, BUFSIZ, "%s:%d:%s\n", se->path, mi->line + 1, match_line);
667 g_free(match_line);
668 ianjuta_message_view_buffer_append (view, buf, NULL);
671 static void
672 on_message_view_destroyed (gpointer unused, GObject* where_the_object_was)
674 end_activity = TRUE;
677 static void
678 on_message_buffer_flush (IAnjutaMessageView *view, const gchar *one_line,
679 gpointer data)
681 ianjuta_message_view_append (view, IANJUTA_MESSAGE_VIEW_TYPE_NORMAL,
682 one_line, "", NULL);
685 static gboolean
686 on_message_clicked (GObject* object, gchar* message, gpointer data)
688 gchar *ptr, *ptr2;
689 gchar *path, *nline;
690 GFile* file;
691 gint line;
693 if (!(ptr = g_strstr_len(message, strlen(message), ":")) )
694 return FALSE;
695 path = g_strndup(message, ptr - message);
697 ptr++;
698 if (!(ptr2 = g_strstr_len(ptr, strlen(ptr), ":")) )
699 return FALSE;
700 nline = g_strndup(ptr, ptr2 - ptr);
701 line = atoi(nline);
703 file = g_file_new_for_path (path);
704 ianjuta_document_manager_goto_file_line_mark (sr->docman, file, line, TRUE, NULL);
705 g_object_unref (file);
706 g_free(path);
707 g_free(nline);
708 return FALSE;
711 static void
712 save_not_opened_files(FileBuffer *fb)
714 FILE *fp;
716 fp = fopen(fb->path, "wb");
717 if (!fp)
718 return;
719 fwrite(fb->buf, fb->len, 1, fp);
720 fclose(fp);
723 static gboolean
724 replace_in_not_opened_files(FileBuffer *fb, MatchInfo *mi, gchar *repl_str)
726 gint l;
727 g_return_val_if_fail (repl_str != NULL, FALSE);
729 if (strlen(repl_str) > mi->len)
731 l = fb->len - mi->pos;
732 fb->len = fb->len + strlen(repl_str) - mi->len;
733 if ( (fb->buf = g_realloc(fb->buf, fb->len)) == NULL )
734 return FALSE;
735 memmove((fb->buf) + mi->pos + strlen(repl_str) - mi->len, fb->buf + mi->pos,l);
737 if (strlen(repl_str) < mi->len)
739 l = fb->len - mi->pos - mi->len ;
740 memmove((fb->buf) + mi->pos + strlen(repl_str), fb->buf + mi->pos + mi->len,l);
741 fb->len = fb->len + strlen(repl_str) - mi->len;
742 if ( (fb->buf = g_realloc(fb->buf, fb->len)) == NULL)
743 return FALSE;
746 for (l=0; l < strlen(repl_str); l++)
747 (fb->buf)[(mi->pos)+l] = repl_str [l];
749 return TRUE;
753 static void
754 search_replace_next_previous(SearchDirection dir)
756 SearchDirection save_direction;
757 SearchAction save_action;
758 SearchRangeType save_type;
760 if (sr)
762 save_action = sr->search.action;
763 save_type = sr->search.range.type;
764 save_direction = sr->search.range.direction;
765 sr->search.range.direction = dir;
766 if (save_type == SR_OPEN_BUFFERS || save_type == SR_PROJECT ||
767 save_type == SR_FILES)
768 sr->search.range.direction = SR_BUFFER;
769 sr->search.action = SA_SELECT;
771 search_and_replace();
773 sr->search.action = save_action;
774 sr->search.range.type = save_type;
775 sr->search.range.direction = save_direction;
777 else
779 DEBUG_PRINT ("sr null\n");
783 void
784 search_replace_next(void)
786 search_replace_next_previous(SD_FORWARD);
789 void
790 search_replace_previous(void)
792 search_replace_next_previous(SD_BACKWARD);
795 /****************************************************************/
797 GladeWidget *
798 sr_get_gladewidget(GladeWidgetId id)
800 return &glade_widgets[id];
803 static void
804 search_set_popdown_strings (GtkComboBoxEntry *combo, GList* strings)
806 GtkListStore *store;
807 gboolean init;
809 init = gtk_combo_box_get_model (GTK_COMBO_BOX(combo)) == NULL;
811 store = gtk_list_store_new (1, G_TYPE_STRING);
812 for (; strings != NULL; strings = g_list_next(strings))
814 GtkTreeIter iter;
816 gtk_list_store_append (store, &iter);
817 gtk_list_store_set (store, &iter, 0, strings->data, -1);
819 gtk_combo_box_set_model (GTK_COMBO_BOX(combo), GTK_TREE_MODEL (store));
820 g_object_unref (store);
822 if (init) gtk_combo_box_entry_set_text_column (combo, 0);
825 static void
826 search_set_popdown_map (GtkComboBox *combo, AnjutaUtilStringMap *map)
828 GtkListStore *store;
829 gboolean init;
830 gint i;
832 init = gtk_combo_box_get_model (combo) == NULL;
834 store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
835 for (i = 0; map[i].type != -1; ++i)
837 GtkTreeIter iter;
839 gtk_list_store_append (store, &iter);
840 gtk_list_store_set (store, &iter, 0, map[i].name, 1, map[i].type, -1);
842 gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
843 g_object_unref (store);
844 gtk_combo_box_set_active (combo, 0);
846 if (init)
848 GtkCellRenderer *cell;
850 cell = gtk_cell_renderer_text_new ();
851 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
852 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
853 "text", 0, NULL);
857 static void
858 search_select_item(GtkComboBox* combo, gint item)
860 GtkTreeModel *model;
861 GtkTreeIter iter;
862 gboolean search;
864 model = gtk_combo_box_get_model(combo);
866 /* Find item corresponding to command */
867 for (search = gtk_tree_model_get_iter_first(model, &iter); search;
868 gtk_tree_model_iter_next (model, &iter))
870 gint id;
872 gtk_tree_model_get (model, &iter, 1, &id, -1);
874 if (id == item)
876 /* Find command */
877 gtk_combo_box_set_active_iter(combo, &iter);
878 break;
884 static void
885 search_set_combo(GladeWidgetId id_combo, gint command)
887 GtkComboBox *combo;
889 combo = GTK_COMBO_BOX(sr_get_gladewidget(id_combo)->widget);
890 search_select_item (combo, command);
893 static void
894 search_set_action(SearchAction action)
896 search_set_combo(SEARCH_ACTION_COMBO, action);
899 static void
900 search_set_target(SearchRangeType target)
902 search_set_combo(SEARCH_TARGET_COMBO, target);
905 static void
906 search_set_direction(SearchDirection dir)
908 search_set_combo(SEARCH_DIRECTION_COMBO, dir);
911 static gint
912 search_get_item_combo(GtkComboBox *combo)
914 gint item;
915 GtkTreeModel *model;
916 GtkTreeIter iter;
917 gboolean sel;
919 sel = gtk_combo_box_get_active_iter (combo, &iter);
920 model = gtk_combo_box_get_model (combo);
921 gtk_tree_model_get (model, &iter, 1, &item, -1);
923 return item;
926 static gint
927 search_get_item_combo_name(GladeWidgetId id)
929 GtkWidget *combo = sr_get_gladewidget(id)->widget;
930 return search_get_item_combo(GTK_COMBO_BOX(combo));
933 static void
934 search_direction_changed(SearchDirection dir)
936 SearchEntryType tgt;
937 SearchAction act;
939 tgt = search_get_item_combo_name(SEARCH_TARGET_COMBO);
940 if (dir != SD_BEGINNING)
942 if (tgt == SR_OPEN_BUFFERS || tgt == SR_PROJECT
943 || tgt == SR_FILES)
944 search_set_target(SR_BUFFER);
946 else
948 if (tgt == SR_BUFFER ||tgt == SR_SELECTION || tgt == SR_BLOCK ||
949 tgt == SR_FUNCTION)
950 search_set_target(SR_BUFFER);
951 else
953 act = search_get_item_combo_name(SEARCH_ACTION_COMBO);
954 if (act == SA_SELECT)
955 search_set_action(SA_BOOKMARK);
956 if (act == SA_REPLACE)
957 search_set_action(SA_REPLACEALL);
962 static void
963 populate_value(GladeWidgetId id, gpointer val_ptr)
965 GladeWidget *gw;
967 g_return_if_fail(id && val_ptr);
969 gw = sr_get_gladewidget(id);
970 g_return_if_fail(gw);
971 switch(gw->type)
973 case GE_COMBO_ENTRY:
974 case GE_TEXT:
975 if (*((char **) val_ptr))
976 g_free(* ((char **) val_ptr));
977 *((char **) val_ptr) = gtk_editable_get_chars(
978 GTK_EDITABLE(gw->widget), 0, -1);
979 break;
980 case GE_BOOLEAN:
981 * ((gboolean *) val_ptr) = gtk_toggle_button_get_active(
982 GTK_TOGGLE_BUTTON(gw->widget));
983 break;
984 case GE_COMBO:
985 g_return_if_fail (gw->extra != NULL);
987 *((int *) val_ptr) = search_get_item_combo (GTK_COMBO_BOX(gw->widget));
988 break;
989 default:
990 g_warning("Bad option %d to populate_value", gw->type);
991 break;
995 static void
996 reset_flags(void)
998 flag_select = FALSE;
999 interactive = FALSE;
1002 static void
1003 reset_flags_and_search_button(void)
1005 reset_flags();
1006 if (sr->search.action != SA_REPLACEALL)
1007 modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
1009 else
1010 modify_label_image_button(SEARCH_BUTTON, _("Replace All"),
1011 GTK_STOCK_FIND_AND_REPLACE);
1013 show_jump_button(FALSE);
1016 static void
1017 search_start_over (SearchDirection direction)
1019 IAnjutaDocument* doc = ianjuta_document_manager_get_current_document(sr->docman,
1020 NULL);
1021 IAnjutaEditor *te = NULL;
1022 if (IANJUTA_IS_EDITOR(doc))
1023 te = IANJUTA_EDITOR(doc);
1025 if (te)
1027 if (direction != SD_BACKWARD)
1028 /* search from doc start */
1029 ianjuta_editor_goto_start (te, NULL);
1030 else
1031 /* search from doc end */
1032 ianjuta_editor_goto_end (te, NULL);
1036 static void
1037 search_end_alert(gchar *string)
1039 GtkWidget *dialog;
1041 if (sr->search.range.direction != SD_BEGINNING && !flag_select)
1043 // Ask if user wants to wrap around the doc
1044 // Dialog to be made HIG compliant.
1045 dialog = gtk_message_dialog_new (GTK_WINDOW (sg->dialog),
1046 GTK_DIALOG_DESTROY_WITH_PARENT,
1047 GTK_MESSAGE_QUESTION,
1048 GTK_BUTTONS_YES_NO,
1049 _("The match \"%s\" was not found. Wrap search around the document?"),
1050 string);
1052 gtk_dialog_set_default_response (GTK_DIALOG (dialog),
1053 GTK_RESPONSE_YES);
1054 g_signal_connect(G_OBJECT(dialog), "key-press-event",
1055 G_CALLBACK(on_search_dialog_key_press_event), NULL);
1056 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES)
1058 search_start_over (sr->search.range.direction);
1059 gtk_widget_destroy(dialog);
1060 reset_flags();
1061 search_and_replace ();
1062 return;
1065 else
1067 dialog = gtk_message_dialog_new(GTK_WINDOW (sg->dialog),
1068 GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
1069 _("The match \"%s\" was not found."),
1070 string);
1071 g_signal_connect(G_OBJECT(dialog), "key-press-event",
1072 G_CALLBACK(on_search_dialog_key_press_event), NULL);
1073 gtk_dialog_run(GTK_DIALOG(dialog));
1075 gtk_widget_destroy(dialog);
1076 reset_flags();
1079 static void
1080 max_results_alert(void)
1082 GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW (sg->dialog),
1083 GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
1084 _("The maximum number of results has been reached."));
1085 g_signal_connect(G_OBJECT(dialog), "key-press-event",
1086 G_CALLBACK(on_search_dialog_key_press_event), NULL);
1087 gtk_dialog_run(GTK_DIALOG(dialog));
1088 gtk_widget_destroy(dialog);
1089 reset_flags();
1092 static void
1093 nb_results_alert(gint nb)
1095 GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW (sg->dialog),
1096 GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
1097 ngettext("%d match has been replaced.",
1098 "%d matches have been replaced.", nb), nb);
1099 g_signal_connect(G_OBJECT(dialog), "key-press-event",
1100 G_CALLBACK(on_search_dialog_key_press_event), NULL);
1101 gtk_dialog_run(GTK_DIALOG(dialog));
1102 gtk_widget_destroy(dialog);
1103 reset_flags();
1106 static void
1107 search_show_replace(gboolean hide)
1109 static GladeWidgetId hide_widgets[] = {
1110 REPLACE_REGEX, REPLACE_STRING_COMBO, LABEL_REPLACE
1112 int i;
1113 GtkWidget *widget;
1115 for (i=0; i < sizeof(hide_widgets)/sizeof(hide_widgets[0]); ++i)
1117 widget = sr_get_gladewidget(hide_widgets[i])->widget;
1118 if (NULL != widget)
1120 if (hide)
1121 gtk_widget_show(widget);
1122 else
1123 gtk_widget_hide(widget);
1128 static void
1129 modify_label_image_button(GladeWidgetId button_id, gchar *name, char *stock_image)
1131 GList *list, *l;
1132 GtkHBox *hbox;
1133 GtkWidget *alignment;
1134 GtkWidget *button = sr_get_gladewidget(button_id)->widget;
1136 list = gtk_container_get_children(GTK_CONTAINER (button));
1137 alignment = GTK_WIDGET(list->data);
1138 g_list_free(list);
1139 list = gtk_container_get_children(GTK_CONTAINER (alignment));
1140 hbox = GTK_HBOX(list->data);
1141 g_list_free(list);
1142 list = gtk_container_get_children(GTK_CONTAINER (hbox));
1143 for (l=list; l; l = g_list_next(l))
1145 if (GTK_IS_LABEL(l->data))
1146 gtk_label_set_text(GTK_LABEL(l->data), name);
1147 if (GTK_IS_IMAGE(l->data))
1148 gtk_image_set_from_stock(GTK_IMAGE(l->data), stock_image,
1149 GTK_ICON_SIZE_BUTTON);
1151 g_list_free(list);
1155 /********************************************************************/
1157 #define POP_LIST(str, var) populate_value(str, &s);\
1158 if (s) \
1160 sr->search.range.files.var = anjuta_util_glist_from_string(s);\
1163 /********************************************************************/
1165 void
1166 search_replace_populate(void)
1168 char *s = NULL;
1169 char *max = NULL;
1171 /* Now, populate the instance with values from the GUI */
1172 populate_value(SEARCH_STRING, &(sr->search.expr.search_str));
1173 populate_value(SEARCH_REGEX, &(sr->search.expr.regex));
1174 populate_value(GREEDY, &(sr->search.expr.greedy));
1175 populate_value(IGNORE_CASE, &(sr->search.expr.ignore_case));
1176 populate_value(WHOLE_WORD, &(sr->search.expr.whole_word));
1177 populate_value(WHOLE_LINE, &(sr->search.expr.whole_line));
1178 populate_value(WORD_START, &(sr->search.expr.word_start));
1179 populate_value(SEARCH_TARGET_COMBO, &(sr->search.range.type));
1180 populate_value(SEARCH_DIRECTION_COMBO, &(sr->search.range.direction));
1181 populate_value(ACTIONS_NO_LIMIT, &(sr->search.expr.no_limit));
1183 populate_value(SEARCH_BASIC, &(sr->search.basic_search));
1185 if (sr->search.expr.no_limit)
1186 sr->search.expr.actions_max = G_MAXINT;
1187 else
1189 populate_value(ACTIONS_MAX, &(max));
1190 sr->search.expr.actions_max = atoi(max);
1191 if (sr->search.expr.actions_max <= 0)
1192 sr->search.expr.actions_max = 200;
1193 g_free(max);
1196 switch (sr->search.range.type)
1198 case SR_FUNCTION:
1199 case SR_BLOCK:
1200 if (flag_select)
1201 sr->search.range.type = SR_SELECTION;
1202 break;
1203 case SR_FILES:
1204 POP_LIST(MATCH_FILES, match_files);
1205 POP_LIST(UNMATCH_FILES, ignore_files);
1206 POP_LIST(MATCH_DIRS, match_dirs);
1207 POP_LIST(UNMATCH_DIRS, ignore_dirs);
1208 populate_value(IGNORE_HIDDEN_FILES, &(sr->search.range.files.ignore_hidden_files));
1209 populate_value(IGNORE_HIDDEN_DIRS, &(sr->search.range.files.ignore_hidden_dirs));
1210 populate_value(SEARCH_RECURSIVE, &(sr->search.range.files.recurse));
1211 break;
1212 default:
1213 break;
1215 populate_value(SEARCH_ACTION_COMBO, &(sr->search.action));
1216 switch (sr->search.action)
1218 case SA_REPLACE:
1219 case SA_REPLACEALL:
1220 populate_value(REPLACE_STRING, &(sr->replace.repl_str));
1221 populate_value(REPLACE_REGEX, &(sr->replace.regex));
1222 break;
1223 default:
1224 break;
1228 static void
1229 show_jump_button (gboolean show)
1231 GtkWidget *jump_button = sr_get_gladewidget(JUMP_BUTTON)->widget;
1232 if (show)
1233 gtk_widget_show(jump_button);
1234 else
1235 gtk_widget_hide(jump_button);
1238 static
1239 void translate_dialog_strings (AnjutaUtilStringMap labels[])
1241 guint i = 0;
1242 while (labels[i].name != NULL)
1244 labels[i].name = gettext (labels[i].name);
1245 i++;
1249 static gboolean
1250 create_dialog(void)
1252 GladeWidget *w;
1253 GtkWidget *widget;
1254 int i;
1256 g_return_val_if_fail(NULL != sr, FALSE);
1257 if (NULL != sg) return TRUE;
1258 sg = g_new0(SearchReplaceGUI, 1);
1260 if (NULL == (sg->xml = glade_xml_new(GLADE_FILE_SEARCH_REPLACE,
1261 SEARCH_REPLACE_DIALOG, NULL)))
1263 anjuta_util_dialog_error(NULL, _("Unable to build user interface for Search And Replace"));
1264 g_free(sg);
1265 sg = NULL;
1266 return FALSE;
1268 sg->dialog = glade_xml_get_widget(sg->xml, SEARCH_REPLACE_DIALOG);
1269 /* gtk_window_set_transient_for (GTK_WINDOW(sg->dialog)
1270 , GTK_WINDOW(app->widgets.window)); */
1272 if (!labels_translated)
1274 labels_translated = TRUE;
1275 translate_dialog_strings (search_direction_strings);
1276 translate_dialog_strings (search_target_strings);
1277 translate_dialog_strings (search_action_strings);
1280 for (i=0; NULL != glade_widgets[i].name; ++i)
1282 w = &(glade_widgets[i]);
1283 w->widget = glade_xml_get_widget(sg->xml, w->name);
1284 if (GE_COMBO_ENTRY == w->type)
1286 /* Get child of GtkComboBoxEntry */
1287 w->widget = GTK_BIN(w->widget)->child;
1289 gtk_widget_ref(w->widget);
1290 if (GE_COMBO == w->type && NULL != w->extra)
1292 search_set_popdown_map(GTK_COMBO_BOX(w->widget), (AnjutaUtilStringMap *)w->extra);
1296 widget = sr_get_gladewidget(SEARCH_STRING_COMBO)->widget;
1297 g_signal_connect (widget, "changed", G_CALLBACK (on_search_expression_changed), NULL);
1298 widget = sr_get_gladewidget(SEARCH_STRING)->widget;
1299 g_signal_connect (widget, "activate", G_CALLBACK (on_search_expression_activate), NULL);
1300 widget = sr_get_gladewidget(REPLACE_STRING)->widget;
1301 g_signal_connect (widget, "activate", G_CALLBACK (on_search_expression_activate), NULL);
1302 widget = sr_get_gladewidget(SEARCH_ACTION_COMBO)->widget;
1303 g_signal_connect (widget, "changed", G_CALLBACK (on_search_action_changed), NULL);
1304 widget = sr_get_gladewidget(SEARCH_DIRECTION_COMBO)->widget;
1305 g_signal_connect (widget, "changed", G_CALLBACK (on_search_direction_changed), NULL);
1306 widget = sr_get_gladewidget(SEARCH_TARGET_COMBO)->widget;
1307 g_signal_connect (widget, "changed", G_CALLBACK (on_search_target_changed), NULL);
1310 search_preferences_initialize_setting_treeview(sg->dialog);
1311 search_preferences_init();
1313 glade_xml_signal_autoconnect(sg->xml);
1314 return TRUE;
1317 static void
1318 show_dialog(void)
1320 gtk_window_present (GTK_WINDOW (sg->dialog));
1321 sg->showing = TRUE;
1324 static gboolean
1325 word_in_list(GList *list, gchar *word)
1327 GList *l = list;
1329 while (l != NULL)
1331 if (strcmp(l->data, word) == 0)
1332 return TRUE;
1333 l = g_list_next(l);
1335 return FALSE;
1338 /* Remove last item of the list if > nb_max */
1340 static GList*
1341 list_max_items(GList *list, guint nb_max)
1343 GList *last;
1345 if (g_list_length(list) > nb_max)
1347 last = g_list_last(list);
1348 g_free(last->data);
1349 list = g_list_delete_link (list, last);
1351 return list;
1354 #define MAX_ITEMS_SEARCH_COMBO 16
1356 static void
1357 search_update_combos(void)
1359 GtkWidget *search_entry = NULL;
1360 gchar *search_word = NULL;
1361 IAnjutaDocument* doc = ianjuta_document_manager_get_current_document(sr->docman,
1362 NULL);
1363 IAnjutaEditor *te = NULL;
1364 if (IANJUTA_IS_EDITOR(doc))
1365 te = IANJUTA_EDITOR(doc);
1367 search_entry = sr_get_gladewidget(SEARCH_STRING)->widget;
1368 if (search_entry && te)
1370 search_word = g_strdup(gtk_entry_get_text(GTK_ENTRY (search_entry)));
1371 if (search_word && strlen(search_word) > 0)
1373 if (!word_in_list(sr->search.expr_history, search_word))
1375 GtkWidget *search_list =
1376 sr_get_gladewidget(SEARCH_STRING_COMBO)->widget;
1377 sr->search.expr_history = g_list_prepend(sr->search.expr_history,
1378 search_word);
1379 sr->search.expr_history = list_max_items(sr->search.expr_history,
1380 MAX_ITEMS_SEARCH_COMBO);
1381 search_set_popdown_strings(GTK_COMBO_BOX_ENTRY (search_list),
1382 sr->search.expr_history);
1384 //search_toolbar_set_text(search_word);
1385 // FIXME comboentry instead of entry
1386 //~ entry_set_text_n_select (app->widgets.toolbar.main_toolbar.find_entry,
1387 //~ search_word, FALSE);
1393 static void
1394 replace_update_combos(void)
1396 GtkWidget *replace_entry = NULL;
1397 gchar *replace_word = NULL;
1398 IAnjutaDocument* doc = ianjuta_document_manager_get_current_document(sr->docman,
1399 NULL);
1400 IAnjutaEditor *te = NULL;
1401 if (IANJUTA_IS_EDITOR(doc))
1402 te = IANJUTA_EDITOR(doc);
1404 replace_entry = sr_get_gladewidget(REPLACE_STRING)->widget;
1405 if (replace_entry && te)
1407 replace_word = g_strdup(gtk_entry_get_text(GTK_ENTRY (replace_entry)));
1408 if (replace_word && strlen(replace_word) > 0)
1410 if (!word_in_list(sr->replace.expr_history, replace_word))
1412 GtkWidget *replace_list =
1413 sr_get_gladewidget(REPLACE_STRING_COMBO)->widget;
1414 sr->replace.expr_history = g_list_prepend(sr->replace.expr_history,
1415 replace_word);
1416 sr->replace.expr_history = list_max_items(sr->replace.expr_history,
1417 MAX_ITEMS_SEARCH_COMBO);
1418 search_set_popdown_strings(GTK_COMBO_BOX_ENTRY (replace_list),
1419 sr->replace.expr_history);
1425 void
1426 search_update_dialog(void)
1428 GtkWidget *widget;
1429 Search *s;
1431 s = &(sr->search);
1432 widget = sr_get_gladewidget(SEARCH_REGEX)->widget;
1433 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.regex);
1434 widget = sr_get_gladewidget(GREEDY)->widget;
1435 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.greedy);
1436 widget = sr_get_gladewidget(IGNORE_CASE)->widget;
1437 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.ignore_case);
1438 widget = sr_get_gladewidget(WHOLE_WORD)->widget;
1439 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.whole_word);
1440 widget = sr_get_gladewidget(WHOLE_LINE)->widget;
1441 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.whole_line);
1442 widget = sr_get_gladewidget(WORD_START)->widget;
1443 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.word_start);
1445 widget = sr_get_gladewidget(ACTIONS_NO_LIMIT)->widget;
1446 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->expr.no_limit);
1447 widget = sr_get_gladewidget(ACTIONS_MAX)->widget;
1448 gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), s->expr.actions_max);
1449 gtk_widget_set_sensitive (widget, !s->expr.no_limit);
1451 widget = sr_get_gladewidget(REPLACE_REGEX)->widget;
1452 gtk_widget_set_sensitive(widget, sr->search.expr.regex);
1454 widget = sr_get_gladewidget(SEARCH_BUTTON)->widget;
1455 gtk_widget_set_sensitive (widget, (s->expr.search_str != NULL) && (*s->expr.search_str != '\0'));
1457 widget = sr_get_gladewidget(SEARCH_STRING)->widget;
1458 if (s->expr.search_str)
1459 gtk_entry_set_text(GTK_ENTRY(widget), s->expr.search_str);
1461 widget = sr_get_gladewidget(SEARCH_DIRECTION_COMBO)->widget;
1462 search_select_item (GTK_COMBO_BOX(widget), s->range.direction);
1464 widget = sr_get_gladewidget(SEARCH_ACTION_COMBO)->widget;
1465 search_select_item (GTK_COMBO_BOX(widget), s->action);
1467 search_show_replace(s->action == SA_REPLACE || s->action == SA_REPLACEALL);
1469 widget = sr_get_gladewidget(SEARCH_TARGET_COMBO)->widget;
1470 search_select_item (GTK_COMBO_BOX(widget), s->range.type);
1472 widget = sr_get_gladewidget(SEARCH_BASIC)->widget;
1473 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), s->basic_search);
1475 widget = sr_get_gladewidget(STOP_BUTTON)->widget;
1476 gtk_widget_set_sensitive (widget, FALSE);
1478 basic_search_toggled();
1481 /* -------------- Callbacks --------------------- */
1483 gboolean
1484 on_search_replace_delete_event(GtkWidget *window, GdkEvent *event,
1485 gboolean user_data)
1487 if (sg->showing)
1489 gtk_widget_hide(sg->dialog);
1490 sg->showing = FALSE;
1492 return TRUE;
1495 gboolean
1496 on_search_dialog_key_press_event(GtkWidget *widget, GdkEventKey *event,
1497 gpointer user_data)
1499 if (event->keyval == GDK_Escape)
1501 if (user_data)
1503 /* Escape pressed in Find window */
1504 gtk_widget_hide(widget);
1505 sg->showing = FALSE;
1507 else
1509 /* Escape pressed in wrap yes/no window */
1510 gtk_dialog_response (GTK_DIALOG (widget), GTK_RESPONSE_NO);
1512 return TRUE;
1514 else
1516 if ( (event->state & GDK_CONTROL_MASK) &&
1517 ((event->keyval & 0x5F) == GDK_G))
1519 if (event->state & GDK_SHIFT_MASK)
1520 search_replace_previous();
1521 else
1522 search_replace_next();
1524 return FALSE;
1528 static void
1529 search_disconnect_set_toggle_connect(GladeWidgetId id, GCallback function,
1530 gboolean active)
1532 GtkWidget *button;
1534 button = sr_get_gladewidget(id)->widget;
1535 g_signal_handlers_disconnect_by_func(G_OBJECT(button), function, NULL);
1536 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
1537 g_signal_connect(G_OBJECT(button), "toggled", function, NULL);
1541 void
1542 on_search_match_whole_word_toggled (GtkToggleButton *togglebutton,
1543 gpointer user_data)
1545 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)))
1547 search_disconnect_set_toggle_connect(WHOLE_LINE, (GCallback)
1548 on_search_match_whole_line_toggled, FALSE);
1549 search_disconnect_set_toggle_connect(WORD_START, (GCallback)
1550 on_search_match_word_start_toggled, FALSE);
1554 void
1555 on_search_match_whole_line_toggled (GtkToggleButton *togglebutton,
1556 gpointer user_data)
1558 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)))
1560 search_disconnect_set_toggle_connect(WHOLE_WORD, (GCallback)
1561 on_search_match_whole_word_toggled, FALSE);
1562 search_disconnect_set_toggle_connect(WORD_START, (GCallback)
1563 on_search_match_word_start_toggled, FALSE);
1567 void
1568 on_search_match_word_start_toggled (GtkToggleButton *togglebutton,
1569 gpointer user_data)
1571 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)))
1573 search_disconnect_set_toggle_connect(WHOLE_WORD, (GCallback)
1574 on_search_match_whole_word_toggled, FALSE);
1575 search_disconnect_set_toggle_connect(WHOLE_LINE, (GCallback)
1576 on_search_match_whole_line_toggled, FALSE);
1581 static void
1582 search_make_sensitive(gboolean sensitive)
1584 static char *widgets[] = {
1585 SEARCH_EXPR_FRAME, SEARCH_TARGET_FRAME, CLOSE_BUTTON, SEARCH_BUTTON,
1586 JUMP_BUTTON
1588 gint i;
1589 GtkWidget *widget;
1591 for (i=0; i < sizeof(widgets)/sizeof(widgets[0]); ++i)
1593 widget = sr_get_gladewidget(widgets[i])->widget;
1594 if (NULL != widget)
1595 gtk_widget_set_sensitive(widget, sensitive);
1600 void
1601 on_search_regex_toggled (GtkToggleButton *togglebutton, gpointer user_data)
1603 static GladeWidgetId dependent_widgets[] = {
1604 WHOLE_WORD, WHOLE_LINE, WORD_START,
1605 SEARCH_BACKWARD, SEARCH_FULL_BUFFER
1607 int i;
1608 GtkWidget *dircombo = sr_get_gladewidget(SEARCH_DIRECTION_COMBO)->widget;
1609 GtkWidget *repl_regex = sr_get_gladewidget(REPLACE_REGEX)->widget;
1610 GtkWidget *widget;
1611 gboolean state = gtk_toggle_button_get_active(togglebutton);
1613 if (state)
1615 search_set_direction(SD_FORWARD);
1618 gtk_widget_set_sensitive(dircombo, !state);
1619 gtk_widget_set_sensitive(repl_regex, state);
1621 for (i=0; i < sizeof(dependent_widgets)/sizeof(dependent_widgets[0]); ++i)
1623 widget = sr_get_gladewidget(dependent_widgets[i])->widget;
1624 if (NULL != widget)
1626 gtk_widget_set_sensitive(widget, !state);
1627 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
1632 static void
1633 search_set_toggle_direction(SearchDirection dir)
1635 switch (dir)
1637 case SD_FORWARD :
1638 search_disconnect_set_toggle_connect(SEARCH_FORWARD, (GCallback)
1639 on_search_forward_toggled, TRUE);
1640 break;
1641 case SD_BACKWARD :
1642 search_disconnect_set_toggle_connect(SEARCH_BACKWARD, (GCallback)
1643 on_search_backward_toggled, TRUE);
1644 break;
1645 case SD_BEGINNING :
1646 search_disconnect_set_toggle_connect(SEARCH_FULL_BUFFER, (GCallback)
1647 on_search_full_buffer_toggled, TRUE);
1648 break;
1652 void
1653 on_search_direction_changed (GtkComboBox *combo, gpointer user_data)
1655 SearchDirection dir;
1657 dir = search_get_item_combo(combo);
1658 search_set_toggle_direction(dir);
1659 search_direction_changed(dir);
1662 void
1663 on_search_action_changed (GtkComboBox *combo, gpointer user_data)
1665 SearchAction act;
1666 SearchRangeType rt;
1668 reset_flags();
1669 act = search_get_item_combo(combo);
1670 rt = search_get_item_combo_name(SEARCH_TARGET_COMBO);
1671 show_jump_button (FALSE);
1672 switch(act)
1674 case SA_SELECT:
1675 search_show_replace(FALSE);
1676 modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
1677 if (rt == SR_OPEN_BUFFERS || rt == SR_PROJECT ||
1678 rt == SR_FILES)
1679 search_set_target(SR_BUFFER);
1680 break;
1681 case SA_REPLACE:
1682 search_show_replace(TRUE);
1683 modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
1684 if (rt == SR_OPEN_BUFFERS || rt == SR_PROJECT ||
1685 rt == SR_FILES)
1686 search_set_target(SR_BUFFER);
1687 break;
1688 case SA_REPLACEALL:
1689 search_show_replace(TRUE);
1690 modify_label_image_button(SEARCH_BUTTON, _("Replace All"),
1691 GTK_STOCK_FIND_AND_REPLACE);
1692 break;
1693 default:
1694 search_show_replace(FALSE);
1695 modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
1696 break;
1700 void
1701 on_search_target_changed(GtkComboBox *combo, gpointer user_data)
1703 SearchRangeType tgt;
1704 SearchDirection dir;
1705 SearchAction act;
1706 GtkWidget *search_var_frame = sr_get_gladewidget(SEARCH_VAR_FRAME)->widget;
1707 GtkWidget *file_filter_frame = sr_get_gladewidget(FILE_FILTER_FRAME)->widget;
1709 tgt = search_get_item_combo(combo);
1710 switch(tgt)
1712 case SR_FILES:
1713 gtk_widget_hide(search_var_frame);
1714 gtk_widget_show(file_filter_frame);
1715 break;
1716 default:
1717 gtk_widget_hide(search_var_frame);
1718 gtk_widget_hide(file_filter_frame);
1719 break;
1722 dir = search_get_item_combo_name(SEARCH_DIRECTION_COMBO);
1724 if (tgt == SR_SELECTION || tgt == SR_BLOCK || tgt == SR_FUNCTION)
1727 if (dir == SD_BEGINNING)
1729 search_set_direction(SD_FORWARD);
1732 if (tgt == SR_OPEN_BUFFERS || tgt == SR_PROJECT ||
1733 tgt == SR_FILES)
1735 search_set_direction(SD_BEGINNING);
1737 act = search_get_item_combo_name(SEARCH_ACTION_COMBO);
1738 if (act != SA_REPLACE && act != SA_REPLACEALL)
1740 if (tgt == SR_OPEN_BUFFERS)
1741 search_set_action(SA_BOOKMARK);
1742 else
1743 search_set_action(SA_FIND_PANE);
1745 else
1747 search_set_action(SA_REPLACEALL);
1748 sr->search.action = SA_REPLACEALL;
1751 reset_flags_and_search_button();
1752 /* Resize dialog */
1753 gtk_window_resize(GTK_WINDOW(sg->dialog), 10, 10);
1756 void
1757 on_search_expression_changed(GtkComboBox *combo, gpointer user_data)
1759 GtkWidget *search_entry = sr_get_gladewidget(SEARCH_STRING)->widget;
1760 GtkWidget *widget = sr_get_gladewidget(SEARCH_BUTTON)->widget;
1761 gboolean sensitive;
1763 sensitive = *gtk_entry_get_text (GTK_ENTRY (search_entry)) == '\0' ? FALSE: TRUE;
1764 gtk_widget_set_sensitive (widget, sensitive);
1768 void
1769 on_actions_no_limit_clicked(GtkButton *button, gpointer user_data)
1771 GtkWidget *actions_max = sr_get_gladewidget(ACTIONS_MAX)->widget;
1773 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
1774 gtk_widget_set_sensitive (actions_max, FALSE);
1775 else
1776 gtk_widget_set_sensitive (actions_max, TRUE);
1779 void
1780 on_search_button_close_clicked(GtkButton *button, gpointer user_data)
1782 if (sg->showing)
1784 gtk_widget_hide(sg->dialog);
1785 sg->showing = FALSE;
1789 void
1790 on_search_button_stop_clicked(GtkButton *button, gpointer user_data)
1792 end_activity = TRUE;
1795 void
1796 on_search_button_next_clicked(GtkButton *button, gpointer user_data)
1798 if (sr->search.expr.regex_info)
1800 g_regex_unref (sr->search.expr.regex_info);
1801 sr->search.expr.regex_info = NULL;
1803 search_replace_populate();
1805 search_and_replace();
1808 void search_replace_find_usage(const gchar *symbol)
1810 gchar *project_root_uri = NULL;
1811 SearchReplace *old_sr = sr;
1812 AnjutaShell* shell;
1814 sr = g_new (SearchReplace, 1);
1816 sr->search.expr.search_str = g_strdup (symbol);
1817 sr->search.expr.regex = FALSE;
1818 sr->search.expr.greedy = FALSE;
1819 sr->search.expr.ignore_case = FALSE;
1820 sr->search.expr.whole_word = TRUE;
1821 sr->search.expr.whole_line = FALSE;
1822 sr->search.expr.word_start = FALSE;
1823 sr->search.expr.no_limit = TRUE;
1824 sr->search.expr.actions_max = G_MAXINT;
1825 sr->search.expr.regex_info = NULL;
1827 g_object_get(G_OBJECT(sr->docman), "shell", &shell, NULL);
1829 anjuta_shell_get (shell,
1830 "project_root_uri", G_TYPE_STRING,
1831 &project_root_uri, NULL);
1833 sr->search.range.type =
1834 project_root_uri != NULL ? SR_PROJECT : SR_OPEN_BUFFERS;
1835 g_free (project_root_uri);
1837 sr->search.range.direction = SD_BEGINNING;
1839 sr->search.range.var = NULL;
1841 sr->search.range.files.top_dir = NULL;
1842 sr->search.range.files.match_files = NULL;
1843 sr->search.range.files.match_dirs = NULL;
1844 sr->search.range.files.ignore_files = NULL;
1845 sr->search.range.files.ignore_dirs = NULL;
1846 sr->search.range.files.ignore_hidden_files = TRUE;
1847 sr->search.range.files.ignore_hidden_dirs = TRUE;
1848 sr->search.range.files.recurse = TRUE;
1850 sr->search.action = SA_FIND_PANE;
1852 sr->search.expr_history = NULL;
1853 sr->search.incremental_pos = 0;
1854 sr->search.incremental_wrap = TRUE;
1856 create_dialog ();
1858 search_and_replace();
1859 g_free (sr);
1860 sr = old_sr;
1863 void
1864 on_search_button_jump_clicked(GtkButton *button, gpointer user_data)
1866 if (sr)
1867 interactive = FALSE;
1868 gtk_widget_hide(GTK_WIDGET(button));
1870 search_replace_populate();
1871 search_and_replace();
1874 void
1875 on_search_expression_activate (GtkEditable *edit, gpointer user_data)
1877 GtkWidget *combo;
1879 search_replace_populate();
1881 search_and_replace();
1882 combo = GTK_WIDGET(edit)->parent;
1883 reset_flags_and_search_button();
1887 void
1888 on_search_full_buffer_toggled (GtkToggleButton *togglebutton,
1889 gpointer user_data)
1891 if (gtk_toggle_button_get_active(togglebutton))
1893 search_set_direction(SD_BEGINNING);
1897 void
1898 on_search_forward_toggled (GtkToggleButton *togglebutton,
1899 gpointer user_data)
1901 if (gtk_toggle_button_get_active(togglebutton))
1903 search_set_direction(SD_FORWARD);
1907 void
1908 on_search_backward_toggled (GtkToggleButton *togglebutton,
1909 gpointer user_data)
1911 if (gtk_toggle_button_get_active(togglebutton))
1913 search_set_direction(SD_BACKWARD);
1917 void
1918 on_setting_basic_search_toggled (GtkToggleButton *togglebutton,
1919 gpointer user_data)
1921 SearchAction act;
1922 GtkWidget *frame_basic = sr_get_gladewidget(FRAME_SEARCH_BASIC)->widget;
1924 if (gtk_toggle_button_get_active(togglebutton))
1926 gtk_widget_show(frame_basic);
1927 search_set_target(SR_BUFFER);
1928 search_set_direction(SD_FORWARD);
1930 act = search_get_item_combo_name(SEARCH_ACTION_COMBO);
1931 if (act == SA_REPLACE || act == SA_REPLACEALL)
1932 search_set_action(SA_REPLACE);
1933 else
1934 search_set_action(SA_SELECT);
1936 else
1937 gtk_widget_hide(frame_basic);
1941 static void
1942 basic_search_toggled(void)
1944 GtkToggleButton *togglebutton;
1946 togglebutton = GTK_TOGGLE_BUTTON(sr_get_gladewidget(SEARCH_BASIC)->widget);
1948 on_setting_basic_search_toggled (togglebutton, NULL);
1951 /***********************************************************************/
1953 #define MAX_LENGTH_SEARCH 64
1955 void
1956 anjuta_search_replace_activate (gboolean replace, gboolean project)
1958 GtkWidget *notebook;
1959 GtkWidget *search_entry;
1960 IAnjutaDocument *doc;
1961 IAnjutaEditor *te;
1963 create_dialog ();
1965 search_update_dialog();
1967 search_replace_populate();
1969 reset_flags_and_search_button();
1971 search_entry = sr_get_gladewidget(SEARCH_STRING)->widget;
1972 doc = ianjuta_document_manager_get_current_document(sr->docman, NULL);
1973 te = (IANJUTA_IS_EDITOR (doc)) ? IANJUTA_EDITOR (doc) : NULL;
1974 if (te && search_entry && sr->search.range.type != SR_SELECTION)
1976 /* Set properties */
1977 gchar *current_word;
1979 current_word = ianjuta_editor_selection_get
1980 (IANJUTA_EDITOR_SELECTION (te), NULL);
1981 if (current_word == NULL)
1982 current_word = ianjuta_editor_get_current_word (te, NULL);
1984 if (current_word && strlen(current_word) > 0 )
1986 if (strlen(current_word) > MAX_LENGTH_SEARCH)
1987 current_word[MAX_LENGTH_SEARCH] = '\0';
1988 gtk_entry_set_text(GTK_ENTRY (search_entry), current_word);
1989 g_free(current_word);
1993 if (replace)
1995 if ( !(sr->search.action == SA_REPLACE ||
1996 sr->search.action == SA_REPLACEALL))
1998 search_set_action(SA_REPLACE);
1999 sr->search.action = SA_REPLACE;
2000 search_show_replace(TRUE);
2003 else
2005 if (sr->search.action == SA_REPLACE || sr->search.action == SA_REPLACEALL)
2007 search_set_action(SA_SELECT);
2008 sr->search.action = SA_SELECT;
2009 search_show_replace(FALSE);
2012 if (sr->search.action != SA_REPLACEALL)
2013 modify_label_image_button(SEARCH_BUTTON, _("Search"), GTK_STOCK_FIND);
2015 if (project)
2017 search_set_target(SR_PROJECT);
2018 if (!replace)
2020 search_set_action (SA_FIND_PANE);
2021 search_set_direction (SD_BEGINNING);
2024 show_jump_button(FALSE);
2026 notebook = sr_get_gladewidget(SEARCH_NOTEBOOK)->widget;
2027 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0);
2029 /* Show the dialog */
2030 if (search_entry)
2031 gtk_widget_grab_focus (search_entry);
2032 show_dialog();