gedit-replace-dialog.c 21.2 KB
Newer Older
Paolo Borelli's avatar
Paolo Borelli committed
1
/*
2
 * gedit-replace-dialog.c
Paolo Borelli's avatar
Paolo Borelli committed
3 4 5
 * This file is part of gedit
 *
 * Copyright (C) 2005 Paolo Maggi
6
 * Copyright (C) 2013 Sébastien Wilmet
Paolo Borelli's avatar
Paolo Borelli committed
7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
Paolo Borelli's avatar
Paolo Borelli committed
20
 */
21

Paolo Borelli's avatar
Paolo Borelli committed
22 23 24 25 26 27
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <string.h>
#include <glib/gi18n.h>
28 29
#include <gdk/gdkkeysyms.h>

30
#include "gedit-replace-dialog.h"
31
#include "gedit-history-entry.h"
32
#include "gedit-document.h"
Paolo Borelli's avatar
Paolo Borelli committed
33

34 35
#define GEDIT_SEARCH_CONTEXT_KEY "gedit-search-context-key"

36
struct _GeditReplaceDialogPrivate
Paolo Borelli's avatar
Paolo Borelli committed
37
{
38
	GtkWidget *grid;
39
	GtkWidget *search_label;
Paolo Borelli's avatar
Paolo Borelli committed
40
	GtkWidget *search_entry;
41
	GtkWidget *search_text_entry;
Paolo Borelli's avatar
Paolo Borelli committed
42 43
	GtkWidget *replace_label;
	GtkWidget *replace_entry;
44
	GtkWidget *replace_text_entry;
Paolo Borelli's avatar
Paolo Borelli committed
45 46
	GtkWidget *match_case_checkbutton;
	GtkWidget *entire_word_checkbutton;
47
	GtkWidget *regex_checkbutton;
Paolo Borelli's avatar
Paolo Borelli committed
48 49 50
	GtkWidget *backwards_checkbutton;
	GtkWidget *wrap_around_checkbutton;

51
	GeditDocument *active_document;
52 53

	guint idle_update_sensitivity_id;
Paolo Borelli's avatar
Paolo Borelli committed
54 55
};

56
G_DEFINE_TYPE_WITH_PRIVATE (GeditReplaceDialog, gedit_replace_dialog, GTK_TYPE_DIALOG)
Paolo Borelli's avatar
Paolo Borelli committed
57

58 59 60 61 62 63 64 65 66 67 68
static GtkSourceSearchContext *
get_search_context (GeditReplaceDialog *dialog,
		    GeditDocument      *doc)
{
	GtkSourceSearchContext *search_context;

	if (doc == NULL)
	{
		return NULL;
	}

69
	search_context = gedit_document_get_search_context (doc);
70 71 72 73 74 75 76 77 78 79

	if (search_context != NULL &&
	    g_object_get_data (G_OBJECT (search_context), GEDIT_SEARCH_CONTEXT_KEY) == dialog)
	{
		return search_context;
	}

	return NULL;
}

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
/* The search settings between the dialog's widgets (checkbuttons and the text
 * entry) and the SearchSettings object are not bound. Instead, this function is
 * called to set the search settings from the widgets to the SearchSettings
 * object.
 *
 * The reason: the search and replace dialog is not an incremental search. You
 * have to press the buttons to have an effect. The SearchContext is created
 * only when a button is pressed, not before. If the SearchContext was created
 * directly when the dialog window is shown, or when the document tab is
 * switched, there would be a problem. When we switch betweeen tabs to find on
 * which tab(s) we want to do the search, we may have older searches (still
 * highlighted) that we don't want to lose, and we don't want the new search to
 * appear on each tab that we open. Only when we press a button. So when the
 * SearchContext is not already created, this is not an incremental search. Once
 * the SearchContext is created, it's better to be consistent, and therefore we
 * don't want the incremental search: we have to always press a button to
 * execute the search.
97 98 99 100 101
 *
 * Likewise, each created SearchContext (from the GeditReplaceDialog) contains a
 * different SearchSettings. When set_search_settings() is called for one
 * document tab (and thus one SearchSettings), it doesn't have an effect on the
 * other tabs. But the dialog widgets don't change.
102 103 104 105
 */
