1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * anjuta
4  * Copyright (C) Johannes Schmid 2007 <jhs@gnome.org>
5  *
6  * anjuta is free software.
7  *
8  * You may redistribute it and/or modify it under the terms of the
9  * GNU General Public License, as published by the Free Software
10  * Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  *
13  * anjuta is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with anjuta.  If not, write to:
20  * 	The Free Software Foundation, Inc.,
21  * 	51 Franklin Street, Fifth Floor
22  * 	Boston, MA  02110-1301, USA.
23  */
24 
25 #include <glib/gi18n.h>
26 #include "search-box.h"
27 
28 #include <stdlib.h>
29 #include <gtk/gtk.h>
30 
31 #include <libanjuta/anjuta-shell.h>
32 #include <libanjuta/anjuta-status.h>
33 #include <libanjuta/anjuta-debug.h>
34 
35 #include <libanjuta/interfaces/ianjuta-editor.h>
36 #include <libanjuta/interfaces/ianjuta-editor-search.h>
37 #include <libanjuta/interfaces/ianjuta-editor-selection.h>
38 #include <libanjuta/interfaces/ianjuta-indicable.h>
39 
40 #define ANJUTA_STOCK_GOTO_LINE "anjuta-goto-line"
41 
42 /* width of the entries in chars, that include the space for the icon */
43 #define LINE_ENTRY_WIDTH 7
44 #define SEARCH_ENTRY_WIDTH 45
45 
46 /* Time spend to do search in the idle callback */
47 #define CONTINUOUS_SEARCH_TIMEOUT 0.1
48 
49 struct _SearchBoxPrivate
50 {
51 	GtkWidget* grid;
52 
53 	GtkWidget* search_entry;
54 	GtkWidget* replace_entry;
55 
56 	GtkWidget* close_button;
57 	GtkWidget* next_button;
58 	GtkWidget* previous_button;
59 
60 	GtkWidget* replace_button;
61 	GtkWidget* replace_all_button;
62 
63 	GtkWidget* goto_entry;
64 	GtkWidget* goto_button;
65 
66 	IAnjutaEditor* current_editor;
67 	AnjutaStatus* status;
68 	AnjutaShell* shell;
69 
70 	/* Search options popup menu */
71 	GtkWidget* popup_menu;
72 	GtkAction* case_action;
73 	GtkAction* highlight_action;
74 	GtkAction* regex_action;
75 
76 	gboolean case_sensitive;
77 	gboolean highlight_all;
78 	gboolean regex_mode;
79 
80 	IAnjutaEditorCell *start_highlight;
81 	IAnjutaEditorCell *end_highlight;
82 	guint idle_id;
83 
84 	GtkCssProvider *provider;
85 };
86 
87 #ifdef GET_PRIVATE
88 # undef GET_PRIVATE
89 #endif
90 #define GET_PRIVATE(o) \
91 	(G_TYPE_INSTANCE_GET_PRIVATE((o), SEARCH_TYPE_BOX, SearchBoxPrivate))
92 
93 G_DEFINE_TYPE (SearchBox, search_box, GTK_TYPE_HBOX);
94 
95 static void
on_search_box_hide(GtkWidget * button,SearchBox * search_box)96 on_search_box_hide (GtkWidget* button, SearchBox* search_box)
97 {
98 	search_box_hide (search_box);
99 }
100 
101 static void
on_document_changed(AnjutaDocman * docman,IAnjutaDocument * doc,SearchBox * search_box)102 on_document_changed (AnjutaDocman* docman, IAnjutaDocument* doc,
103 					SearchBox* search_box)
104 {
105 	if (!doc || !IANJUTA_IS_EDITOR (doc))
106 	{
107 		gtk_widget_hide (GTK_WIDGET (search_box));
108 		search_box->priv->current_editor = NULL;
109 	}
110 	else
111 	{
112 		search_box->priv->current_editor = IANJUTA_EDITOR (doc);
113 		if (search_box->priv->highlight_all) search_box_highlight_all (search_box);
114 	}
115 }
116 
117 static void
on_goto_activated(GtkWidget * widget,SearchBox * search_box)118 on_goto_activated (GtkWidget* widget, SearchBox* search_box)
119 {
120 	const gchar* str_line = gtk_entry_get_text (GTK_ENTRY (search_box->priv->goto_entry));
121 
122 	gint line = atoi (str_line);
123 	if (line > 0)
124 	{
125 		ianjuta_editor_goto_line (search_box->priv->current_editor, line, NULL);
126 	}
127 }
128 
129 static void
search_box_set_entry_color(SearchBox * search_box,gboolean found)130 search_box_set_entry_color (SearchBox* search_box, gboolean found)
131 {
132 	GtkStyleContext *context;
133 
134 	context = gtk_widget_get_style_context (GTK_WIDGET (search_box->priv->search_entry));
135 	if (!found)
136 	{
137 		gtk_style_context_add_class (context, "not-found");
138 	}
139 	else
140 	{
141 		gtk_style_context_remove_class (context, "not-found");
142 	}
143 }
144 
145 static gboolean
on_goto_key_pressed(GtkWidget * entry,GdkEventKey * event,SearchBox * search_box)146 on_goto_key_pressed (GtkWidget* entry, GdkEventKey* event, SearchBox* search_box)
147 {
148 	switch (event->keyval)
149 	{
150 		case GDK_KEY_0:
151 		case GDK_KEY_1:
152 		case GDK_KEY_2:
153 		case GDK_KEY_3:
154 		case GDK_KEY_4:
155 		case GDK_KEY_5:
156 		case GDK_KEY_6:
157 		case GDK_KEY_7:
158 		case GDK_KEY_8:
159 		case GDK_KEY_9:
160 		case GDK_KEY_KP_0:
161 		case GDK_KEY_KP_1:
162 		case GDK_KEY_KP_2:
163 		case GDK_KEY_KP_3:
164 		case GDK_KEY_KP_4:
165 		case GDK_KEY_KP_5:
166 		case GDK_KEY_KP_6:
167 		case GDK_KEY_KP_7:
168 		case GDK_KEY_KP_8:
169 		case GDK_KEY_KP_9:
170 		case GDK_KEY_Return:
171 		case GDK_KEY_KP_Enter:
172 		case GDK_KEY_BackSpace:
173 		case GDK_KEY_Delete:
174 		case GDK_KEY_Tab:
175 		{
176 			/* This is a number or enter which is ok */
177 			break;
178 		}
179 		case GDK_KEY_Escape:
180 		{
181 			search_box_hide (search_box);
182 		}
183 		default:
184 		{
185 			/* Not a number */
186 			gdk_beep ();
187 			return TRUE;
188 		}
189 	}
190 	return FALSE;
191 }
192 
193 static gboolean
on_search_box_key_pressed(GtkWidget * widget,GdkEventKey * event,SearchBox * search_box)194 on_search_box_key_pressed (GtkWidget* widget, GdkEventKey* event, SearchBox* search_box)
195 {
196 	switch (event->keyval)
197 	{
198 		case GDK_KEY_Escape:
199 		{
200 			gtk_widget_hide (GTK_WIDGET (search_box));
201 			search_box_set_entry_color (search_box, TRUE);
202 			if (search_box->priv->current_editor)
203 			{
204 				ianjuta_document_grab_focus (IANJUTA_DOCUMENT (search_box->priv->current_editor),
205 											 NULL);
206 			}
207 		}
208 		default:
209 		{
210 			/* Do nothing... */
211 		}
212 	}
213 	return FALSE;
214 }
215 
216 static gboolean
on_search_focus_out(GtkWidget * widget,GdkEvent * event,SearchBox * search_box)217 on_search_focus_out (GtkWidget* widget, GdkEvent* event, SearchBox* search_box)
218 {
219 	anjuta_status_pop (search_box->priv->status);
220 
221 	return FALSE;
222 }
223 
224 
225 /* Search regular expression in text, return TRUE and matching part as start and
226  * end integer position */
227 static gboolean
search_regex_in_text(const gchar * search_entry,const gchar * editor_text,gboolean search_forward,gint * start_pos,gint * end_pos)228 search_regex_in_text (const gchar* search_entry, const gchar* editor_text, gboolean search_forward, gint * start_pos, gint * end_pos)
229 {
230 	GRegex * regex;
231 	GMatchInfo *match_info;
232 	gboolean found;
233 	GError * err = NULL;
234 
235 	regex = g_regex_new (search_entry, 0, 0, &err);
236 	if (err)
237 	{
238 		g_message ("%s",err->message);
239 		g_error_free (err);
240 		g_regex_unref(regex);
241 		return FALSE;
242 	}
243 
244 	found = g_regex_match (regex, editor_text, 0, &match_info);
245 
246 	if (found)
247 	{
248 		if (search_forward)
249 			g_match_info_fetch_pos(match_info, 0, start_pos, end_pos);
250 		else
251 		{
252 			do
253 			{
254 				g_match_info_fetch_pos(match_info, 0, start_pos, end_pos);
255 			}
256 			while (g_match_info_next(match_info, NULL));
257 		}
258 
259 		*start_pos = g_utf8_pointer_to_offset(editor_text, &editor_text[*start_pos]);
260 		*end_pos = g_utf8_pointer_to_offset(editor_text, &editor_text[*end_pos]);
261 	}
262 
263 	if (regex)
264 		g_regex_unref(regex);
265 	if (match_info)
266 		g_match_info_free (match_info);
267 
268 	return found;
269 
270 }
271 
272 /* Search string in text, return TRUE and matching part as start and
273  * end integer position */
274 static gboolean
search_str_in_text(const gchar * search_entry,const gchar * editor_text,gboolean case_sensitive,gint * start_pos,gint * end_pos)275 search_str_in_text (const gchar* search_entry, const gchar* editor_text, gboolean case_sensitive, gint * start_pos, gint * end_pos)
276 {
277 	gboolean found;
278 
279 	if (strlen (editor_text) >= strlen (search_entry))
280 	{
281 		gchar* selected_text_case;
282 		gchar* search_text_case;
283 
284 		if (case_sensitive)
285 		{
286 			selected_text_case = g_strdup (editor_text);
287 			search_text_case = g_strdup (search_entry);
288 		}
289 		else
290 		{
291 			selected_text_case = g_utf8_casefold (editor_text, strlen (editor_text));
292 			search_text_case = g_utf8_casefold (search_entry, strlen (search_entry));
293 		}
294 
295 		gchar* strstr = g_strstr_len (selected_text_case, -1, search_text_case);
296 
297 		if (strstr)
298 		{
299 			*start_pos = g_utf8_pointer_to_offset(selected_text_case, strstr);
300 			*end_pos = g_utf8_pointer_to_offset(selected_text_case, strstr + strlen (search_entry));
301 			found = TRUE;
302 		}
303 
304 		g_free (selected_text_case);
305 		g_free (search_text_case);
306 	}
307 
308 	return found;
309 }
310 
311 /* Search string in editor, return TRUE and matching part as start and
312  * end editor cell */
313 static gboolean
editor_search(IAnjutaEditor * editor,const gchar * search_text,gboolean case_sensitive,gboolean search_forward,gboolean regex_mode,IAnjutaEditorCell * search_start,IAnjutaEditorCell * search_end,IAnjutaEditorCell ** result_start,IAnjutaEditorCell ** result_end)314 editor_search (IAnjutaEditor *editor,
315                const gchar *search_text,
316                gboolean case_sensitive,
317                gboolean search_forward,
318                gboolean regex_mode,
319                IAnjutaEditorCell* search_start,
320                IAnjutaEditorCell* search_end,
321                IAnjutaEditorCell** result_start,
322                IAnjutaEditorCell** result_end)
323 {
324 	gboolean found;
325 
326 	if (regex_mode)
327 	{
328 		gint start_pos;
329 		gint end_pos;
330 		gchar *text_to_search;
331 
332 		text_to_search = ianjuta_editor_get_text (editor,
333 		                                          IANJUTA_ITERABLE (search_start),
334 		                                          IANJUTA_ITERABLE (search_end), NULL);
335 
336 		found = search_regex_in_text (search_text, text_to_search, search_forward, &start_pos, &end_pos);
337 
338 		start_pos += ianjuta_iterable_get_position(IANJUTA_ITERABLE (search_start), NULL);
339 		end_pos += ianjuta_iterable_get_position(IANJUTA_ITERABLE (search_start), NULL);
340 
341 		if (found && start_pos >= 0)
342 		{
343 			*result_start = IANJUTA_EDITOR_CELL (ianjuta_editor_get_start_position (editor,
344 			                                                                        NULL));
345 			*result_end = IANJUTA_EDITOR_CELL (ianjuta_editor_get_start_position (editor,
346 			                                                                      NULL));
347 
348 			if (!ianjuta_iterable_set_position(IANJUTA_ITERABLE(*result_start), start_pos, NULL) ||
349 				!ianjuta_iterable_set_position(IANJUTA_ITERABLE(*result_end), end_pos, NULL))
350 			{
351 				g_object_unref(*result_start);
352 				g_object_unref(*result_end);
353 				found = FALSE;
354 			}
355 		}
356 
357 		g_free(text_to_search);
358 	}
359 	else
360 	{
361 		if (search_forward)
362 		{
363 			found = ianjuta_editor_search_forward (IANJUTA_EDITOR_SEARCH (editor),
364 			                                       search_text, case_sensitive,
365 			                                       search_start, search_end,
366 			                                       result_start,
367 			                                       result_end, NULL);
368 		}
369 		else
370 		{
371 			found = ianjuta_editor_search_backward (IANJUTA_EDITOR_SEARCH (editor),
372 			                                        search_text, case_sensitive,
373 			                                        search_end, search_start,
374 			                                        result_start,
375 			                                        result_end, NULL);
376 		}
377 	}
378 
379 	return found;
380 }
381 
382 gboolean
search_box_incremental_search(SearchBox * search_box,gboolean search_forward,gboolean search_next,gboolean wrap)383 search_box_incremental_search (SearchBox* search_box,
384                                gboolean search_forward,
385                                gboolean search_next,
386                                gboolean wrap)
387 {
388 	IAnjutaIterable* real_start;
389 	IAnjutaEditorCell* search_start;
390 	IAnjutaEditorCell* search_end;
391 	IAnjutaEditorCell* result_start;
392 	IAnjutaEditorCell* result_end;
393 	IAnjutaEditorSelection* selection;
394 
395 	const gchar* search_text = gtk_entry_get_text (GTK_ENTRY (search_box->priv->search_entry));
396 
397 	gboolean found = FALSE;
398 
399 	if (!search_box->priv->current_editor || !search_text || !strlen (search_text))
400 		return FALSE;
401 
402 	selection = IANJUTA_EDITOR_SELECTION (search_box->priv->current_editor);
403 
404 	if (ianjuta_editor_selection_has_selection (selection, NULL))
405 	{
406 		search_start =
407 			IANJUTA_EDITOR_CELL (ianjuta_editor_selection_get_start (selection, NULL));
408 	}
409 	else
410 	{
411 		search_start =
412 			IANJUTA_EDITOR_CELL (ianjuta_editor_get_position (search_box->priv->current_editor,
413 			                                                  NULL));
414 	}
415 
416 	real_start =
417 		ianjuta_iterable_clone (IANJUTA_ITERABLE (search_start), NULL);
418 
419 	/* If forward, set search start and end to current position of
420 	 * cursor and editor end, respectively, or if backward to editor
421 	 * start and current position of cursor, respectively. Current
422 	 * position of cursor is selection start if have selection. */
423 	if (search_forward)
424 	{
425 		search_end = IANJUTA_EDITOR_CELL (ianjuta_editor_get_position (search_box->priv->current_editor,
426 	                                                                   NULL));
427 		ianjuta_iterable_last (IANJUTA_ITERABLE (search_end), NULL);
428 	}
429 	else
430 	{
431 		search_end = search_start;
432 		search_start = IANJUTA_EDITOR_CELL (ianjuta_editor_get_position (search_box->priv->current_editor,
433 	                                                                     NULL));
434 		ianjuta_iterable_first (IANJUTA_ITERABLE (search_start), NULL);
435 	}
436 
437 	/* When there's a selection, if forward, set search start and end
438      * to match end and editor end, respectively, or if backward to
439      * editor start and match start, respectively. If forward and
440      * selection starts with a match, look for next match.
441 	 */
442 	if (ianjuta_editor_selection_has_selection (selection,
443 	                                            NULL) && search_next)
444 	{
445 		gchar* selected_text =
446 			ianjuta_editor_selection_get (selection, NULL);
447 
448 		gint start_pos, end_pos;
449 		gboolean selected_have_search_text = FALSE;
450 
451 		selected_have_search_text = search_box->priv->regex_mode ?
452 			search_regex_in_text (search_text, selected_text, TRUE, &start_pos, &end_pos) :
453 			search_str_in_text (search_text, selected_text, search_box->priv->case_sensitive, &start_pos, &end_pos);
454 
455 		if (selected_have_search_text)
456 		{
457 			IAnjutaIterable* selection_start =
458 				ianjuta_editor_selection_get_start (selection, NULL);
459 
460 			if (search_forward && start_pos == 0)
461 			{
462 				end_pos += ianjuta_iterable_get_position(IANJUTA_ITERABLE (selection_start), NULL);
463 				ianjuta_iterable_set_position (IANJUTA_ITERABLE(search_start), end_pos, NULL);
464 				ianjuta_iterable_last (IANJUTA_ITERABLE (search_end), NULL);
465 			}
466 			else if (!search_forward)
467 			{
468 				start_pos += ianjuta_iterable_get_position(IANJUTA_ITERABLE (selection_start), NULL);
469 				ianjuta_iterable_set_position (IANJUTA_ITERABLE(search_end), start_pos, NULL);
470 				ianjuta_iterable_first (IANJUTA_ITERABLE (search_start), NULL);
471 			}
472 			g_object_unref (selection_start);
473 		}
474 
475 		g_free (selected_text);
476 	}
477 
478 	/* Try searching in current position */
479 	found = editor_search (search_box->priv->current_editor,
480 	                       search_text,
481 	                       search_box->priv->case_sensitive,
482 	                       search_forward,
483 	                       search_box->priv->regex_mode,
484 	                       search_start,
485 	                       search_end,
486 	                       &result_start,
487 	                       &result_end);
488 
489 	if (found)
490 	{
491 		anjuta_status_pop (ANJUTA_STATUS (search_box->priv->status));
492 	}
493 	else if (wrap)
494 	{
495 		/* Try to wrap if not found */
496 		ianjuta_iterable_first (IANJUTA_ITERABLE (search_start), NULL);
497 		ianjuta_iterable_last (IANJUTA_ITERABLE (search_end), NULL);
498 
499 		/* Try to search again */
500 		found = editor_search (search_box->priv->current_editor,
501 		                       search_text,
502 		                       search_box->priv->case_sensitive,
503 		                       search_forward,
504 		                       search_box->priv->regex_mode,
505 		                       search_start,
506 		                       search_end,
507 		                       &result_start,
508 		                       &result_end);
509 
510 		/* Check if successful */
511 		if (found)
512 		{
513 			if (ianjuta_iterable_compare (IANJUTA_ITERABLE (result_start),
514 			                              real_start, NULL) != 0)
515 			{
516 				anjuta_status_pop (search_box->priv->status);
517 				if (search_forward)
518 				{
519 					anjuta_status_push (search_box->priv->status,
520 					                    _("Search for \"%s\" reached the end and was continued at the top."), search_text);
521 				}
522 				else
523 				{
524 					anjuta_status_push (search_box->priv->status,
525 					                    _("Search for \"%s\" reached top and was continued at the bottom."), search_text);
526 				}
527 			}
528 			else if (ianjuta_editor_selection_has_selection (selection, NULL))
529 			{
530 				found = FALSE;
531 				anjuta_status_pop (search_box->priv->status);
532 				if (search_forward)
533 				{
534 					anjuta_status_push (search_box->priv->status,
535 						                _("Search for \"%s\" reached the end and was continued at the top but no new match was found."), search_text);
536 				}
537 				else
538 				{
539 					anjuta_status_push (search_box->priv->status,
540 						                _("Search for \"%s\" reached top and was continued at the bottom but no new match was found."), search_text);
541 				}
542 			}
543 			else
544 			{
545 				found = FALSE;
546 			}
547 		}
548 	}
549 
550 	if (found)
551 	{
552 		ianjuta_editor_selection_set (selection,
553 		                              IANJUTA_ITERABLE (result_start),
554 		                              IANJUTA_ITERABLE (result_end), TRUE, NULL);
555 		g_object_unref (result_start);
556 		g_object_unref (result_end);
557 	}
558 	else
559 	{
560 		if(ianjuta_editor_selection_get (selection, NULL)!=NULL)
561 		{
562 			IAnjutaIterable* selection_start =
563 				ianjuta_editor_selection_get_start (selection, NULL);
564 			ianjuta_editor_selection_set (selection,
565 			                              IANJUTA_ITERABLE (selection_start),
566 			                              IANJUTA_ITERABLE (selection_start), TRUE, NULL);
567 			g_object_unref (selection_start);
568 		}
569 
570 	}
571 
572 	search_box_set_entry_color (search_box, found);
573 	g_object_unref (real_start);
574 	g_object_unref (search_start);
575 	g_object_unref (search_end);
576 
577 	return found;
578 }
579 
580 static gboolean
highlight_in_background(SearchBox * search_box)581 highlight_in_background (SearchBox *search_box)
582 {
583 	gboolean found = FALSE;
584 
585 
586 	if (search_box->priv->start_highlight != NULL)
587 	{
588 		const gchar* search_text = gtk_entry_get_text (GTK_ENTRY (search_box->priv->search_entry));
589 		GTimer *timer = g_timer_new();
590 
591 		if (*search_text != '\0')
592 		{
593 			do
594 			{
595 				IAnjutaEditorCell* result_start;
596 				IAnjutaEditorCell* result_end;
597 
598 				found = editor_search (search_box->priv->current_editor,
599 				                       search_text,
600 				                       search_box->priv->case_sensitive,
601 			        	               TRUE,
602 			                	       search_box->priv->regex_mode,
603 				                       search_box->priv->start_highlight,
604 				                       search_box->priv->end_highlight,
605 				                       &result_start,
606 				                       &result_end);
607 				if (found)
608 				{
609 					ianjuta_indicable_set(IANJUTA_INDICABLE(search_box->priv->current_editor),
610 					                      IANJUTA_ITERABLE (result_start),
611 					                      IANJUTA_ITERABLE (result_end),
612 				        	              IANJUTA_INDICABLE_IMPORTANT, NULL);
613 					g_object_unref (result_start);
614 					g_object_unref (search_box->priv->start_highlight);
615 					search_box->priv->start_highlight = result_end;
616 				}
617 			}
618 			while (found && g_timer_elapsed(timer, NULL) < CONTINUOUS_SEARCH_TIMEOUT);
619 		}
620 		g_timer_destroy (timer);
621 	}
622 
623 	if (!found)
624 	{
625 		search_box->priv->idle_id = 0;
626 		g_clear_object (&search_box->priv->start_highlight);
627 		g_clear_object (&search_box->priv->end_highlight);
628 	}
629 
630 	return found;
631 }
632 
633 void
search_box_highlight_all(SearchBox * search_box)634 search_box_highlight_all (SearchBox *search_box)
635 {
636 	if (!search_box->priv->current_editor)
637 		return;
638 
639 	ianjuta_indicable_clear(IANJUTA_INDICABLE(search_box->priv->current_editor), NULL);
640 	if (search_box->priv->start_highlight != NULL) g_object_unref (search_box->priv->start_highlight);
641 	if (search_box->priv->end_highlight != NULL) g_object_unref (search_box->priv->end_highlight);
642 	search_box->priv->start_highlight = IANJUTA_EDITOR_CELL (ianjuta_editor_get_start_position (search_box->priv->current_editor, NULL));
643 	search_box->priv->end_highlight = IANJUTA_EDITOR_CELL (ianjuta_editor_get_end_position (search_box->priv->current_editor, NULL));
644 
645 	if (search_box->priv->idle_id == 0)
646 	{
647 		search_box->priv->idle_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
648 		                                            (GSourceFunc)highlight_in_background,
649 		                                            search_box,
650 		                                            NULL);
651 	}
652 }
653 
654 void
search_box_clear_highlight(SearchBox * search_box)655 search_box_clear_highlight (SearchBox * search_box)
656 {
657 	if (!search_box->priv->current_editor)
658 		return;
659 
660 	ianjuta_indicable_clear(IANJUTA_INDICABLE(search_box->priv->current_editor), NULL);
661 }
662 
663 void
search_box_toggle_highlight(SearchBox * search_box,gboolean status)664 search_box_toggle_highlight (SearchBox * search_box, gboolean status)
665 {
666 	if (!search_box->priv->current_editor)
667 		return;
668 
669 	search_box->priv->highlight_all = status;
670 	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(search_box->priv->highlight_action),
671 	                             status);
672 
673 	if (!status)
674 	{
675 		ianjuta_indicable_clear(IANJUTA_INDICABLE(search_box->priv->current_editor), NULL);
676 		g_clear_object (&search_box->priv->start_highlight);
677 		g_clear_object (&search_box->priv->end_highlight);
678 	}
679 	else
680 	{
681 		search_box_highlight_all (search_box);
682 	}
683 }
684 
685 void
search_box_toggle_case_sensitive(SearchBox * search_box,gboolean status)686 search_box_toggle_case_sensitive (SearchBox * search_box, gboolean status)
687 {
688 	if (!search_box->priv->current_editor)
689 		return;
690 	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(search_box->priv->case_action),
691 	                             status);
692 
693 	search_box->priv->case_sensitive = status;
694 	if (search_box->priv->highlight_all) search_box_highlight_all (search_box);
695 }
696 
697 void
search_box_toggle_regex(SearchBox * search_box,gboolean status)698 search_box_toggle_regex (SearchBox * search_box, gboolean status)
699 {
700 	if (!search_box->priv->current_editor)
701 		return;
702 
703 	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(search_box->priv->regex_action),
704 	                             status);
705 
706 	search_box->priv->regex_mode = status;
707 	if (search_box->priv->highlight_all) search_box_highlight_all (search_box);
708 }
709 
710 static void
on_search_box_entry_changed(GtkWidget * widget,SearchBox * search_box)711 on_search_box_entry_changed (GtkWidget * widget, SearchBox * search_box)
712 {
713 	if (!search_box->priv->regex_mode)
714 	{
715 		GtkEntryBuffer* buffer = gtk_entry_get_buffer (GTK_ENTRY(widget));
716 		if (gtk_entry_buffer_get_length (buffer))
717 			search_box_incremental_search (search_box, TRUE, FALSE, TRUE);
718 		else
719 		{
720 			/* clear selection */
721 			IAnjutaIterable* cursor =
722 				ianjuta_editor_get_position (IANJUTA_EDITOR (search_box->priv->current_editor),
723 				                             NULL);
724 			ianjuta_editor_selection_set (IANJUTA_EDITOR_SELECTION (search_box->priv->current_editor),
725 			                              cursor,
726 			                              cursor,
727 			                              FALSE, NULL);
728 		}
729 	}
730 
731 	if (search_box->priv->highlight_all) search_box_highlight_all (search_box);
732 }
733 
734 static void
search_box_forward_search(SearchBox * search_box,GtkWidget * widget)735 search_box_forward_search (SearchBox * search_box, GtkWidget* widget)
736 {
737 	search_box_incremental_search (search_box, TRUE, TRUE, TRUE);
738 }
739 
740 static void
on_search_box_backward_search(GtkWidget * widget,SearchBox * search_box)741 on_search_box_backward_search (GtkWidget * widget, SearchBox * search_box)
742 {
743 	search_box_incremental_search (search_box, FALSE, TRUE, TRUE);
744 }
745 
746 static gboolean
search_box_replace(SearchBox * search_box,GtkWidget * widget,gboolean undo)747 search_box_replace (SearchBox * search_box, GtkWidget * widget,
748                     gboolean undo /* treat as undo action */)
749 {
750 
751 	IAnjutaEditorSelection* selection;
752 	gchar * selection_text;
753 	gboolean replace_successful = FALSE;
754 
755 	const gchar* replace_text = gtk_entry_get_text (GTK_ENTRY (search_box->priv->replace_entry));
756 	const gchar* search_text = gtk_entry_get_text (GTK_ENTRY (search_box->priv->search_entry));
757 
758 	selection = IANJUTA_EDITOR_SELECTION (search_box->priv->current_editor);
759 	selection_text = ianjuta_editor_selection_get (selection, NULL);
760 
761 	if (ianjuta_editor_selection_has_selection (selection, NULL))
762 	{
763 		if (search_box->priv->regex_mode)
764 		{
765 			GRegex * regex;
766 			gchar * replacement_text;
767 			gint start_pos, end_pos;
768 			GError * err = NULL;
769 			gboolean result = search_regex_in_text (search_text, selection_text, TRUE, &start_pos, &end_pos);
770 
771 			if (result)
772 			{
773 				regex = g_regex_new (search_text, 0, 0, NULL);
774 				replacement_text = g_regex_replace(regex, selection_text, strlen(selection_text), 0,
775 													replace_text, 0, &err);
776 				if (err)
777 				{
778 					g_message ("%s",err->message);
779 					g_error_free (err);
780 					g_regex_unref(regex);
781 				}
782                 else
783 				{
784 					if (undo)
785 						ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT (selection), NULL);
786 					ianjuta_editor_selection_replace (selection, replacement_text, strlen(replacement_text), NULL);
787 					if (undo)
788 						ianjuta_document_end_undo_action (IANJUTA_DOCUMENT (selection), NULL);
789 
790 					replace_successful = TRUE;
791 				}
792 
793 				if (regex)
794 					g_regex_unref(regex);
795 				if (replacement_text)
796 					g_free(replacement_text);
797 			}
798 		}
799 		else if ((search_box->priv->case_sensitive && g_str_equal (selection_text, search_text)) ||
800 		         (!search_box->priv->case_sensitive && strcasecmp (selection_text, search_text) == 0))
801 		{
802 			if (undo)
803 				ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT (selection), NULL);
804 			ianjuta_editor_selection_replace (selection, replace_text, strlen(replace_text), NULL);
805 			if (undo)
806 				ianjuta_document_end_undo_action (IANJUTA_DOCUMENT (selection), NULL);
807 
808 			replace_successful = TRUE;
809 		}
810 
811 		g_free(selection_text);
812 	}
813 
814 	return replace_successful;
815 
816 }
817 
818 static void
on_replace_activated(GtkWidget * widget,SearchBox * search_box)819 on_replace_activated (GtkWidget* widget, SearchBox* search_box)
820 {
821 	gboolean successful_replace;
822 
823 	if (!search_box->priv->current_editor)
824 		return;
825 
826 	/* Either replace search-term or try to move search forward to next occurence */
827 
828 	successful_replace = search_box_replace (search_box, widget, TRUE);
829 
830 	if (successful_replace)
831 	{
832 		search_box_forward_search (search_box, widget);
833 	}
834 }
835 
836 static void
do_popup_menu(GtkWidget * widget,GdkEventButton * event,SearchBox * search_box)837 do_popup_menu (GtkWidget* widget, GdkEventButton *event, SearchBox* search_box)
838 {
839 	int button, event_time;
840 
841 	if (event)
842 	{
843 		button = event->button;
844 		event_time = event->time;
845 	}
846 	else
847 	{
848 		button = 0;
849 		event_time = gtk_get_current_event_time ();
850 	}
851 
852 	if (!gtk_menu_get_attach_widget(GTK_MENU (search_box->priv->popup_menu)))
853 		gtk_menu_attach_to_widget (GTK_MENU (search_box->priv->popup_menu), widget, NULL);
854 
855 	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(search_box->priv->case_action), search_box->priv->case_sensitive);
856 	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(search_box->priv->regex_action), search_box->priv->regex_mode);
857 	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(search_box->priv->highlight_action), search_box->priv->highlight_all);
858 
859 	gtk_menu_popup (GTK_MENU (search_box->priv->popup_menu), NULL, NULL, NULL, NULL,
860                   button, event_time);
861 
862 }
863 
864 static gboolean
on_search_entry_icon_pressed(GtkWidget * widget,GtkEntryIconPosition pos,GdkEvent * event,SearchBox * search_box)865 on_search_entry_icon_pressed (GtkWidget* widget, GtkEntryIconPosition pos,
866 								GdkEvent* event, SearchBox * search_box)
867 {
868 	do_popup_menu (widget, (GdkEventButton*)event, search_box);
869 	return TRUE;
870 }
871 
872 static gboolean
on_search_entry_popup_menu(GtkWidget * widget,SearchBox * search_box)873 on_search_entry_popup_menu (GtkWidget* widget, SearchBox* search_box)
874 {
875 	do_popup_menu (widget, NULL, search_box);
876 	return TRUE;
877 }
878 
879 static void
on_replace_all_activated(GtkWidget * widget,SearchBox * search_box)880 on_replace_all_activated (GtkWidget* widget, SearchBox* search_box)
881 {
882 	IAnjutaIterable* cursor;
883 
884 	if (!search_box->priv->current_editor)
885 		return;
886 
887 	/* Cache current position and search from begin */
888 	cursor = ianjuta_editor_get_position (IANJUTA_EDITOR (search_box->priv->current_editor),
889 	                                      NULL);
890 	ianjuta_editor_goto_start (IANJUTA_EDITOR (search_box->priv->current_editor), NULL);
891 
892 	/* Replace all instances of search_entry with replace_entry text */
893 	ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT (search_box->priv->current_editor), NULL);
894 	while (search_box_incremental_search (search_box, TRUE, TRUE, FALSE))
895 	{
896 		search_box_replace (search_box, widget, FALSE);
897 	}
898 	ianjuta_document_end_undo_action (IANJUTA_DOCUMENT (search_box->priv->current_editor), NULL);
899 
900 	/* Back to cached position */
901 	ianjuta_editor_selection_set (IANJUTA_EDITOR_SELECTION (search_box->priv->current_editor),
902 	                              cursor, cursor, TRUE, NULL);
903 	g_object_unref (cursor);
904 }
905 
906 static void
search_box_init(SearchBox * search_box)907 search_box_init (SearchBox *search_box)
908 {
909 	search_box->priv = GET_PRIVATE(search_box);
910 	GList* focus_chain = NULL;
911 	GtkStyleContext *context;
912 
913 	/* Button images */
914 	GtkWidget* close =
915 		gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
916 
917 	/* Searching */
918 	search_box->priv->search_entry = gtk_entry_new();
919 	gtk_widget_set_tooltip_text (search_box->priv->search_entry,
920 	                             _("Use the context menu of the \"Find\" icon for more search options"));
921 	g_signal_connect_swapped (G_OBJECT (search_box->priv->search_entry), "activate",
922 	                          G_CALLBACK (search_box_forward_search),
923 	                          search_box);
924 	g_signal_connect (G_OBJECT (search_box), "key-press-event",
925 					  G_CALLBACK (on_search_box_key_pressed),
926 					  search_box);
927 	g_signal_connect (G_OBJECT (search_box->priv->search_entry), "changed",
928 					  G_CALLBACK (on_search_box_entry_changed),
929 					  search_box);
930 	g_signal_connect (G_OBJECT (search_box->priv->search_entry), "focus-out-event",
931 					  G_CALLBACK (on_search_focus_out),
932 					  search_box);
933 	g_signal_connect (G_OBJECT (search_box->priv->search_entry), "icon-press",
934 					  G_CALLBACK (on_search_entry_icon_pressed),
935 					  search_box);
936 	g_signal_connect (G_OBJECT (search_box->priv->search_entry), "popup-menu",
937 					  G_CALLBACK (on_search_entry_popup_menu),
938 					  search_box);
939 
940 	search_box->priv->close_button = gtk_button_new();
941 	gtk_button_set_image (GTK_BUTTON (search_box->priv->close_button), close);
942 	gtk_button_set_relief (GTK_BUTTON (search_box->priv->close_button), GTK_RELIEF_NONE);
943 
944 	g_signal_connect (G_OBJECT (search_box->priv->close_button), "clicked",
945 					  G_CALLBACK (on_search_box_hide), search_box);
946 
947 	/* CSS custom style */
948 	search_box->priv->provider = gtk_css_provider_new ();
949 	gtk_css_provider_load_from_data (search_box->priv->provider,
950 	                                 ".not-found {color: @gedit_not_found_fg; background-image: none; background-color: @gedit_not_found_bg;}"
951 	                                 ".not-found:selected {color: @theme_selected_fg_color; background-color: @theme_selected_bg_color;}"
952 	                                 , -1, NULL);
953 	context = gtk_widget_get_style_context (GTK_WIDGET (search_box->priv->search_entry));
954 	gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (search_box->priv->provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
955 
956 
957 	/* Previous, Next Navigation */
958 	search_box->priv->next_button = gtk_button_new ();
959 	gtk_container_add (GTK_CONTAINER (search_box->priv->next_button),
960 	                   gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD,
961 	                                             GTK_ICON_SIZE_BUTTON));
962 	gtk_button_set_relief (GTK_BUTTON (search_box->priv->next_button), GTK_RELIEF_NONE);
963 	g_signal_connect_swapped (G_OBJECT(search_box->priv->next_button), "clicked",
964 	                          G_CALLBACK (search_box_forward_search), search_box);
965 	search_box->priv->previous_button = gtk_button_new ();
966 	gtk_container_add (GTK_CONTAINER (search_box->priv->previous_button),
967 	                   gtk_image_new_from_stock (GTK_STOCK_GO_BACK,
968 	                                             GTK_ICON_SIZE_BUTTON));
969 	gtk_button_set_relief (GTK_BUTTON (search_box->priv->previous_button), GTK_RELIEF_NONE);
970 	g_signal_connect (G_OBJECT(search_box->priv->previous_button), "clicked",
971 					G_CALLBACK (on_search_box_backward_search), search_box);
972 
973 	/* Goto line */
974 	search_box->priv->goto_entry = gtk_entry_new ();
975 	gtk_entry_set_width_chars (GTK_ENTRY (search_box->priv->goto_entry), LINE_ENTRY_WIDTH);
976 	gtk_entry_set_icon_from_stock (GTK_ENTRY (search_box->priv->goto_entry),
977 	                               GTK_ENTRY_ICON_SECONDARY,
978 	                               ANJUTA_STOCK_GOTO_LINE);
979 	g_signal_connect (G_OBJECT (search_box->priv->goto_entry), "activate",
980 					  G_CALLBACK (on_goto_activated),
981 					  search_box);
982 	g_signal_connect (G_OBJECT (search_box->priv->goto_entry), "key-press-event",
983 					  G_CALLBACK (on_goto_key_pressed),
984 					  search_box);
985 	/* Replace */
986 	search_box->priv->replace_entry = gtk_entry_new();
987 	g_signal_connect (G_OBJECT (search_box->priv->replace_entry), "activate",
988 					  G_CALLBACK (on_replace_activated),
989 					  search_box);
990 
991 	search_box->priv->replace_button = gtk_button_new_with_label(_("Replace"));
992 	gtk_button_set_relief (GTK_BUTTON (search_box->priv->replace_button), GTK_RELIEF_NONE);
993 	g_signal_connect (G_OBJECT(search_box->priv->replace_button), "clicked",
994 					G_CALLBACK (on_replace_activated), search_box);
995 
996 	search_box->priv->replace_all_button = gtk_button_new_with_label(_("Replace all"));
997 	gtk_button_set_relief (GTK_BUTTON (search_box->priv->replace_all_button), GTK_RELIEF_NONE);
998 	g_signal_connect (G_OBJECT(search_box->priv->replace_all_button), "clicked",
999 					G_CALLBACK (on_replace_all_activated), search_box);
1000 
1001 	/* Popup Menu Options */
1002 	search_box->priv->regex_mode = FALSE;
1003 	search_box->priv->highlight_all = FALSE;
1004 	search_box->priv->case_sensitive = FALSE;
1005 
1006 	/* Highlight iterator */
1007 	search_box->priv->start_highlight = NULL;
1008 	search_box->priv->end_highlight = NULL;
1009 	search_box->priv->idle_id = 0;
1010 
1011 	/* Initialize search_box grid */
1012 	search_box->priv->grid = gtk_grid_new();
1013 	gtk_orientable_set_orientation (GTK_ORIENTABLE (search_box->priv->grid),
1014 									GTK_ORIENTATION_VERTICAL);
1015 	gtk_grid_set_row_spacing (GTK_GRID (search_box->priv->grid), 5);
1016 
1017 	/* Attach search elements to grid */
1018 	gtk_grid_attach (GTK_GRID (search_box->priv->grid), search_box->priv->goto_entry, 0, 0, 1, 1);
1019 
1020 	gtk_grid_attach (GTK_GRID (search_box->priv->grid), search_box->priv->search_entry, 1, 0, 1, 1);
1021 
1022 	gtk_grid_attach (GTK_GRID (search_box->priv->grid), search_box->priv->previous_button, 2, 0, 1, 1);
1023 	gtk_grid_attach (GTK_GRID (search_box->priv->grid), search_box->priv->next_button, 3, 0, 1, 1);
1024 
1025 	gtk_grid_attach_next_to (GTK_GRID (search_box->priv->grid),
1026 	                         search_box->priv->close_button,
1027 	                         search_box->priv->next_button,
1028 	                         GTK_POS_RIGHT, 1, 1);
1029 	gtk_widget_set_hexpand(search_box->priv->close_button, TRUE);
1030 	gtk_widget_set_halign(search_box->priv->close_button,
1031 	                      GTK_ALIGN_END);
1032 
1033 	/* Add Replace elements to search box on 2nd level */
1034 	gtk_grid_attach (GTK_GRID (search_box->priv->grid), search_box->priv->replace_entry, 1, 1, 1, 1);
1035 	gtk_grid_attach (GTK_GRID (search_box->priv->grid), search_box->priv->replace_button, 2, 1, 1, 1);
1036 	gtk_grid_attach (GTK_GRID (search_box->priv->grid), search_box->priv->replace_all_button, 3, 1, 1, 1);
1037 
1038 	/* Expand search entries (a bit) */
1039 	gtk_entry_set_width_chars (GTK_ENTRY (search_box->priv->search_entry), SEARCH_ENTRY_WIDTH);
1040 	gtk_entry_set_width_chars (GTK_ENTRY (search_box->priv->replace_entry), SEARCH_ENTRY_WIDTH);
1041 
1042 	/* Set nice icons */
1043 	gtk_entry_set_icon_from_stock (GTK_ENTRY (search_box->priv->search_entry),
1044 	                               GTK_ENTRY_ICON_PRIMARY,
1045 	                               GTK_STOCK_FIND);
1046 	gtk_entry_set_icon_from_stock (GTK_ENTRY (search_box->priv->replace_entry),
1047 	                               GTK_ENTRY_ICON_PRIMARY,
1048 	                               GTK_STOCK_FIND_AND_REPLACE);
1049 
1050 	/* Pack grid into search box */
1051 	gtk_box_pack_start (GTK_BOX(search_box), search_box->priv->grid, TRUE, TRUE, 0);
1052 
1053 	/* Set focus chain */
1054 	focus_chain = g_list_prepend (focus_chain, search_box->priv->search_entry);
1055 	focus_chain = g_list_prepend (focus_chain, search_box->priv->replace_entry);
1056 	focus_chain = g_list_prepend (focus_chain, search_box->priv->next_button);
1057 	focus_chain = g_list_prepend (focus_chain, search_box->priv->previous_button);
1058 	focus_chain = g_list_prepend (focus_chain, search_box->priv->replace_button);
1059 	focus_chain = g_list_prepend (focus_chain, search_box->priv->replace_all_button);
1060 	focus_chain = g_list_prepend (focus_chain, search_box->priv->goto_entry);
1061 	focus_chain = g_list_prepend (focus_chain, search_box->priv->close_button);
1062 	focus_chain = g_list_prepend (focus_chain, search_box->priv->search_entry);
1063 	focus_chain = g_list_reverse (focus_chain);
1064 	gtk_container_set_focus_chain (GTK_CONTAINER (search_box->priv->grid),
1065 	                               focus_chain);
1066 	g_list_free (focus_chain);
1067 
1068 	/* Show all children but keep the top box hidden. */
1069 	gtk_widget_show_all (GTK_WIDGET (search_box));
1070 	gtk_widget_hide (GTK_WIDGET (search_box));
1071 }
1072 
1073 static void
search_box_finalize(GObject * object)1074 search_box_finalize (GObject *object)
1075 {
1076 	SearchBox *search_box = SEARCH_BOX (object);
1077 
1078 	if (search_box->priv->idle_id) g_source_remove (search_box->priv->idle_id);
1079 	if (search_box->priv->start_highlight) g_object_unref (search_box->priv->start_highlight);
1080 	if (search_box->priv->end_highlight) g_object_unref (search_box->priv->end_highlight);
1081 	if (search_box->priv->provider) g_object_unref (search_box->priv->provider);
1082 
1083 	G_OBJECT_CLASS (search_box_parent_class)->finalize (object);
1084 }
1085 
1086 static void
search_box_class_init(SearchBoxClass * klass)1087 search_box_class_init (SearchBoxClass *klass)
1088 {
1089 	GObjectClass* object_class = G_OBJECT_CLASS (klass);
1090 
1091 	g_type_class_add_private (klass, sizeof (SearchBoxPrivate));
1092 
1093 	object_class->finalize = search_box_finalize;
1094 }
1095 
1096 GtkWidget*
search_box_new(AnjutaDocman * docman)1097 search_box_new (AnjutaDocman *docman)
1098 {
1099 	SearchBox* search_box;
1100 	AnjutaUI *ui;
1101 
1102 	search_box = SEARCH_BOX (g_object_new (SEARCH_TYPE_BOX, "homogeneous",
1103 											FALSE, NULL));
1104 
1105 	g_signal_connect (G_OBJECT (docman), "document-changed",
1106 					  G_CALLBACK (on_document_changed), search_box);
1107 
1108 	search_box->priv->status = anjuta_shell_get_status (docman->shell, NULL);
1109 
1110 	ui = anjuta_shell_get_ui (docman->shell, NULL);
1111 	search_box->priv->popup_menu = gtk_ui_manager_get_widget (GTK_UI_MANAGER (ui),
1112 											"/SearchboxPopup");
1113 	g_assert (search_box->priv->popup_menu != NULL && GTK_IS_MENU (search_box->priv->popup_menu));
1114 
1115 	search_box->priv->case_action =
1116 		gtk_ui_manager_get_action (GTK_UI_MANAGER (ui),
1117 		                           "/SearchboxPopup/CaseCheck");
1118 
1119 	search_box->priv->highlight_action =
1120 		gtk_ui_manager_get_action (GTK_UI_MANAGER (ui),
1121 		                           "/SearchboxPopup/HighlightAll");
1122 	search_box->priv->regex_action =
1123 		gtk_ui_manager_get_action (GTK_UI_MANAGER (ui),
1124 		                           "/SearchboxPopup/RegexSearch");
1125 
1126 	g_signal_connect (search_box->priv->popup_menu, "deactivate",
1127 					  G_CALLBACK (gtk_widget_hide), NULL);
1128 
1129 	return GTK_WIDGET (search_box);
1130 }
1131 
1132 void
search_box_fill_search_focus(SearchBox * search_box,gboolean on_replace)1133 search_box_fill_search_focus (SearchBox* search_box, gboolean on_replace)
1134 {
1135 	IAnjutaEditor* te = search_box->priv->current_editor;
1136 
1137 	if (IANJUTA_IS_EDITOR (te) && !search_box->priv->regex_mode)
1138 	{
1139 		gchar *buffer;
1140 
1141 		buffer = ianjuta_editor_selection_get (IANJUTA_EDITOR_SELECTION (te), NULL);
1142 		if (buffer != NULL)
1143 		{
1144 			g_strstrip (buffer);
1145 			if (*buffer != 0)
1146 			{
1147 
1148 				gtk_entry_set_text (GTK_ENTRY (search_box->priv->search_entry), buffer);
1149 				gtk_editable_select_region (GTK_EDITABLE (search_box->priv->search_entry), 0, -1);
1150 
1151 			}
1152 			g_free (buffer);
1153 		}
1154 	}
1155 
1156 	/* Toggle replace level (replace entry, replace buttons) of search box */
1157 	search_box_set_replace (search_box, on_replace);
1158 
1159 	gtk_widget_grab_focus (search_box->priv->search_entry);
1160 }
1161 
1162 void
search_box_grab_line_focus(SearchBox * search_box)1163 search_box_grab_line_focus (SearchBox* search_box)
1164 {
1165 	gtk_widget_grab_focus (search_box->priv->goto_entry);
1166 }
1167 
1168 void
search_box_hide(SearchBox * search_box)1169 search_box_hide (SearchBox* search_box)
1170 {
1171 	gtk_widget_hide (GTK_WIDGET (search_box));
1172 	search_box_set_entry_color (search_box, TRUE);
1173 	if (search_box->priv->current_editor)
1174 	{
1175 		ianjuta_document_grab_focus (IANJUTA_DOCUMENT (search_box->priv->current_editor),
1176 		                             NULL);
1177 	}
1178 }
1179 
1180 void
search_box_set_replace(SearchBox * search_box,gboolean replace)1181 search_box_set_replace (SearchBox* search_box, gboolean replace)
1182 {
1183 	if (replace)
1184 	{
1185 		gtk_widget_show (search_box->priv->replace_entry);
1186 		gtk_widget_show (search_box->priv->replace_button);
1187 		gtk_widget_show (search_box->priv->replace_all_button);
1188 	}
1189 	else
1190 	{
1191 		gtk_widget_hide (search_box->priv->replace_entry);
1192 		gtk_widget_hide (search_box->priv->replace_button);
1193 		gtk_widget_hide (search_box->priv->replace_all_button);
1194 	}
1195 }
1196 
search_box_get_search_string(SearchBox * search_box)1197 const gchar* search_box_get_search_string (SearchBox* search_box)
1198 {
1199 	g_return_val_if_fail (search_box != NULL && SEARCH_IS_BOX(search_box), NULL);
1200 
1201 	return gtk_entry_get_text (GTK_ENTRY (search_box->priv->search_entry));
1202 }
1203 
search_box_set_search_string(SearchBox * search_box,const gchar * search)1204 void search_box_set_search_string (SearchBox* search_box, const gchar* search)
1205 {
1206 	g_return_if_fail (search_box != NULL && SEARCH_IS_BOX(search_box));
1207 
1208 	gtk_entry_set_text (GTK_ENTRY (search_box->priv->search_entry), search);
1209 }
1210 
search_box_get_replace_string(SearchBox * search_box)1211 const gchar* search_box_get_replace_string (SearchBox* search_box)
1212 {
1213 	g_return_val_if_fail (search_box != NULL && SEARCH_IS_BOX(search_box), NULL);
1214 
1215 	return gtk_entry_get_text (GTK_ENTRY (search_box->priv->replace_entry));
1216 
1217 }
1218 
search_box_set_replace_string(SearchBox * search_box,const gchar * replace)1219 void search_box_set_replace_string (SearchBox* search_box, const gchar* replace)
1220 {
1221 	g_return_if_fail (search_box != NULL && SEARCH_IS_BOX(search_box));
1222 
1223 	gtk_entry_set_text (GTK_ENTRY (search_box->priv->replace_entry), replace);
1224 }
1225 
1226 void
search_box_session_load(SearchBox * search_box,AnjutaSession * session)1227 search_box_session_load (SearchBox* search_box, AnjutaSession* session)
1228 {
1229 	g_return_if_fail (search_box != NULL && SEARCH_IS_BOX(search_box));
1230 
1231 	search_box->priv->case_sensitive = anjuta_session_get_int (session, "Search Box", "Case Sensitive") ? TRUE : FALSE;
1232 	search_box->priv->regex_mode = anjuta_session_get_int (session, "Search Box", "Regular Expression") ? TRUE : FALSE;
1233 	search_box->priv->highlight_all = anjuta_session_get_int (session, "Search Box", "Highlight Match") ? TRUE : FALSE;
1234 }
1235 
1236 void
search_box_session_save(SearchBox * search_box,AnjutaSession * session)1237 search_box_session_save (SearchBox* search_box, AnjutaSession* session)
1238 {
1239 	g_return_if_fail (search_box != NULL && SEARCH_IS_BOX(search_box));
1240 
1241 	anjuta_session_set_int (session, "Search Box", "Case Sensitive", search_box->priv->case_sensitive ? 1 : 0);
1242 	anjuta_session_set_int (session, "Search Box", "Regular Expression", search_box->priv->regex_mode ? 1 : 0);
1243 	anjuta_session_set_int (session, "Search Box", "Highlight Match", search_box->priv->highlight_all ? 1 : 0);
1244 }
1245