1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * dialog-search-replace.c:
5 * Dialog for entering a search-and-replace query.
8 * Morten Welinder (terra@gnome.org)
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <https://www.gnu.org/licenses/>.
24 #include <gnumeric-config.h>
25 #include <glib/gi18n-lib.h>
30 #include <gnumeric-conf.h>
33 #include <widgets/gnumeric-expr-entry.h>
35 #include <selection.h>
37 #include <goffice/goffice.h>
41 #define SEARCH_REPLACE_KEY "search-replace-dialog"
47 GtkEntry
*search_text
;
48 GtkEntry
*replace_text
;
49 GnmExprEntry
*rangetext
;
50 SearchDialogCallback cb
;
53 static const char * const error_group
[] = {
62 static const char * const search_type_group
[] = {
68 static const char * const scope_group
[] = {
75 static const char * const direction_group
[] = {
82 is_checked (GtkBuilder
*gui
, const char *name
)
84 GtkWidget
*w
= go_gtk_builder_get_widget (gui
, name
);
85 return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w
));
89 set_checked (GtkBuilder
*gui
, const char *name
, gboolean checked
)
91 GtkWidget
*w
= go_gtk_builder_get_widget (gui
, name
);
92 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w
), checked
);
96 dialog_search_replace_save_in_prefs (DialogState
*dd
)
98 GtkBuilder
*gui
= dd
->gui
;
100 #define SETW(w,f) f (is_checked (gui, w));
101 SETW("search_expr", gnm_conf_set_searchreplace_change_cell_expressions
);
102 SETW("search_other", gnm_conf_set_searchreplace_change_cell_other
);
103 SETW("search_string", gnm_conf_set_searchreplace_change_cell_strings
);
104 SETW("search_comments", gnm_conf_set_searchreplace_change_comments
);
105 SETW("ignore_case", gnm_conf_set_searchreplace_ignore_case
);
106 SETW("keep_strings", gnm_conf_set_searchreplace_keep_strings
);
107 SETW("preserve_case", gnm_conf_set_searchreplace_preserve_case
);
108 SETW("query", gnm_conf_set_searchreplace_query
);
109 SETW("match_words", gnm_conf_set_searchreplace_whole_words_only
);
110 SETW("column_major", gnm_conf_set_searchreplace_columnmajor
);
113 gnm_conf_set_searchreplace_regex
114 (gnm_gui_group_value (gui
, search_type_group
));
115 gnm_conf_set_searchreplace_error_behaviour
116 (gnm_gui_group_value (gui
, error_group
));
117 gnm_conf_set_searchreplace_scope
118 (gnm_gui_group_value (gui
, scope_group
));
122 apply_clicked (G_GNUC_UNUSED GtkWidget
*widget
, DialogState
*dd
)
124 GtkBuilder
*gui
= dd
->gui
;
125 GtkDialog
*dialog
= dd
->dialog
;
126 WBCGtk
*wbcg
= dd
->wbcg
;
127 SearchDialogCallback cb
= dd
->cb
;
128 GnmSearchReplace
*sr
;
131 GnmSearchReplaceScope scope
;
132 char *search_text
, *replace_text
;
134 i
= gnm_gui_group_value (gui
, scope_group
);
135 scope
= (i
== -1) ? GNM_SRS_SHEET
: (GnmSearchReplaceScope
)i
;
137 search_text
= gnm_search_normalize (gtk_entry_get_text (dd
->search_text
));
138 replace_text
= gnm_search_normalize (gtk_entry_get_text (dd
->replace_text
));
140 sr
= g_object_new (GNM_SEARCH_REPLACE_TYPE
,
141 "sheet", wb_control_cur_sheet (GNM_WBC (wbcg
)),
143 "range-text", gnm_expr_entry_get_text (dd
->rangetext
),
144 "search-text", search_text
,
145 "replace-text", replace_text
,
146 "is-regexp", gnm_gui_group_value (gui
, search_type_group
) == 1,
147 "ignore-case", is_checked (gui
, "ignore_case"),
148 "match-words", is_checked (gui
, "match_words"),
149 "preserve-case", is_checked (gui
, "preserve_case"),
150 "query", is_checked (gui
, "query"),
151 "replace-keep-strings", is_checked (gui
, "keep_strings"),
152 "search-strings", is_checked (gui
, "search_string"),
153 "search-other-values", is_checked (gui
, "search_other"),
154 "search-expressions", is_checked (gui
, "search_expr"),
155 "search-expression-results", FALSE
,
156 "search-comments", is_checked (gui
, "search_comments"),
157 "by-row", gnm_gui_group_value (gui
, direction_group
) == 0,
160 g_free (search_text
);
161 g_free (replace_text
);
163 i
= gnm_gui_group_value (gui
, error_group
);
164 sr
->error_behaviour
= (i
== -1) ? GNM_SRE_FAIL
: (GnmSearchReplaceError
)i
;
166 if (is_checked (gui
, "save-in-prefs"))
167 dialog_search_replace_save_in_prefs (dd
);
170 err
= gnm_search_replace_verify (sr
, TRUE
);
172 go_gtk_notice_dialog (GTK_WINDOW (dialog
), GTK_MESSAGE_ERROR
,
177 } else if (!sr
->search_strings
&&
178 !sr
->search_other_values
&&
179 !sr
->search_expressions
&&
180 !sr
->search_expression_results
&&
181 !sr
->search_comments
) {
182 go_gtk_notice_dialog (GTK_WINDOW (dialog
), GTK_MESSAGE_ERROR
,
183 _("You must select some cell types to search."));
193 ok_clicked (GtkWidget
*widget
, DialogState
*dd
)
195 apply_clicked (widget
, dd
);
197 gtk_widget_destroy (GTK_WIDGET (dd
->dialog
));
198 dd
= NULL
; /* Destroyed */
202 cancel_clicked (G_GNUC_UNUSED GtkWidget
*widget
, DialogState
*dd
)
204 GtkDialog
*dialog
= dd
->dialog
;
206 gtk_widget_destroy (GTK_WIDGET (dialog
));
211 cb_dialog_destroy (DialogState
*dd
)
213 g_object_unref (dd
->gui
);
214 memset (dd
, 0, sizeof (*dd
));
219 range_focused (G_GNUC_UNUSED GtkWidget
*widget
,
220 G_GNUC_UNUSED GdkEventFocus
*event
,
223 GtkWidget
*scope_range
= go_gtk_builder_get_widget (dd
->gui
, "scope_range");
224 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scope_range
), TRUE
);
229 dialog_search_replace (WBCGtk
*wbcg
,
230 SearchDialogCallback cb
)
236 char *selection_text
;
238 g_return_if_fail (wbcg
!= NULL
);
240 /* Only one guru per workbook. */
241 if (wbc_gtk_get_guru (wbcg
))
244 if (gnm_dialog_raise_if_exists (wbcg
, SEARCH_REPLACE_KEY
))
247 gui
= gnm_gtk_builder_load ("res:ui/search-replace.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
251 dialog
= GTK_DIALOG (go_gtk_builder_get_widget (gui
, "search_replace_dialog"));
253 /* Fairly silly: we need to destroy the other dialog in the file. */
254 gtk_widget_destroy (go_gtk_builder_get_widget (gui
, "query_dialog"));
256 dd
= g_new (DialogState
, 1);
262 grid
= GTK_GRID (go_gtk_builder_get_widget (gui
, "normal-grid"));
263 dd
->search_text
= GTK_ENTRY (gtk_entry_new ());
264 gtk_widget_set_hexpand (GTK_WIDGET (dd
->search_text
), TRUE
);
265 gtk_grid_attach (grid
, GTK_WIDGET (dd
->search_text
), 1, 1, 2, 1);
266 gnm_editable_enters (GTK_WINDOW (dialog
),
267 GTK_WIDGET (dd
->search_text
));
269 dd
->replace_text
= GTK_ENTRY (gtk_entry_new ());
270 gtk_widget_set_hexpand (GTK_WIDGET (dd
->replace_text
), TRUE
);
271 gtk_grid_attach (grid
, GTK_WIDGET (dd
->replace_text
), 1, 2, 2, 1);
272 gnm_editable_enters (GTK_WINDOW (dialog
),
273 GTK_WIDGET (dd
->replace_text
));
275 dd
->rangetext
= gnm_expr_entry_new (wbcg
, TRUE
);
276 gnm_expr_entry_set_flags (dd
->rangetext
, 0, GNM_EE_MASK
);
277 gtk_widget_set_hexpand (GTK_WIDGET (dd
->rangetext
), TRUE
);
278 gtk_grid_attach (grid
, GTK_WIDGET (dd
->rangetext
), 1, 9, 2, 1);
279 selection_text
= selection_to_string (
280 wb_control_cur_sheet_view (GNM_WBC (wbcg
)),
282 gnm_expr_entry_load_from_text (dd
->rangetext
, selection_text
);
283 g_free (selection_text
);
284 gtk_widget_show (GTK_WIDGET (dd
->rangetext
));
286 #define SETW(w,f) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (gui, w)), f())
287 SETW("search_expr", gnm_conf_get_searchreplace_change_cell_expressions
);
288 SETW("search_other", gnm_conf_get_searchreplace_change_cell_other
);
289 SETW("search_string", gnm_conf_get_searchreplace_change_cell_strings
);
290 SETW("search_comments", gnm_conf_get_searchreplace_change_comments
);
291 SETW("ignore_case", gnm_conf_get_searchreplace_ignore_case
);
292 SETW("keep_strings", gnm_conf_get_searchreplace_keep_strings
);
293 SETW("preserve_case", gnm_conf_get_searchreplace_preserve_case
);
294 SETW("query", gnm_conf_get_searchreplace_query
);
295 SETW("match_words", gnm_conf_get_searchreplace_whole_words_only
);
298 gtk_toggle_button_set_active
300 (go_gtk_builder_get_widget
302 search_type_group
[gnm_conf_get_searchreplace_regex () ? 1 : 0])), TRUE
);
303 gtk_toggle_button_set_active
305 (go_gtk_builder_get_widget
307 direction_group
[gnm_conf_get_searchreplace_columnmajor () ? 1 : 0])), TRUE
);
308 gtk_toggle_button_set_active
310 (go_gtk_builder_get_widget
312 error_group
[gnm_conf_get_searchreplace_error_behaviour ()])), TRUE
);
313 gtk_toggle_button_set_active
315 (go_gtk_builder_get_widget
317 scope_group
[gnm_conf_get_searchreplace_scope ()])), TRUE
);
320 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "ok_button")),
322 G_CALLBACK (ok_clicked
), dd
);
323 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "apply_button")),
325 G_CALLBACK (apply_clicked
), dd
);
326 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui
, "cancel_button")),
328 G_CALLBACK (cancel_clicked
), dd
);
329 g_signal_connect (G_OBJECT (gnm_expr_entry_get_entry (dd
->rangetext
)),
331 G_CALLBACK (range_focused
), dd
);
333 gnm_init_help_button (
334 go_gtk_builder_get_widget (gui
, "help_button"),
335 GNUMERIC_HELP_LINK_SEARCH_REPLACE
);
336 g_object_set_data_full (G_OBJECT (dialog
),
337 "state", dd
, (GDestroyNotify
) cb_dialog_destroy
);
339 gtk_widget_show_all (gtk_dialog_get_content_area (dialog
));
340 gtk_widget_grab_focus (GTK_WIDGET (dd
->search_text
));
342 gnm_dialog_setup_destroy_handlers (dialog
, wbcg
,
343 GNM_DIALOG_DESTROY_SHEET_REMOVED
);
345 wbc_gtk_attach_guru (wbcg
, GTK_WIDGET (dialog
));
347 gnm_keyed_dialog (wbcg
, GTK_WINDOW (dialog
), SEARCH_REPLACE_KEY
);
348 gtk_widget_show (GTK_WIDGET (dialog
));
352 dialog_search_replace_query (WBCGtk
*wbcg
,
353 GnmSearchReplace
*sr
,
354 const char *location
,
355 const char *old_text
,
356 const char *new_text
)
362 g_return_val_if_fail (wbcg
!= NULL
, 0);
364 gui
= gnm_gtk_builder_load ("res:ui/search-replace.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
368 dialog
= GTK_DIALOG (go_gtk_builder_get_widget (gui
, "query_dialog"));
370 /* Fairly silly: we need to destroy the other dialog in the file. */
371 gtk_widget_destroy (go_gtk_builder_get_widget (gui
, "search_replace_dialog"));
373 gtk_entry_set_text (GTK_ENTRY (go_gtk_builder_get_widget (gui
, "qd_location")),
375 gtk_entry_set_text (GTK_ENTRY (go_gtk_builder_get_widget (gui
, "qd_old_text")),
377 gtk_entry_set_text (GTK_ENTRY (go_gtk_builder_get_widget (gui
, "qd_new_text")),
380 set_checked (gui
, "qd_query", sr
->query
);
382 wbcg_set_transient (wbcg
, GTK_WINDOW (dialog
));
383 go_dialog_guess_alternative_button_order (dialog
);
384 gtk_widget_show_all (GTK_WIDGET (dialog
));
386 gnm_dialog_setup_destroy_handlers (dialog
, wbcg
,
387 GNM_DIALOG_DESTROY_SHEET_REMOVED
);
389 res
= gtk_dialog_run (dialog
);
391 case GTK_RESPONSE_YES
:
392 case GTK_RESPONSE_NO
:
393 sr
->query
= is_checked (gui
, "qd_query");
396 res
= GTK_RESPONSE_CANCEL
;
399 gtk_widget_destroy (GTK_WIDGET (dialog
));
400 g_object_unref (gui
);
405 /* ------------------------------------------------------------------------- */