static void
set_search_settings (GeditReplaceDialog *dialog)
{
106 107
	GtkSourceSearchContext *search_context;
	GtkSourceSearchSettings *search_settings;
108 109 110 111 112 113
	gboolean case_sensitive;
	gboolean at_word_boundaries;
	gboolean regex_enabled;
	gboolean wrap_around;
	const gchar *search_text;

114 115 116 117 118 119 120 121 122
	search_context = get_search_context (dialog, dialog->priv->active_document);

	if (search_context == NULL)
	{
		return;
	}

	search_settings = gtk_source_search_context_get_settings (search_context);

123
	case_sensitive = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->match_case_checkbutton));
124
	gtk_source_search_settings_set_case_sensitive (search_settings, case_sensitive);
125 126

	at_word_boundaries = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->entire_word_checkbutton));
127
	gtk_source_search_settings_set_at_word_boundaries (search_settings, at_word_boundaries);
128 129

	regex_enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->regex_checkbutton));
130
	gtk_source_search_settings_set_regex_enabled (search_settings, regex_enabled);
131 132

	wrap_around = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->wrap_around_checkbutton));
133
	gtk_source_search_settings_set_wrap_around (search_settings, wrap_around);
134 135 136 137 138

	search_text = gtk_entry_get_text (GTK_ENTRY (dialog->priv->search_text_entry));

	if (regex_enabled)
	{
139
		gtk_source_search_settings_set_search_text (search_settings, search_text);
140 141 142 143
	}
	else
	{
		gchar *unescaped_search_text = gtk_source_utils_unescape_search_text (search_text);
144
		gtk_source_search_settings_set_search_text (search_settings, unescaped_search_text);
145 146 147 148
		g_free (unescaped_search_text);
	}
}

149 150 151 152 153
static GeditWindow *
get_gedit_window (GeditReplaceDialog *dialog)
{
	GtkWindow *transient_for = gtk_window_get_transient_for (GTK_WINDOW (dialog));

154
	return transient_for != NULL ? GEDIT_WINDOW (transient_for) : NULL;
155 156
}

157 158 159 160 161
static GeditDocument *
get_active_document (GeditReplaceDialog *dialog)
{
	GeditWindow *window = get_gedit_window (dialog);

162
	return window != NULL ? gedit_window_get_active_document (window) : NULL;
163 164
}

165
void
166
gedit_replace_dialog_present_with_time (GeditReplaceDialog *dialog,
167
					guint32             timestamp)
168
{
169
	g_return_if_fail (GEDIT_REPLACE_DIALOG (dialog));
170

171
	gtk_window_present_with_time (GTK_WINDOW (dialog), timestamp);
172

173
	gtk_widget_grab_focus (dialog->priv->search_text_entry);
174 175
}

176 177 178 179 180 181 182 183
static gboolean
gedit_replace_dialog_delete_event (GtkWidget   *widget,
                                   GdkEventAny *event)
{
	/* prevent destruction */
	return TRUE;
}

184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
static void
set_error (GtkEntry    *entry,
	   const gchar *error_msg)
{
	if (error_msg == NULL || error_msg[0] == '\0')
	{
		gtk_entry_set_icon_from_gicon (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
		gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
	}
	else
	{
		GIcon *icon = g_themed_icon_new_with_default_fallbacks ("dialog-error-symbolic");

		gtk_entry_set_icon_from_gicon (entry, GTK_ENTRY_ICON_SECONDARY, icon);
		gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, error_msg);

		g_object_unref (icon);
	}
}

static void
set_search_error (GeditReplaceDialog *dialog,
		  const gchar        *error_msg)
{
	set_error (GTK_ENTRY (dialog->priv->search_text_entry), error_msg);
}

211 212 213
void
gedit_replace_dialog_set_replace_error (GeditReplaceDialog *dialog,
					const gchar        *error_msg)
214 215 216 217
{
	set_error (GTK_ENTRY (dialog->priv->replace_text_entry), error_msg);
}

218 219 220 221 222 223 224 225 226
static gboolean
has_search_error (GeditReplaceDialog *dialog)
{
	GIcon *icon = gtk_entry_get_icon_gicon (GTK_ENTRY (dialog->priv->search_text_entry),
						GTK_ENTRY_ICON_SECONDARY);

	return icon != NULL;
}

