GUI: Move .ui files from goffice resources to glib resources
[gnumeric.git] / src / dialogs / dialog-search-replace.c
blob6d2413cf1e59db2c4e889110dee567390c7c357e
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /*
4 * dialog-search-replace.c:
5 * Dialog for entering a search-and-replace query.
7 * Author:
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>
26 #include <gnumeric.h>
27 #include "dialogs.h"
28 #include "help.h"
30 #include <gnumeric-conf.h>
31 #include <gui-util.h>
32 #include <search.h>
33 #include <widgets/gnumeric-expr-entry.h>
34 #include <wbc-gtk.h>
35 #include <selection.h>
37 #include <goffice/goffice.h>
38 #include <gtk/gtk.h>
39 #include <string.h>
41 #define SEARCH_REPLACE_KEY "search-replace-dialog"
43 typedef struct {
44 WBCGtk *wbcg;
45 GtkBuilder *gui;
46 GtkDialog *dialog;
47 GtkEntry *search_text;
48 GtkEntry *replace_text;
49 GnmExprEntry *rangetext;
50 SearchDialogCallback cb;
51 } DialogState;
53 static const char * const error_group[] = {
54 "error_fail",
55 "error_skip",
56 "error_query",
57 "error_error",
58 "error_string",
59 NULL
62 static const char * const search_type_group[] = {
63 "search_type_text",
64 "search_type_regexp",
65 NULL
68 static const char * const scope_group[] = {
69 "scope_workbook",
70 "scope_sheet",
71 "scope_range",
72 NULL
75 static const char * const direction_group[] = {
76 "row_major",
77 "column_major",
78 NULL
81 static gboolean
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));
88 static void
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);
95 static void
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);
111 #undef SETW
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));
121 static void
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;
129 char *err;
130 int i;
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)),
142 "scope", scope,
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,
158 NULL);
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);
171 if (err) {
172 go_gtk_notice_dialog (GTK_WINDOW (dialog), GTK_MESSAGE_ERROR,
173 "%s", err);
174 g_free (err);
175 g_object_unref (sr);
176 return;
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."));
184 g_object_unref (sr);
185 return;
188 cb (wbcg, sr);
189 g_object_unref (sr);
192 static void
193 ok_clicked (GtkWidget *widget, DialogState *dd)
195 apply_clicked (widget, dd);
197 gtk_widget_destroy (GTK_WIDGET (dd->dialog));
198 dd = NULL; /* Destroyed */
201 static void
202 cancel_clicked (G_GNUC_UNUSED GtkWidget *widget, DialogState *dd)
204 GtkDialog *dialog = dd->dialog;
206 gtk_widget_destroy (GTK_WIDGET (dialog));
210 static void
211 cb_dialog_destroy (DialogState *dd)
213 g_object_unref (dd->gui);
214 memset (dd, 0, sizeof (*dd));
215 g_free (dd);
218 static gboolean
219 range_focused (G_GNUC_UNUSED GtkWidget *widget,
220 G_GNUC_UNUSED GdkEventFocus *event,
221 DialogState *dd)
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);
225 return FALSE;
228 void
229 dialog_search_replace (WBCGtk *wbcg,
230 SearchDialogCallback cb)
232 GtkBuilder *gui;
233 GtkDialog *dialog;
234 DialogState *dd;
235 GtkGrid *grid;
236 char *selection_text;
238 g_return_if_fail (wbcg != NULL);
240 /* Only one guru per workbook. */
241 if (wbc_gtk_get_guru (wbcg))
242 return;
244 if (gnm_dialog_raise_if_exists (wbcg, SEARCH_REPLACE_KEY))
245 return;
247 gui = gnm_gtk_builder_load ("res:ui/search-replace.ui", NULL, GO_CMD_CONTEXT (wbcg));
248 if (gui == NULL)
249 return;
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);
257 dd->wbcg = wbcg;
258 dd->gui = gui;
259 dd->cb = cb;
260 dd->dialog = dialog;
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)),
281 TRUE);
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);
296 #undef SETW
298 gtk_toggle_button_set_active
299 (GTK_TOGGLE_BUTTON
300 (go_gtk_builder_get_widget
301 (gui,
302 search_type_group[gnm_conf_get_searchreplace_regex () ? 1 : 0])), TRUE);
303 gtk_toggle_button_set_active
304 (GTK_TOGGLE_BUTTON
305 (go_gtk_builder_get_widget
306 (gui,
307 direction_group[gnm_conf_get_searchreplace_columnmajor () ? 1 : 0])), TRUE);
308 gtk_toggle_button_set_active
309 (GTK_TOGGLE_BUTTON
310 (go_gtk_builder_get_widget
311 (gui,
312 error_group[gnm_conf_get_searchreplace_error_behaviour ()])), TRUE);
313 gtk_toggle_button_set_active
314 (GTK_TOGGLE_BUTTON
315 (go_gtk_builder_get_widget
316 (gui,
317 scope_group[gnm_conf_get_searchreplace_scope ()])), TRUE);
320 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui, "ok_button")),
321 "clicked",
322 G_CALLBACK (ok_clicked), dd);
323 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui, "apply_button")),
324 "clicked",
325 G_CALLBACK (apply_clicked), dd);
326 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui, "cancel_button")),
327 "clicked",
328 G_CALLBACK (cancel_clicked), dd);
329 g_signal_connect (G_OBJECT (gnm_expr_entry_get_entry (dd->rangetext)),
330 "focus-in-event",
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)
358 GtkBuilder *gui;
359 GtkDialog *dialog;
360 int res;
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));
365 if (gui == NULL)
366 return 0;
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")),
374 location);
375 gtk_entry_set_text (GTK_ENTRY (go_gtk_builder_get_widget (gui, "qd_old_text")),
376 old_text);
377 gtk_entry_set_text (GTK_ENTRY (go_gtk_builder_get_widget (gui, "qd_new_text")),
378 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);
390 switch (res) {
391 case GTK_RESPONSE_YES:
392 case GTK_RESPONSE_NO:
393 sr->query = is_checked (gui, "qd_query");
394 break;
395 default:
396 res = GTK_RESPONSE_CANCEL;
399 gtk_widget_destroy (GTK_WIDGET (dialog));
400 g_object_unref (gui);
402 return res;
405 /* ------------------------------------------------------------------------- */