Update Spanish translation
[gnumeric.git] / src / search.c
blob57b5575f68f1a0694d7975c53f1c8033c09879b0
1 /*
2 * search.c: Search-and-replace for Gnumeric.
4 * Copyright (C) 2001-2009 Morten Welinder (terra@gnome.org)
5 */
7 #include <gnumeric-config.h>
8 #include <gnm-i18n.h>
9 #include <gnumeric.h>
10 #include <search.h>
12 #include <gutils.h>
13 #include <ranges.h>
14 #include <sheet.h>
15 #include <workbook.h>
16 #include <position.h>
17 #include <cell.h>
18 #include <number-match.h>
19 #include <value.h>
20 #include <sheet-object-cell-comment.h>
21 #include <gsf/gsf-impl-utils.h>
23 #include <string.h>
24 #include <stdlib.h>
26 static GObjectClass *parent_class;
28 typedef struct {
29 GOSearchReplaceClass base_class;
30 } GnmSearchReplaceClass;
32 enum {
33 PROP_0,
34 PROP_IS_NUMBER,
35 PROP_SEARCH_STRINGS,
36 PROP_SEARCH_OTHER_VALUES,
37 PROP_SEARCH_EXPRESSIONS,
38 PROP_SEARCH_EXPRESSION_RESULTS,
39 PROP_SEARCH_COMMENTS,
40 PROP_SEARCH_SCRIPTS,
41 PROP_INVERT,
42 PROP_BY_ROW,
43 PROP_QUERY,
44 PROP_REPLACE_KEEP_STRINGS,
45 PROP_SHEET,
46 PROP_SCOPE,
47 PROP_RANGE_TEXT
50 /* ------------------------------------------------------------------------- */
52 typedef struct {
53 GnmCell *cell;
54 } GnmSearchReplaceValueResult;
55 static gboolean
56 gnm_search_replace_value (GnmSearchReplace *sr,
57 const GnmEvalPos *ep,
58 GnmSearchReplaceValueResult *res);
60 /* ------------------------------------------------------------------------- */
62 char *
63 gnm_search_normalize (const char *txt)
65 return g_utf8_normalize (txt, -1, G_NORMALIZE_NFD);
68 static char *
69 gnm_search_normalize_result (const char *txt)
71 return g_utf8_normalize (txt, -1, G_NORMALIZE_NFC);
74 /* ------------------------------------------------------------------------- */
76 static gboolean
77 check_number (GnmSearchReplace *sr)
79 GODateConventions const *date_conv = sheet_date_conv (sr->sheet);
80 GOSearchReplace *gosr = (GOSearchReplace *)sr;
81 GnmValue *v = format_match_number (gosr->search_text, NULL, date_conv);
83 if (v) {
84 gnm_float f = value_get_as_float (v);
85 if (f < 0) {
86 sr->low_number = gnm_add_epsilon (f);
87 sr->high_number = gnm_sub_epsilon (f);
88 } else {
89 sr->low_number = gnm_sub_epsilon (f);
90 sr->high_number = gnm_add_epsilon (f);
92 value_release (v);
93 return TRUE;
94 } else {
95 sr->low_number = sr->high_number = gnm_nan;
96 return FALSE;
100 static gboolean
101 gnm_search_match_value (GnmSearchReplace const *sr, GnmValue const *val)
103 gnm_float f;
104 if (!VALUE_IS_NUMBER (val))
105 return FALSE;
106 f = value_get_as_float (val);
108 return (sr->low_number <= f && f <= sr->high_number);
112 char *
113 gnm_search_replace_verify (GnmSearchReplace *sr, gboolean repl)
115 GError *error = NULL;
116 GOSearchReplace *gosr = (GOSearchReplace *)sr;
117 g_return_val_if_fail (sr != NULL, NULL);
119 if (!go_search_replace_verify (gosr, repl, &error)) {
120 char *msg = g_strdup (error->message);
121 g_error_free (error);
122 return msg;
125 if (sr->is_number && gosr->is_regexp)
126 return g_strdup (_("Searching for regular expressions and numbers are mutually exclusive."));
128 if (sr->is_number) {
129 if (!check_number (sr))
130 return g_strdup (_("The search text must be a number."));
133 if (sr->scope == GNM_SRS_RANGE) {
134 GSList *range_list;
136 if (!sr->range_text || sr->range_text[0] == 0)
137 return g_strdup (_("You must specify a range to search."));
139 if ((range_list = global_range_list_parse (sr->sheet, sr->range_text))
140 == NULL)
141 return g_strdup (_("The search range is invalid."));
142 range_list_destroy (range_list);
145 return NULL;
148 /* ------------------------------------------------------------------------- */
150 static int
151 cb_order_sheet_row_col (void const *_a, void const *_b)
153 GnmEvalPos const *a = *(GnmEvalPos const **)_a;
154 GnmEvalPos const *b = *(GnmEvalPos const **)_b;
155 int i;
157 i = strcmp (a->sheet->name_unquoted_collate_key,
158 b->sheet->name_unquoted_collate_key);
160 /* By row number. */
161 if (!i) i = (a->eval.row - b->eval.row);
163 /* By column number. */
164 if (!i) i = (a->eval.col - b->eval.col);
166 return i;
169 static int
170 cb_order_sheet_col_row (void const *_a, void const *_b)
172 GnmEvalPos const *a = *(GnmEvalPos const **)_a;
173 GnmEvalPos const *b = *(GnmEvalPos const **)_b;
174 int i;
176 i = strcmp (a->sheet->name_unquoted_collate_key,
177 b->sheet->name_unquoted_collate_key);
179 /* By column number. */
180 if (!i) i = (a->eval.col - b->eval.col);
182 /* By row number. */
183 if (!i) i = (a->eval.row - b->eval.row);
185 return i;
188 static GnmValue *
189 search_collect_cells_cb (GnmCellIter const *iter, gpointer user)
191 GPtrArray *cells = user;
192 GnmEvalPos *ep = g_new (GnmEvalPos, 1);
194 g_ptr_array_add (cells, eval_pos_init_cell (ep, iter->cell));
196 return NULL;
200 * gnm_search_collect_cells:
201 * @sr: #GnmSearchReplace
203 * Collect a list of all cells subject to search.
204 * Returns: (element-type GnmEvalPos) (transfer full): the newly created array.
206 GPtrArray *
207 gnm_search_collect_cells (GnmSearchReplace *sr)
209 GPtrArray *cells;
211 switch (sr->scope) {
212 case GNM_SRS_WORKBOOK:
213 g_return_val_if_fail (sr->sheet != NULL, NULL);
214 cells = workbook_cells (sr->sheet->workbook, TRUE,
215 GNM_SHEET_VISIBILITY_HIDDEN);
216 break;
218 case GNM_SRS_SHEET:
219 cells = sheet_cell_positions (sr->sheet, TRUE);
220 break;
222 case GNM_SRS_RANGE:
224 GSList *range_list;
225 GnmEvalPos ep;
226 cells = g_ptr_array_new ();
227 range_list = global_range_list_parse (sr->sheet, sr->range_text);
228 global_range_list_foreach (range_list,
229 eval_pos_init_sheet (&ep, sr->sheet),
230 CELL_ITER_IGNORE_BLANK,
231 search_collect_cells_cb, cells);
232 range_list_destroy (range_list);
233 break;
236 default:
237 cells = NULL;
238 g_assert_not_reached ();
241 /* Sort our cells. */
242 g_ptr_array_sort (cells,
243 sr->by_row ? cb_order_sheet_row_col : cb_order_sheet_col_row);
245 return cells;
249 * gnm_search_collect_cells_free:
250 * @cells: (element-type GnmEvalPos) (transfer full):
252 void
253 gnm_search_collect_cells_free (GPtrArray *cells)
255 unsigned i;
257 for (i = 0; i < cells->len; i++)
258 g_free (g_ptr_array_index (cells, i));
259 g_ptr_array_free (cells, TRUE);
262 /* ------------------------------------------------------------------------- */
264 * gnm_search_filter_matching:
265 * @sr: The search spec.
266 * @cells: (element-type GnmEvalPos): Cell positions to filter, presumably a result of gnm_search_collect_cells.
268 * Returns: (element-type GnmSearchFilterResult) (transfer full): matches
271 GPtrArray *
272 gnm_search_filter_matching (GnmSearchReplace *sr, const GPtrArray *cells)
274 unsigned i;
275 GPtrArray *result = g_ptr_array_new ();
277 if (sr->is_number)
278 check_number (sr);
280 for (i = 0; i < cells->len; i++) {
281 GnmSearchReplaceCellResult cell_res;
282 GnmSearchReplaceValueResult value_res;
283 GnmSearchReplaceCommentResult comment_res;
284 gboolean found;
285 const GnmEvalPos *ep = g_ptr_array_index (cells, i);
287 found = gnm_search_replace_cell (sr, ep, FALSE, &cell_res);
288 g_free (cell_res.old_text);
289 if (cell_res.cell != NULL && found != sr->invert) {
290 GnmSearchFilterResult *item = g_new (GnmSearchFilterResult, 1);
291 item->ep = *ep;
292 item->locus = GNM_SRL_CONTENTS;
293 g_ptr_array_add (result, item);
296 found = gnm_search_replace_value (sr, ep, &value_res);
297 if (value_res.cell != NULL && gnm_cell_has_expr (value_res.cell) && found != sr->invert) {
298 GnmSearchFilterResult *item = g_new (GnmSearchFilterResult, 1);
299 item->ep = *ep;
300 item->locus = GNM_SRL_VALUE;
301 g_ptr_array_add (result, item);
304 found = gnm_search_replace_comment (sr, ep, FALSE, &comment_res);
305 if (comment_res.comment != NULL && found != sr->invert) {
306 GnmSearchFilterResult *item = g_new (GnmSearchFilterResult, 1);
307 item->ep = *ep;
308 item->locus = GNM_SRL_COMMENT;
309 g_ptr_array_add (result, item);
313 return result;
317 * gnm_search_filter_matching_free:
318 * @matches: (element-type GnmSearchFilterResult) (transfer full): matches
320 void
321 gnm_search_filter_matching_free (GPtrArray *matches)
323 unsigned i;
324 for (i = 0; i < matches->len; i++)
325 g_free (g_ptr_array_index (matches, i));
326 g_ptr_array_free (matches, TRUE);
329 /* ------------------------------------------------------------------------- */
331 gboolean
332 gnm_search_replace_comment (GnmSearchReplace *sr,
333 const GnmEvalPos *ep,
334 gboolean repl,
335 GnmSearchReplaceCommentResult *res)
337 gboolean found;
338 char *norm_text;
340 g_return_val_if_fail (res, FALSE);
342 res->comment = NULL;
343 res->old_text = NULL;
344 res->new_text = NULL;
346 g_return_val_if_fail (sr, FALSE);
348 if (!sr->search_comments) return FALSE;
349 if (sr->is_number) return FALSE;
351 res->comment = sheet_get_comment (ep->sheet, &ep->eval);
352 if (!res->comment) return FALSE;
354 res->old_text = cell_comment_text_get (res->comment);
356 norm_text = gnm_search_normalize (res->old_text);
358 if (repl) {
359 res->new_text = go_search_replace_string (GO_SEARCH_REPLACE (sr),
360 norm_text);
361 found = (res->new_text != NULL);
362 if (found) {
363 char *norm = gnm_search_normalize_result (res->new_text);
364 g_free (res->new_text);
365 res->new_text = norm;
367 } else
368 found = go_search_match_string (GO_SEARCH_REPLACE (sr),
369 norm_text);
371 g_free (norm_text);
373 return found;
376 /* ------------------------------------------------------------------------- */
378 gboolean
379 gnm_search_replace_cell (GnmSearchReplace *sr,
380 const GnmEvalPos *ep,
381 gboolean repl,
382 GnmSearchReplaceCellResult *res)
384 GnmCell *cell;
385 GnmValue *v;
386 gboolean is_expr, is_value, is_string, is_other;
387 gboolean found = FALSE;
389 g_return_val_if_fail (res, FALSE);
391 res->cell = NULL;
392 res->old_text = NULL;
393 res->new_text = NULL;
395 g_return_val_if_fail (sr, FALSE);
397 cell = res->cell = sheet_cell_get (ep->sheet, ep->eval.col, ep->eval.row);
398 if (!cell) return FALSE;
400 v = cell->value;
402 is_expr = gnm_cell_has_expr (cell);
403 is_value = !is_expr && !gnm_cell_is_empty (cell) && v;
404 is_string = is_value && (VALUE_IS_STRING (v));
405 is_other = is_value && !is_string;
407 if (sr->is_number) {
408 if (!is_value || !VALUE_IS_NUMBER (v))
409 return FALSE;
410 return gnm_search_match_value (sr, v);
413 if ((is_expr && sr->search_expressions) ||
414 (is_string && sr->search_strings) ||
415 (is_other && sr->search_other_values)) {
416 char *actual_src;
417 gboolean initial_quote;
419 res->old_text = gnm_cell_get_entered_text (cell);
420 initial_quote = (is_string && res->old_text[0] == '\'');
422 actual_src = gnm_search_normalize (res->old_text + initial_quote);
424 if (repl) {
425 res->new_text = go_search_replace_string (GO_SEARCH_REPLACE (sr),
426 actual_src);
427 if (res->new_text) {
428 char *norm = gnm_search_normalize_result (res->new_text);
429 g_free (res->new_text);
430 res->new_text = norm;
432 if (sr->replace_keep_strings && is_string) {
434 * The initial quote was not part of the s-a-r,
435 * so tack it back on.
437 char *tmp = g_new (char, strlen (res->new_text) + 2);
438 tmp[0] = '\'';
439 strcpy (tmp + 1, res->new_text);
440 g_free (res->new_text);
441 res->new_text = tmp;
443 found = TRUE;
445 } else
446 found = go_search_match_string (GO_SEARCH_REPLACE (sr), actual_src);
448 g_free (actual_src);
451 return found;
454 /* ------------------------------------------------------------------------- */
456 static gboolean
457 gnm_search_replace_value (GnmSearchReplace *sr,
458 const GnmEvalPos *ep,
459 GnmSearchReplaceValueResult *res)
461 GnmCell *cell;
463 g_return_val_if_fail (res, FALSE);
465 res->cell = NULL;
467 g_return_val_if_fail (sr, FALSE);
469 if (!sr->search_expression_results)
470 return FALSE;
472 cell = res->cell = sheet_cell_get (ep->sheet, ep->eval.col, ep->eval.row);
473 if (!cell || !gnm_cell_has_expr (cell) || !cell->value)
474 return FALSE;
475 else if (sr->is_number) {
476 return gnm_search_match_value (sr, cell->value);
477 } else {
478 char *val = gnm_search_normalize (value_peek_string (cell->value));
479 gboolean res = go_search_match_string (GO_SEARCH_REPLACE (sr), val);
480 g_free (val);
481 return res;
485 /* ------------------------------------------------------------------------- */
487 void
488 gnm_search_replace_query_fail (GnmSearchReplace *sr,
489 const GnmSearchReplaceCellResult *res)
491 if (!sr->query_func)
492 return;
494 sr->query_func (GNM_SRQ_FAIL, sr,
495 res->cell, res->old_text, res->new_text);
499 gnm_search_replace_query_cell (GnmSearchReplace *sr,
500 const GnmSearchReplaceCellResult *res)
502 if (!sr->query || !sr->query_func)
503 return GTK_RESPONSE_YES;
505 return sr->query_func (GNM_SRQ_QUERY, sr,
506 res->cell, res->old_text, res->new_text);
511 gnm_search_replace_query_comment (GnmSearchReplace *sr,
512 const GnmEvalPos *ep,
513 const GnmSearchReplaceCommentResult *res)
515 if (!sr->query || !sr->query_func)
516 return GTK_RESPONSE_YES;
518 return sr->query_func (GNM_SRQ_QUERY_COMMENT, sr,
519 ep->sheet, &ep->eval,
520 res->old_text, res->new_text);
523 /* ------------------------------------------------------------------------- */
525 GType
526 gnm_search_replace_scope_get_type (void)
528 static GType etype = 0;
529 if (etype == 0) {
530 static const GEnumValue values[] = {
531 { GNM_SRS_WORKBOOK, "GNM_SRS_WORKBOOK", "workbook" },
532 { GNM_SRS_SHEET, "GNM_SRS_SHEET", "sheet" },
533 { GNM_SRS_RANGE, "GNM_SRS_RANGE", "range" },
534 { 0, NULL, NULL }
536 etype = g_enum_register_static ("GnmSearchReplaceScope", values);
538 return etype;
541 /* ------------------------------------------------------------------------- */
543 static void
544 gnm_search_replace_init (GObject *obj)
548 /* ------------------------------------------------------------------------- */
550 static void
551 gnm_search_replace_get_property (GObject *object,
552 guint property_id,
553 GValue *value,
554 GParamSpec *pspec)
556 GnmSearchReplace *sr = (GnmSearchReplace *)object;
558 switch (property_id) {
559 case PROP_IS_NUMBER:
560 g_value_set_boolean (value, sr->is_number);
561 break;
562 case PROP_SEARCH_STRINGS:
563 g_value_set_boolean (value, sr->search_strings);
564 break;
565 case PROP_SEARCH_OTHER_VALUES:
566 g_value_set_boolean (value, sr->search_other_values);
567 break;
568 case PROP_SEARCH_EXPRESSIONS:
569 g_value_set_boolean (value, sr->search_expressions);
570 break;
571 case PROP_SEARCH_EXPRESSION_RESULTS:
572 g_value_set_boolean (value, sr->search_expression_results);
573 break;
574 case PROP_SEARCH_COMMENTS:
575 g_value_set_boolean (value, sr->search_comments);
576 break;
577 case PROP_SEARCH_SCRIPTS:
578 g_value_set_boolean (value, sr->search_scripts);
579 break;
580 case PROP_INVERT:
581 g_value_set_boolean (value, sr->invert);
582 break;
583 case PROP_BY_ROW:
584 g_value_set_boolean (value, sr->by_row);
585 break;
586 case PROP_QUERY:
587 g_value_set_boolean (value, sr->query);
588 break;
589 case PROP_REPLACE_KEEP_STRINGS:
590 g_value_set_boolean (value, sr->replace_keep_strings);
591 break;
592 case PROP_SHEET:
593 g_value_set_object (value, sr->sheet);
594 break;
595 case PROP_SCOPE:
596 g_value_set_enum (value, sr->scope);
597 break;
598 case PROP_RANGE_TEXT:
599 g_value_set_string (value, sr->range_text);
600 break;
601 default:
602 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
603 break;
607 /* ------------------------------------------------------------------------- */
609 static void
610 gnm_search_replace_set_sheet (GnmSearchReplace *sr, Sheet *sheet)
612 if (sheet)
613 g_object_ref (sheet);
614 if (sr->sheet)
615 g_object_unref (sr->sheet);
616 sr->sheet = sheet;
619 static void
620 gnm_search_replace_set_range_text (GnmSearchReplace *sr, char const *text)
622 char *text_copy = g_strdup (text);
623 g_free (sr->range_text);
624 sr->range_text = text_copy;
627 static void
628 gnm_search_replace_set_property (GObject *object,
629 guint property_id,
630 GValue const *value,
631 GParamSpec *pspec)
633 GnmSearchReplace *sr = (GnmSearchReplace *)object;
635 switch (property_id) {
636 case PROP_IS_NUMBER:
637 sr->is_number = g_value_get_boolean (value);
638 break;
639 case PROP_SEARCH_STRINGS:
640 sr->search_strings = g_value_get_boolean (value);
641 break;
642 case PROP_SEARCH_OTHER_VALUES:
643 sr->search_other_values = g_value_get_boolean (value);
644 break;
645 case PROP_SEARCH_EXPRESSIONS:
646 sr->search_expressions = g_value_get_boolean (value);
647 break;
648 case PROP_SEARCH_EXPRESSION_RESULTS:
649 sr->search_expression_results = g_value_get_boolean (value);
650 break;
651 case PROP_SEARCH_COMMENTS:
652 sr->search_comments = g_value_get_boolean (value);
653 break;
654 case PROP_SEARCH_SCRIPTS:
655 sr->search_scripts = g_value_get_boolean (value);
656 break;
657 case PROP_INVERT:
658 sr->invert = g_value_get_boolean (value);
659 break;
660 case PROP_BY_ROW:
661 sr->by_row = g_value_get_boolean (value);
662 break;
663 case PROP_QUERY:
664 sr->query = g_value_get_boolean (value);
665 break;
666 case PROP_REPLACE_KEEP_STRINGS:
667 sr->replace_keep_strings = g_value_get_boolean (value);
668 break;
669 case PROP_SHEET:
670 gnm_search_replace_set_sheet (sr, g_value_get_object (value));
671 break;
672 case PROP_SCOPE:
673 sr->scope = g_value_get_enum (value);
674 break;
675 case PROP_RANGE_TEXT:
676 gnm_search_replace_set_range_text (sr, g_value_get_string (value));
677 break;
678 default:
679 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
680 break;
684 /* ------------------------------------------------------------------------- */
686 static void
687 gnm_search_replace_finalize (GObject *obj)
689 GnmSearchReplace *sr = (GnmSearchReplace *)obj;
691 gnm_search_replace_set_sheet (sr, NULL);
692 g_free (sr->range_text);
694 G_OBJECT_CLASS (parent_class)->finalize (obj);
697 /* ------------------------------------------------------------------------- */
699 static void
700 gnm_search_replace_class_init (GObjectClass *gobject_class)
702 parent_class = g_type_class_peek_parent (gobject_class);
704 gobject_class->finalize = gnm_search_replace_finalize;
705 gobject_class->get_property = gnm_search_replace_get_property;
706 gobject_class->set_property = gnm_search_replace_set_property;
708 g_object_class_install_property
709 (gobject_class,
710 PROP_IS_NUMBER,
711 g_param_spec_boolean ("is-number",
712 P_("Is Number"),
713 P_("Search for Specific Number Regardless of Formatting?"),
714 FALSE,
715 GSF_PARAM_STATIC |
716 G_PARAM_READWRITE));
717 g_object_class_install_property
718 (gobject_class,
719 PROP_SEARCH_STRINGS,
720 g_param_spec_boolean ("search-strings",
721 P_("Search Strings"),
722 P_("Should strings be searched?"),
723 FALSE,
724 GSF_PARAM_STATIC |
725 G_PARAM_READWRITE));
726 g_object_class_install_property
727 (gobject_class,
728 PROP_SEARCH_OTHER_VALUES,
729 g_param_spec_boolean ("search-other-values",
730 P_("Search Other Values"),
731 P_("Should non-strings be searched?"),
732 FALSE,
733 GSF_PARAM_STATIC |
734 G_PARAM_READWRITE));
735 g_object_class_install_property
736 (gobject_class,
737 PROP_SEARCH_EXPRESSIONS,
738 g_param_spec_boolean ("search-expressions",
739 P_("Search Expressions"),
740 P_("Should expressions be searched?"),
741 FALSE,
742 GSF_PARAM_STATIC |
743 G_PARAM_READWRITE));
744 g_object_class_install_property
745 (gobject_class,
746 PROP_SEARCH_EXPRESSION_RESULTS,
747 g_param_spec_boolean ("search-expression-results",
748 P_("Search Expression Results"),
749 P_("Should the results of expressions be searched?"),
750 FALSE,
751 GSF_PARAM_STATIC |
752 G_PARAM_READWRITE));
753 g_object_class_install_property
754 (gobject_class,
755 PROP_SEARCH_COMMENTS,
756 g_param_spec_boolean ("search-comments",
757 P_("Search Comments"),
758 P_("Should cell comments be searched?"),
759 FALSE,
760 GSF_PARAM_STATIC |
761 G_PARAM_READWRITE));
762 g_object_class_install_property
763 (gobject_class,
764 PROP_SEARCH_SCRIPTS,
765 g_param_spec_boolean ("search-scripts",
766 P_("Search Scripts"),
767 P_("Should scrips (workbook, and worksheet) be searched?"),
768 FALSE,
769 GSF_PARAM_STATIC |
770 G_PARAM_READWRITE));
771 g_object_class_install_property
772 (gobject_class,
773 PROP_INVERT,
774 g_param_spec_boolean ("invert",
775 P_("Invert"),
776 P_("Collect non-matching items"),
777 FALSE,
778 GSF_PARAM_STATIC |
779 G_PARAM_READWRITE));
780 g_object_class_install_property
781 (gobject_class,
782 PROP_BY_ROW,
783 g_param_spec_boolean ("by-row",
784 P_("By Row"),
785 P_("Is the search order by row?"),
786 FALSE,
787 GSF_PARAM_STATIC |
788 G_PARAM_READWRITE));
789 g_object_class_install_property
790 (gobject_class,
791 PROP_QUERY,
792 g_param_spec_boolean ("query",
793 P_("Query"),
794 P_("Should we query for each replacement?"),
795 FALSE,
796 GSF_PARAM_STATIC |
797 G_PARAM_READWRITE));
798 g_object_class_install_property
799 (gobject_class,
800 PROP_REPLACE_KEEP_STRINGS,
801 g_param_spec_boolean ("replace-keep-strings",
802 P_("Keep Strings"),
803 P_("Should replacement keep strings as strings?"),
804 FALSE,
805 GSF_PARAM_STATIC |
806 G_PARAM_READWRITE));
807 g_object_class_install_property
808 (gobject_class,
809 PROP_SHEET,
810 g_param_spec_object ("sheet",
811 P_("Sheet"),
812 P_("The sheet in which to search."),
813 GNM_SHEET_TYPE,
814 GSF_PARAM_STATIC |
815 G_PARAM_READWRITE));
816 g_object_class_install_property
817 (gobject_class,
818 PROP_SCOPE,
819 g_param_spec_enum ("scope",
820 P_("Scope"),
821 P_("Where to search."),
822 GNM_SEARCH_REPLACE_SCOPE_TYPE,
823 GNM_SRS_SHEET,
824 GSF_PARAM_STATIC |
825 G_PARAM_READWRITE));
826 g_object_class_install_property
827 (gobject_class,
828 PROP_RANGE_TEXT,
829 g_param_spec_string ("range-text",
830 P_("Range as Text"),
831 P_("The range in which to search."),
832 NULL,
833 GSF_PARAM_STATIC |
834 G_PARAM_READWRITE));
837 /* ------------------------------------------------------------------------- */
839 GSF_CLASS (GnmSearchReplace, gnm_search_replace,
840 gnm_search_replace_class_init, gnm_search_replace_init, GO_TYPE_SEARCH_REPLACE)