227 228 229 230 231 232 233 234 235
static gboolean
has_replace_error (GeditReplaceDialog *dialog)
{
	GIcon *icon = gtk_entry_get_icon_gicon (GTK_ENTRY (dialog->priv->replace_text_entry),
						GTK_ENTRY_ICON_SECONDARY);

	return icon != NULL;
}

236 237 238 239 240 241 242 243
static void
update_regex_error (GeditReplaceDialog *dialog)
{
	GtkSourceSearchContext *search_context;
	GError *regex_error;

	set_search_error (dialog, NULL);

244
	search_context = get_search_context (dialog, dialog->priv->active_document);
245 246 247 248 249 250 251 252

	if (search_context == NULL)
	{
		return;
	}

	regex_error = gtk_source_search_context_get_regex_error (search_context);

253
	if (regex_error != NULL)
254
	{
255 256
		set_search_error (dialog, regex_error->message);
		g_error_free (regex_error);
257 258 259
	}
}

260 261 262 263 264 265 266 267
static gboolean
update_replace_response_sensitivity_cb (GeditReplaceDialog *dialog)
{
	GtkSourceSearchContext *search_context;
	GtkTextIter start;
	GtkTextIter end;
	gint pos;

268 269 270 271 272 273 274 275 276 277
	if (has_replace_error (dialog))
	{
		gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
						   GEDIT_REPLACE_DIALOG_REPLACE_RESPONSE,
						   FALSE);

		dialog->priv->idle_update_sensitivity_id = 0;
		return G_SOURCE_REMOVE;
	}

278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
	search_context = get_search_context (dialog, dialog->priv->active_document);

	if (search_context == NULL)
	{
		dialog->priv->idle_update_sensitivity_id = 0;
		return G_SOURCE_REMOVE;
	}

	gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (dialog->priv->active_document),
					      &start,
					      &end);

	pos = gtk_source_search_context_get_occurrence_position (search_context,
								 &start,
								 &end);

	if (pos < 0)
	{
		return G_SOURCE_CONTINUE;
	}

	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
					   GEDIT_REPLACE_DIALOG_REPLACE_RESPONSE,
					   pos > 0);

	dialog->priv->idle_update_sensitivity_id = 0;
	return G_SOURCE_REMOVE;
}

static void
install_idle_update_sensitivity (GeditReplaceDialog *dialog)
{
	if (dialog->priv->idle_update_sensitivity_id != 0)
	{
		return;
	}

	dialog->priv->idle_update_sensitivity_id =
		g_idle_add ((GSourceFunc)update_replace_response_sensitivity_cb,
			    dialog);
}

static void
mark_set_cb (GtkTextBuffer      *buffer,
	     GtkTextIter        *location,
	     GtkTextMark        *mark,
	     GeditReplaceDialog *dialog)
{
	GtkTextMark *insert;
	GtkTextMark *selection_bound;

	insert = gtk_text_buffer_get_insert (buffer);
	selection_bound = gtk_text_buffer_get_selection_bound (buffer);

	if (mark == insert || mark == selection_bound)
	{
		install_idle_update_sensitivity (dialog);
	}
}

338 339 340 341
static void
update_responses_sensitivity (GeditReplaceDialog *dialog)
{
	const gchar *search_text;
342
	gboolean sensitive = TRUE;
343

344 345
	install_idle_update_sensitivity (dialog);

346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
	search_text = gtk_entry_get_text (GTK_ENTRY (dialog->priv->search_text_entry));

	if (search_text[0] == '\0')
	{
		gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
						   GEDIT_REPLACE_DIALOG_FIND_RESPONSE,
						   FALSE);

		gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
						   GEDIT_REPLACE_DIALOG_REPLACE_ALL_RESPONSE,
						   FALSE);

		return;
	}

361
	sensitive = !has_search_error (dialog);
362 363 364 365 366

	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
					   GEDIT_REPLACE_DIALOG_FIND_RESPONSE,
					   sensitive);

367 368 369 370 371
	if (has_replace_error (dialog))
	{
		sensitive = FALSE;
	}

372 373 374 375 376 377 378 379 380 381 382 383
	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
					   GEDIT_REPLACE_DIALOG_REPLACE_ALL_RESPONSE,
					   sensitive);
}

static void
regex_error_notify_cb (GeditReplaceDialog *dialog)
{
	update_regex_error (dialog);
	update_responses_sensitivity (dialog);
}

384
static void
385
disconnect_document (GeditReplaceDialog *dialog)
386
{
387
	GtkSourceSearchContext *search_context;
388

389
	if (dialog->priv->active_document == NULL)
390
	{
391 392
		return;
	}
393

394
	search_context = get_search_context (dialog, dialog->priv->active_document);
395

396 397 398 399 400
	if (search_context != NULL)
	{
		g_signal_handlers_disconnect_by_func (search_context,
						      regex_error_notify_cb,
						      dialog);
401 402
	}

403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
	g_signal_handlers_disconnect_by_func (dialog->priv->active_document,
					      mark_set_cb,
					      dialog);

	g_clear_object (&dialog->priv->active_document);
}

static void
connect_active_document (GeditReplaceDialog *dialog)
{
	GeditDocument *doc;
	GtkSourceSearchContext *search_context;

	disconnect_document (dialog);

	doc = get_active_document (dialog);

420
	if (doc == NULL)
421 422 423 424
	{
		return;
	}

425 426 427 428 429 430
	dialog->priv->active_document = g_object_ref (doc);

	search_context = get_search_context (dialog, doc);

	if (search_context == NULL)
	{
431 432
		GtkSourceSearchSettings *settings = gtk_source_search_settings_new ();

433
		search_context = gtk_source_search_context_new (GTK_SOURCE_BUFFER (doc),
434 435 436 437 438 439 440 441 442
								settings);

		/* Mark the search context that it comes from the search and
		 * replace dialog. Search contexts can be created also from the
		 * GeditViewFrame.
		 */
		g_object_set_data (G_OBJECT (search_context),
				   GEDIT_SEARCH_CONTEXT_KEY,
				   dialog);
443

444
		gedit_document_set_search_context (doc, search_context);
445 446

		g_object_unref (settings);
447 448
		g_object_unref (search_context);
	}
449 450 451

	g_signal_connect_object (search_context,
				 "notify::regex-error",
452
				 G_CALLBACK (regex_error_notify_cb),
453 454 455
				 dialog,
				 G_CONNECT_SWAPPED);

456 457 458 459 460 461
	g_signal_connect_object (doc,
				 "mark-set",
				 G_CALLBACK (mark_set_cb),
				 dialog,
				 0);

462 463
	update_regex_error (dialog);
	update_responses_sensitivity (dialog);
464 465
}

466
static void
467 468
response_cb (GtkDialog *dialog,
	     gint       response_id)
469 470 471 472 473 474 475 476 477 478 479 480 481
{
	GeditReplaceDialog *dlg = GEDIT_REPLACE_DIALOG (dialog);
	const gchar *str;

	switch (response_id)
	{
		case GEDIT_REPLACE_DIALOG_REPLACE_RESPONSE:
		case GEDIT_REPLACE_DIALOG_REPLACE_ALL_RESPONSE:
			str = gtk_entry_get_text (GTK_ENTRY (dlg->priv->replace_text_entry));
			if (*str != '\0')
			{
				gedit_history_entry_prepend_text
						(GEDIT_HISTORY_ENTRY (dlg->priv->replace_entry),
482
						 str);
483 484 485 486 487 488 489 490
			}
			/* fall through, so that we also save the find entry */
		case GEDIT_REPLACE_DIALOG_FIND_RESPONSE:
			str = gtk_entry_get_text (GTK_ENTRY (dlg->priv->search_text_entry));
			if (*str != '\0')
			{
				gedit_history_entry_prepend_text
						(GEDIT_HISTORY_ENTRY (dlg->priv->search_entry),
491
						 str);
492 493
			}
	}
494 495 496 497 498 499 500

	switch (response_id)
	{
		case GEDIT_REPLACE_DIALOG_REPLACE_RESPONSE:
		case GEDIT_REPLACE_DIALOG_REPLACE_ALL_RESPONSE:
		case GEDIT_REPLACE_DIALOG_FIND_RESPONSE:
			connect_active_document (GEDIT_REPLACE_DIALOG (dialog));
501
			set_search_settings (GEDIT_REPLACE_DIALOG (dialog));
502
	}
503 504
}

505 506 507 508 509
static void
gedit_replace_dialog_dispose (GObject *object)
{
	GeditReplaceDialog *dialog = GEDIT_REPLACE_DIALOG (object);

510
	g_clear_object (&dialog->priv->active_document);
511

512 513 514 515 516 517
	if (dialog->priv->idle_update_sensitivity_id != 0)
	{
		g_source_remove (dialog->priv->idle_update_sensitivity_id);
		dialog->priv->idle_update_sensitivity_id = 0;
	}

518 519 520
	G_OBJECT_CLASS (gedit_replace_dialog_parent_class)->dispose (object);
}

521
static void
522
gedit_replace_dialog_class_init (GeditReplaceDialogClass *klass)
Paolo Borelli's avatar
Paolo Borelli committed
523
{
524
	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
525 526
	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

527
	gobject_class->dispose = gedit_replace_dialog_dispose;
528 529 530 531 532
	widget_class->delete_event = gedit_replace_dialog_delete_event;

	/* Bind class to template */
	gtk_widget_class_set_template_from_resource (widget_class,
	                                             "/org/gnome/gedit/ui/gedit-replace-dialog.ui");
533 534 535 536 537
	gtk_widget_class_bind_template_child_private (widget_class, GeditReplaceDialog, grid);
	gtk_widget_class_bind_template_child_private (widget_class, GeditReplaceDialog, search_label);
	gtk_widget_class_bind_template_child_private (widget_class, GeditReplaceDialog, replace_label);
	gtk_widget_class_bind_template_child_private (widget_class, GeditReplaceDialog, match_case_checkbutton);
	gtk_widget_class_bind_template_child_private (widget_class, GeditReplaceDialog, entire_word_checkbutton);
538
	gtk_widget_class_bind_template_child_private (widget_class, GeditReplaceDialog, regex_checkbutton);
539 540
	gtk_widget_class_bind_template_child_private (widget_class, GeditReplaceDialog, backwards_checkbutton);
	gtk_widget_class_bind_template_child_private (widget_class, GeditReplaceDialog, wrap_around_checkbutton);
Paolo Borelli's avatar
Paolo Borelli committed
541 542 543
}

static void
544 545
search_text_entry_changed (GtkEditable        *editable,
			   GeditReplaceDialog *dialog)
Paolo Borelli's avatar
Paolo Borelli committed
546
{
547
	set_search_error (dialog, NULL);
548

549
	update_responses_sensitivity (dialog);
550 551
}

552 553 554 555 556 557 558 559 560
static void
replace_text_entry_changed (GtkEditable        *editable,
			    GeditReplaceDialog *dialog)
{
	gedit_replace_dialog_set_replace_error (dialog, NULL);

	update_responses_sensitivity (dialog);
}

561 562 563 564 565 566 567 568 569 570 571 572
static void
regex_checkbutton_toggled (GtkToggleButton    *checkbutton,
			   GeditReplaceDialog *dialog)
{
	if (!gtk_toggle_button_get_active (checkbutton))
	{
		/* Remove the regex error state so the user can search again */
		set_search_error (dialog, NULL);
		update_responses_sensitivity (dialog);
	}
}

573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
/* TODO: move in gedit-document.c and share it with gedit-view-frame */
static gboolean
get_selected_text (GtkTextBuffer  *doc,
		   gchar         **selected_text,
		   gint           *len)
{
	GtkTextIter start, end;

	g_return_val_if_fail (selected_text != NULL, FALSE);
	g_return_val_if_fail (*selected_text == NULL, FALSE);

	if (!gtk_text_buffer_get_selection_bounds (doc, &start, &end))
	{
		if (len != NULL)
		{
			len = 0;
		}

		return FALSE;
	}

	*selected_text = gtk_text_buffer_get_slice (doc, &start, &end, TRUE);

	if (len != NULL)
	{
		*len = g_utf8_strlen (*selected_text, -1);
	}

	return TRUE;
}

static void
show_cb (GeditReplaceDialog *dialog)
{
	GeditWindow *window;
	GeditDocument *doc;
	gboolean selection_exists;
	gchar *selection = NULL;
	gint selection_length;

	window = get_gedit_window (dialog);

	if (window == NULL)
	{
		return;
	}

620
	doc = get_active_document (dialog);
621 622 623 624 625 626 627 628 629 630 631 632

	if (doc == NULL)
	{
		return;
	}

	selection_exists = get_selected_text (GTK_TEXT_BUFFER (doc),
					      &selection,
					      &selection_length);

	if (selection_exists && selection != NULL && selection_length < 80)
	{
633
		gboolean regex_enabled;
634 635
		gchar *escaped_selection;

636 637 638
		regex_enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->regex_checkbutton));

		if (regex_enabled)
639 640 641 642 643 644 645
		{
			escaped_selection = g_regex_escape_string (selection, -1);
		}
		else
		{
			escaped_selection = gtk_source_utils_escape_search_text (selection);
		}
646 647 648 649 650 651 652 653 654 655

		gtk_entry_set_text (GTK_ENTRY (dialog->priv->search_text_entry),
				    escaped_selection);

		g_free (escaped_selection);
	}

	g_free (selection);
}

656 657 658
static void
hide_cb (GeditReplaceDialog *dialog)
{
659
	disconnect_document (dialog);
660 661
}

Paolo Borelli's avatar
Paolo Borelli committed
662
static void
663
gedit_replace_dialog_init (GeditReplaceDialog *dlg)
Paolo Borelli's avatar
Paolo Borelli committed
664
{
665
	dlg->priv = gedit_replace_dialog_get_instance_private (dlg);
666 667

	gtk_widget_init_template (GTK_WIDGET (dlg));
Paolo Borelli's avatar
Paolo Borelli committed
668

669
	dlg->priv->search_entry = gedit_history_entry_new ("search-for-entry", TRUE);
670
	gtk_widget_set_size_request (dlg->priv->search_entry, 300, -1);
671
	gtk_widget_set_hexpand (GTK_WIDGET (dlg->priv->search_entry), TRUE);
672
	dlg->priv->search_text_entry = gedit_history_entry_get_entry (GEDIT_HISTORY_ENTRY (dlg->priv->search_entry));
673 674 675 676 677
	gtk_entry_set_activates_default (GTK_ENTRY (dlg->priv->search_text_entry), TRUE);
	gtk_grid_attach_next_to (GTK_GRID (dlg->priv->grid),
				 dlg->priv->search_entry,
				 dlg->priv->search_label,
				 GTK_POS_RIGHT, 1, 1);
678
	gtk_widget_show_all (dlg->priv->search_entry);
679 680 681

	dlg->priv->replace_entry = gedit_history_entry_new ("replace-with-entry", TRUE);
	gtk_widget_set_hexpand (GTK_WIDGET (dlg->priv->replace_entry), TRUE);
682
	dlg->priv->replace_text_entry = gedit_history_entry_get_entry (GEDIT_HISTORY_ENTRY (dlg->priv->replace_entry));
683 684 685 686 687
	gtk_entry_set_activates_default (GTK_ENTRY (dlg->priv->replace_text_entry), TRUE);
	gtk_grid_attach_next_to (GTK_GRID (dlg->priv->grid),
				 dlg->priv->replace_entry,
				 dlg->priv->replace_label,
				 GTK_POS_RIGHT, 1, 1);
688
	gtk_widget_show_all (dlg->priv->replace_entry);
689 690 691 692 693 694

	gtk_label_set_mnemonic_widget (GTK_LABEL (dlg->priv->search_label),
				       dlg->priv->search_entry);
	gtk_label_set_mnemonic_widget (GTK_LABEL (dlg->priv->replace_label),
				       dlg->priv->replace_entry);

Paolo Borelli's avatar
Paolo Borelli committed
695
	gtk_dialog_set_default_response (GTK_DIALOG (dlg),
696
					 GEDIT_REPLACE_DIALOG_FIND_RESPONSE);
Paolo Borelli's avatar
Paolo Borelli committed
697 698 699

	/* insensitive by default */
	gtk_dialog_set_response_sensitive (GTK_DIALOG (dlg),
700
					   GEDIT_REPLACE_DIALOG_FIND_RESPONSE,
Paolo Borelli's avatar
Paolo Borelli committed
701 702
					   FALSE);
	gtk_dialog_set_response_sensitive (GTK_DIALOG (dlg),
703
					   GEDIT_REPLACE_DIALOG_REPLACE_RESPONSE,
Paolo Borelli's avatar
Paolo Borelli committed
704 705
					   FALSE);
	gtk_dialog_set_response_sensitive (GTK_DIALOG (dlg),
706
					   GEDIT_REPLACE_DIALOG_REPLACE_ALL_RESPONSE,
Paolo Borelli's avatar
Paolo Borelli committed
707 708
					   FALSE);

709
	g_signal_connect (dlg->priv->search_text_entry,
Paolo Borelli's avatar
Paolo Borelli committed
710
			  "changed",
711
			  G_CALLBACK (search_text_entry_changed),
Paolo Borelli's avatar
Paolo Borelli committed
712 713
			  dlg);

714 715 716 717 718
	g_signal_connect (dlg->priv->replace_text_entry,
			  "changed",
			  G_CALLBACK (replace_text_entry_changed),
			  dlg);

719 720 721 722 723
	g_signal_connect (dlg->priv->regex_checkbutton,
			  "toggled",
			  G_CALLBACK (regex_checkbutton_toggled),
			  dlg);

724 725 726 727
	g_signal_connect (dlg,
			  "show",
			  G_CALLBACK (show_cb),
			  NULL);
728 729 730 731 732

	g_signal_connect (dlg,
			  "hide",
			  G_CALLBACK (hide_cb),
			  NULL);
733 734 735 736 737 738 739 740

	/* We connect here to make sure this handler runs before the others so
	 * that the search context is created.
	 */
	g_signal_connect (dlg,
			  "response",
			  G_CALLBACK (response_cb),
			  NULL);
Paolo Borelli's avatar
Paolo Borelli committed
741 742 743
}

GtkWidget *
744
gedit_replace_dialog_new (GeditWindow *window)
Paolo Borelli's avatar
Paolo Borelli committed
745
{
746
	GeditReplaceDialog *dialog;
Paolo Borelli's avatar
Paolo Borelli committed
747

748
	g_return_val_if_fail (GEDIT_IS_WINDOW (window), NULL);
749

750 751 752 753
	dialog = g_object_new (GEDIT_TYPE_REPLACE_DIALOG,
			       "transient-for", window,
			       "destroy-with-parent", TRUE,
			       NULL);
754

755
	return GTK_WIDGET (dialog);
Paolo Borelli's avatar
Paolo Borelli committed
756 757 758
}

const gchar *
759
gedit_replace_dialog_get_replace_text (GeditReplaceDialog *dialog)
Paolo Borelli's avatar
Paolo Borelli committed
760
{
761
	g_return_val_if_fail (GEDIT_IS_REPLACE_DIALOG (dialog), NULL);
Paolo Borelli's avatar
Paolo Borelli committed
762

763
	return gtk_entry_get_text (GTK_ENTRY (dialog->priv->replace_text_entry));
Paolo Borelli's avatar
Paolo Borelli committed
764 765 766
}

gboolean
767
gedit_replace_dialog_get_backwards (GeditReplaceDialog *dialog)
Paolo Borelli's avatar
Paolo Borelli committed
768
{
769
	g_return_val_if_fail (GEDIT_IS_REPLACE_DIALOG (dialog), FALSE);
Paolo Borelli's avatar
Paolo Borelli committed
770 771 772 773

	return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->backwards_checkbutton));
}

774 775 776 777 778 779 780 781 782 783 784 785
/* This function returns the original search text. The search text from the
 * search settings has been unescaped, and the escape function is not
 * reciprocal. So to avoid bugs, we have to deal with the original search text.
 */
const gchar *
gedit_replace_dialog_get_search_text (GeditReplaceDialog *dialog)
{
	g_return_val_if_fail (GEDIT_IS_REPLACE_DIALOG (dialog), NULL);

	return gtk_entry_get_text (GTK_ENTRY (dialog->priv->search_text_entry));
}

786
/* ex:set ts=8 noet: */