Compilation: fix warning.
[gnumeric.git] / src / search.c
blob1af1ea5bfdcdd14b8d53793da2c475fdbfb4030a
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 =
80 workbook_date_conv (sr->sheet->workbook);
81 GOSearchReplace *gosr = (GOSearchReplace *)sr;
82 GnmValue *v = format_match_number (gosr->search_text, NULL, date_conv);
84 if (v) {
85 gnm_float f = value_get_as_float (v);
86 if (f < 0) {
87 sr->low_number = gnm_add_epsilon (f);
88 sr->high_number = gnm_sub_epsilon (f);
89 } else {
90 sr->low_number = gnm_sub_epsilon (f);
91 sr->high_number = gnm_add_epsilon (f);
93 value_release (v);
94 return TRUE;
95 } else {
96 sr->low_number = sr->high_number = gnm_nan;
97 return FALSE;
101 static gboolean
102 gnm_search_match_value (GnmSearchReplace const *sr, GnmValue const *val)
104 gnm_float f;
105 if (!VALUE_IS_NUMBER (val))
106 return FALSE;
107 f = value_get_as_float (val);
109 return (sr->low_number <= f && f <= sr->high_number);
113 char *
114 gnm_search_replace_verify (GnmSearchReplace *sr, gboolean repl)
116 GError *error = NULL;
117 GOSearchReplace *gosr = (GOSearchReplace *)sr;
118 g_return_val_if_fail (sr != NULL, NULL);
120 if (!go_search_replace_verify (gosr, repl, &error)) {
121 char *msg = g_strdup (error->message);
122 g_error_free (error);
123 return msg;
126 if (sr->is_number && gosr->is_regexp)
127 return g_strdup (_("Searching for regular expressions and numbers are mutually exclusive."));
129 if (sr->is_number) {
130 if (!check_number (sr))
131 return g_strdup (_("The search text must be a number."));
134 if (sr->scope == GNM_SRS_RANGE) {
135 GSList *range_list;
137 if (!sr->range_text || sr->range_text[0] == 0)
138 return g_strdup (_("You must specify a range to search."));
140 if ((range_list = global_range_list_parse (sr->sheet, sr->range_text))
141 == NULL)
142 return g_strdup (_("The search range is invalid."));
143 range_list_destroy (range_list);
146 return NULL;
149 /* ------------------------------------------------------------------------- */
151 static int
152 cb_order_sheet_row_col (void const *_a, void const *_b)
154 GnmEvalPos const *a = *(GnmEvalPos const **)_a;
155 GnmEvalPos const *b = *(GnmEvalPos const **)_b;
156 int i;
158 i = strcmp (a->sheet->name_unquoted_collate_key,
159 b->sheet->name_unquoted_collate_key);
161 /* By row number. */
162 if (!i) i = (a->eval.row - b->eval.row);
164 /* By column number. */
165 if (!i) i = (a->eval.col - b->eval.col);
167 return i;
170 static int
171 cb_order_sheet_col_row (void const *_a, void const *_b)
173 GnmEvalPos const *a = *(GnmEvalPos const **)_a;
174 GnmEvalPos const *b = *(GnmEvalPos const **)_b;
175 int i;
177 i = strcmp (a->sheet->name_unquoted_collate_key,
178 b->sheet->name_unquoted_collate_key);
180 /* By column number. */
181 if (!i) i = (a->eval.col - b->eval.col);
183 /* By row number. */
184 if (!i) i = (a->eval.row - b->eval.row);
186 return i;
189 static GnmValue *
190 search_collect_cells_cb (GnmCellIter const *iter, gpointer user)
192 GPtrArray *cells = user;
193 GnmEvalPos *ep = g_new (GnmEvalPos, 1);
195 g_ptr_array_add (cells, eval_pos_init_cell (ep, iter->cell));
197 return NULL;
201 * gnm_search_collect_cells:
202 * @sr: #GnmSearchReplace
204 * Collect a list of all cells subject to search.
205 * Returns: (element-type GnmEvalPos) (transfer full): the newly created array.
207 GPtrArray *
208 gnm_search_collect_cells (GnmSearchReplace *sr)
210 GPtrArray *cells;
212 switch (sr->scope) {
213 case GNM_SRS_WORKBOOK:
214 g_return_val_if_fail (sr->sheet != NULL, NULL);
215 cells = workbook_cells (sr->sheet->workbook, TRUE,
216 GNM_SHEET_VISIBILITY_HIDDEN);
217 break;
219 case GNM_SRS_SHEET:
220 cells = sheet_cell_positions (sr->sheet, TRUE);
221 break;
223 case GNM_SRS_RANGE:
225 GSList *range_list;
226 GnmEvalPos ep;
227 cells = g_ptr_array_new ();
228 range_list = global_range_list_parse (sr->sheet, sr->range_text);
229 global_range_list_foreach (range_list,
230 eval_pos_init_sheet (&ep, sr->sheet),
231 CELL_ITER_IGNORE_BLANK,
232 search_collect_cells_cb, cells);
233 range_list_destroy (range_list);
234 break;
237 default:
238 cells = NULL;
239 g_assert_not_reached ();
242 /* Sort our cells. */
243 g_ptr_array_sort (cells,
244 sr->by_row ? cb_order_sheet_row_col : cb_order_sheet_col_row);
246 return cells;
250 * gnm_search_collect_cells_free:
251 * @cells: (element-type GnmEvalPos) (transfer full):
253 void
254 gnm_search_collect_cells_free (GPtrArray *cells)
256 unsigned i;
258 for (i = 0; i < cells->len; i++)
259 g_free (g_ptr_array_index (cells, i));
260 g_ptr_array_free (cells, TRUE);
263 /* ------------------------------------------------------------------------- */
265 * gnm_search_filter_matching:
266 * @sr: The search spec.
267 * @cells: (element-type GnmEvalPos): Cell positions to filter, presumably a result of gnm_search_collect_cells.
269 * Returns: (element-type GnmSearchFilterResult) (transfer full): matches
272 GPtrArray *
273 gnm_search_filter_matching (GnmSearchReplace *sr, const GPtrArray *cells)
275 unsigned i;
276 GPtrArray *result = g_ptr_array_new ();
278 if (sr->is_number)
279 check_number (sr);
281 for (i = 0; i < cells->len; i++) {
282 GnmSearchReplaceCellResult cell_res;
283 GnmSearchReplaceValueResult value_res;
284 GnmSearchReplaceCommentResult comment_res;
285 gboolean found;
286 const GnmEvalPos *ep = g_ptr_array_index (cells, i);
288 found = gnm_search_replace_cell (sr, ep, FALSE, &cell_res);
289 g_free (cell_res.old_text);
290 if (cell_res.cell != NULL && found != sr->invert) {
291 GnmSearchFilterResult *item = g_new (GnmSearchFilterResult, 1);
292 item->ep = *ep;
293 item->locus = GNM_SRL_CONTENTS;
294 g_ptr_array_add (result, item);
297 found = gnm_search_replace_value (sr, ep, &value_res);
298 if (value_res.cell != NULL && gnm_cell_has_expr (value_res.cell) && found != sr->invert) {
299 GnmSearchFilterResult *item = g_new (GnmSearchFilterResult, 1);
300 item->ep = *ep;
301 item->locus = GNM_SRL_VALUE;
302 g_ptr_array_add (result, item);
305 found = gnm_search_replace_comment (sr, ep, FALSE, &comment_res);
306 if (comment_res.comment != NULL && found != sr->invert) {
307 GnmSearchFilterResult *item = g_new (GnmSearchFilterResult, 1);
308 item->ep = *ep;
309 item->locus = GNM_SRL_COMMENT;
310 g_ptr_array_add (result, item);
314 return result;
318 * gnm_search_filter_matching_free:
319 * @matches: (element-type GnmSearchFilterResult) (transfer full): matches
321 void
322 gnm_search_filter_matching_free (GPtrArray *matches)
324 unsigned i;
325 for (i = 0; i < matches->len; i++)
326 g_free (g_ptr_array_index (matches, i));
327 g_ptr_array_free (matches, TRUE);
330 /* ------------------------------------------------------------------------- */
332 gboolean
333 gnm_search_replace_comment (GnmSearchReplace *sr,
334 const GnmEvalPos *ep,
335 gboolean repl,
336 GnmSearchReplaceCommentResult *res)
338 gboolean found;
339 char *norm_text;
341 g_return_val_if_fail (res, FALSE);
343 res->comment = NULL;
344 res->old_text = NULL;
345 res->new_text = NULL;
347 g_return_val_if_fail (sr, FALSE);
349 if (!sr->search_comments) return FALSE;
350 if (sr->is_number) return FALSE;
352 res->comment = sheet_get_comment (ep->sheet, &ep->eval);
353 if (!res->comment) return FALSE;
355 res->old_text = cell_comment_text_get (res->comment);
357 norm_text = gnm_search_normalize (res->old_text);
359 if (repl) {
360 res->new_text = go_search_replace_string (GO_SEARCH_REPLACE (sr),
361 norm_text);
362 found = (res->new_text != NULL);
363 if (found) {
364 char *norm = gnm_search_normalize_result (res->new_text);
365 g_free (res->new_text);
366 res->new_text = norm;
368 } else
369 found = go_search_match_string (GO_SEARCH_REPLACE (sr),
370 norm_text);
372 g_free (norm_text);
374 return found;
377 /* ------------------------------------------------------------------------- */
379 gboolean
380 gnm_search_replace_cell (GnmSearchReplace *sr,
381 const GnmEvalPos *ep,
382 gboolean repl,
383 GnmSearchReplaceCellResult *res)
385 GnmCell *cell;
386 GnmValue *v;
387 gboolean is_expr, is_value, is_string, is_other;
388 gboolean found = FALSE;
390 g_return_val_if_fail (res, FALSE);
392 res->cell = NULL;
393 res->old_text = NULL;
394 res->new_text = NULL;
396 g_return_val_if_fail (sr, FALSE);
398 cell = res->cell = sheet_cell_get (ep->sheet, ep->eval.col, ep->eval.row);
399 if (!cell) return FALSE;
401 v = cell->value;
403 is_expr = gnm_cell_has_expr (cell);
404 is_value = !is_expr && !gnm_cell_is_empty (cell) && v;
405 is_string = is_value && (VALUE_IS_STRING (v));
406 is_other = is_value && !is_string;
408 if (sr->is_number) {
409 if (!is_value || !VALUE_IS_NUMBER (v))
410 return FALSE;
411 return gnm_search_match_value (sr, v);
414 if ((is_expr && sr->search_expressions) ||
415 (is_string && sr->search_strings) ||
416 (is_other && sr->search_other_values)) {
417 char *actual_src;
418 gboolean initial_quote;
420 res->old_text = gnm_cell_get_entered_text (cell);
421 initial_quote = (is_string && res->old_text[0] == '\'');
423 actual_src = gnm_search_normalize (res->old_text + initial_quote);
425 if (repl) {
426 res->new_text = go_search_replace_string (GO_SEARCH_REPLACE (sr),
427 actual_src);
428 if (res->new_text) {
429 char *norm = gnm_search_normalize_result (res->new_text);
430 g_free (res->new_text);
431 res->new_text = norm;
433 if (sr->replace_keep_strings && is_string) {
435 * The initial quote was not part of the s-a-r,
436 * so tack it back on.
438 char *tmp = g_new (char, strlen (res->new_text) + 2);
439 tmp[0] = '\'';
440 strcpy (tmp + 1, res->new_text);
441 g_free (res->new_text);
442 res->new_text = tmp;
444 found = TRUE;
446 } else
447 found = go_search_match_string (GO_SEARCH_REPLACE (sr), actual_src);
449 g_free (actual_src);
452 return found;
455 /* ------------------------------------------------------------------------- */
457 static gboolean
458 gnm_search_replace_value (GnmSearchReplace *sr,
459 const GnmEvalPos *ep,
460 GnmSearchReplaceValueResult *res)
462 GnmCell *cell;
464 g_return_val_if_fail (res, FALSE);
466 res->cell = NULL;
468 g_return_val_if_fail (sr, FALSE);
470 if (!sr->search_expression_results)
471 return FALSE;
473 cell = res->cell = sheet_cell_get (ep->sheet, ep->eval.col, ep->eval.row);
474 if (!cell || !gnm_cell_has_expr (cell) || !cell->value)
475 return FALSE;
476 else if (sr->is_number) {
477 return gnm_search_match_value (sr, cell->value);
478 } else {
479 char *val = gnm_search_normalize (value_peek_string (cell->value));
480 gboolean res = go_search_match_string (GO_SEARCH_REPLACE (sr), val);
481 g_free (val);
482 return res;
486 /* ------------------------------------------------------------------------- */
488 void
489 gnm_search_replace_query_fail (GnmSearchReplace *sr,
490 const GnmSearchReplaceCellResult *res)
492 if (!sr->query_func)
493 return;
495 sr->query_func (GNM_SRQ_FAIL, sr,
496 res->cell, res->old_text, res->new_text);
500 gnm_search_replace_query_cell (GnmSearchReplace *sr,
501 const GnmSearchReplaceCellResult *res)
503 if (!sr->query || !sr->query_func)
504 return GTK_RESPONSE_YES;
506 return sr->query_func (GNM_SRQ_QUERY, sr,
507 res->cell, res->old_text, res->new_text);
512 gnm_search_replace_query_comment (GnmSearchReplace *sr,
513 const GnmEvalPos *ep,
514 const GnmSearchReplaceCommentResult *res)
516 if (!sr->query || !sr->query_func)
517 return GTK_RESPONSE_YES;
519 return sr->query_func (GNM_SRQ_QUERY_COMMENT, sr,
520 ep->sheet, &ep->eval,
521 res->old_text, res->new_text);
524 /* ------------------------------------------------------------------------- */
526 GType
527 gnm_search_replace_scope_get_type (void)
529 static GType etype = 0;
530 if (etype == 0) {
531 static const GEnumValue values[] = {
532 { GNM_SRS_WORKBOOK, "GNM_SRS_WORKBOOK", "workbook" },
533 { GNM_SRS_SHEET, "GNM_SRS_SHEET", "sheet" },
534 { GNM_SRS_RANGE, "GNM_SRS_RANGE", "range" },
535 { 0, NULL, NULL }
537 etype = g_enum_register_static ("GnmSearchReplaceScope", values);
539 return etype;
542 /* ------------------------------------------------------------------------- */
544 static void
545 gnm_search_replace_init (GObject *obj)
549 /* ------------------------------------------------------------------------- */
551 static void
552 gnm_search_replace_get_property (GObject *object,
553 guint property_id,
554 GValue *value,
555 GParamSpec *pspec)
557 GnmSearchReplace *sr = (GnmSearchReplace *)object;
559 switch (property_id) {
560 case PROP_IS_NUMBER:
561 g_value_set_boolean (value, sr->is_number);
562 break;
563 case PROP_SEARCH_STRINGS:
564 g_value_set_boolean (value, sr->search_strings);
565 break;
566 case PROP_SEARCH_OTHER_VALUES:
567 g_value_set_boolean (value, sr->search_other_values);
568 break;
569 case PROP_SEARCH_EXPRESSIONS:
570 g_value_set_boolean (value, sr->search_expressions);
571 break;
572 case PROP_SEARCH_EXPRESSION_RESULTS:
573 g_value_set_boolean (value, sr->search_expression_results);
574 break;
575 case PROP_SEARCH_COMMENTS:
576 g_value_set_boolean (value, sr->search_comments);
577 break;
578 case PROP_SEARCH_SCRIPTS:
579 g_value_set_boolean (value, sr->search_scripts);
580 break;
581 case PROP_INVERT:
582 g_value_set_boolean (value, sr->invert);
583 break;
584 case PROP_BY_ROW:
585 g_value_set_boolean (value, sr->by_row);
586 break;
587 case PROP_QUERY:
588 g_value_set_boolean (value, sr->query);
589 break;
590 case PROP_REPLACE_KEEP_STRINGS:
591 g_value_set_boolean (value, sr->replace_keep_strings);
592 break;
593 case PROP_SHEET:
594 g_value_set_object (value, sr->sheet);
595 break;
596 case PROP_SCOPE:
597 g_value_set_enum (value, sr->scope);
598 break;
599 case PROP_RANGE_TEXT:
600 g_value_set_string (value, sr->range_text);
601 break;
602 default:
603 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
604 break;
608 /* ------------------------------------------------------------------------- */
610 static void
611 gnm_search_replace_set_sheet (GnmSearchReplace *sr, Sheet *sheet)
613 if (sheet)
614 g_object_ref (sheet);
615 if (sr->sheet)
616 g_object_unref (sr->sheet);
617 sr->sheet = sheet;
620 static void
621 gnm_search_replace_set_range_text (GnmSearchReplace *sr, char const *text)
623 char *text_copy = g_strdup (text);
624 g_free (sr->range_text);
625 sr->range_text = text_copy;
628 static void
629 gnm_search_replace_set_property (GObject *object,
630 guint property_id,
631 GValue const *value,
632 GParamSpec *pspec)
634 GnmSearchReplace *sr = (GnmSearchReplace *)object;
636 switch (property_id) {
637 case PROP_IS_NUMBER:
638 sr->is_number = g_value_get_boolean (value);
639 break;
640 case PROP_SEARCH_STRINGS:
641 sr->search_strings = g_value_get_boolean (value);
642 break;
643 case PROP_SEARCH_OTHER_VALUES:
644 sr->search_other_values = g_value_get_boolean (value);
645 break;
646 case PROP_SEARCH_EXPRESSIONS:
647 sr->search_expressions = g_value_get_boolean (value);
648 break;
649 case PROP_SEARCH_EXPRESSION_RESULTS:
650 sr->search_expression_results = g_value_get_boolean (value);
651 break;
652 case PROP_SEARCH_COMMENTS:
653 sr->search_comments = g_value_get_boolean (value);
654 break;
655 case PROP_SEARCH_SCRIPTS:
656 sr->search_scripts = g_value_get_boolean (value);
657 break;
658 case PROP_INVERT:
659 sr->invert = g_value_get_boolean (value);
660 break;
661 case PROP_BY_ROW:
662 sr->by_row = g_value_get_boolean (value);
663 break;
664 case PROP_QUERY:
665 sr->query = g_value_get_boolean (value);
666 break;
667 case PROP_REPLACE_KEEP_STRINGS:
668 sr->replace_keep_strings = g_value_get_boolean (value);
669 break;
670 case PROP_SHEET:
671 gnm_search_replace_set_sheet (sr, g_value_get_object (value));
672 break;
673 case PROP_SCOPE:
674 sr->scope = g_value_get_enum (value);
675 break;
676 case PROP_RANGE_TEXT:
677 gnm_search_replace_set_range_text (sr, g_value_get_string (value));
678 break;
679 default:
680 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
681 break;
685 /* ------------------------------------------------------------------------- */
687 static void
688 gnm_search_replace_finalize (GObject *obj)
690 GnmSearchReplace *sr = (GnmSearchReplace *)obj;
692 gnm_search_replace_set_sheet (sr, NULL);
693 g_free (sr->range_text);
695 G_OBJECT_CLASS (parent_class)->finalize (obj);
698 /* ------------------------------------------------------------------------- */
700 static void
701 gnm_search_replace_class_init (GObjectClass *gobject_class)
703 parent_class = g_type_class_peek_parent (gobject_class);
705 gobject_class->finalize = gnm_search_replace_finalize;
706 gobject_class->get_property = gnm_search_replace_get_property;
707 gobject_class->set_property = gnm_search_replace_set_property;
709 g_object_class_install_property
710 (gobject_class,
711 PROP_IS_NUMBER,
712 g_param_spec_boolean ("is-number",
713 P_("Is Number"),
714 P_("Search for Specific Number Regardless of Formatting?"),
715 FALSE,
716 GSF_PARAM_STATIC |
717 G_PARAM_READWRITE));
718 g_object_class_install_property
719 (gobject_class,
720 PROP_SEARCH_STRINGS,
721 g_param_spec_boolean ("search-strings",
722 P_("Search Strings"),
723 P_("Should strings be searched?"),
724 FALSE,
725 GSF_PARAM_STATIC |
726 G_PARAM_READWRITE));
727 g_object_class_install_property
728 (gobject_class,
729 PROP_SEARCH_OTHER_VALUES,
730 g_param_spec_boolean ("search-other-values",
731 P_("Search Other Values"),
732 P_("Should non-strings be searched?"),
733 FALSE,
734 GSF_PARAM_STATIC |
735 G_PARAM_READWRITE));
736 g_object_class_install_property
737 (gobject_class,
738 PROP_SEARCH_EXPRESSIONS,
739 g_param_spec_boolean ("search-expressions",
740 P_("Search Expressions"),
741 P_("Should expressions be searched?"),
742 FALSE,
743 GSF_PARAM_STATIC |
744 G_PARAM_READWRITE));
745 g_object_class_install_property
746 (gobject_class,
747 PROP_SEARCH_EXPRESSION_RESULTS,
748 g_param_spec_boolean ("search-expression-results",
749 P_("Search Expression Results"),
750 P_("Should the results of expressions be searched?"),
751 FALSE,
752 GSF_PARAM_STATIC |
753 G_PARAM_READWRITE));
754 g_object_class_install_property
755 (gobject_class,
756 PROP_SEARCH_COMMENTS,
757 g_param_spec_boolean ("search-comments",
758 P_("Search Comments"),
759 P_("Should cell comments be searched?"),
760 FALSE,
761 GSF_PARAM_STATIC |
762 G_PARAM_READWRITE));
763 g_object_class_install_property
764 (gobject_class,
765 PROP_SEARCH_SCRIPTS,
766 g_param_spec_boolean ("search-scripts",
767 P_("Search Scripts"),
768 P_("Should scrips (workbook, and worksheet) be searched?"),
769 FALSE,
770 GSF_PARAM_STATIC |
771 G_PARAM_READWRITE));
772 g_object_class_install_property
773 (gobject_class,
774 PROP_INVERT,
775 g_param_spec_boolean ("invert",
776 P_("Invert"),
777 P_("Collect non-matching items"),
778 FALSE,
779 GSF_PARAM_STATIC |
780 G_PARAM_READWRITE));
781 g_object_class_install_property
782 (gobject_class,
783 PROP_BY_ROW,
784 g_param_spec_boolean ("by-row",
785 P_("By Row"),
786 P_("Is the search order by row?"),
787 FALSE,
788 GSF_PARAM_STATIC |
789 G_PARAM_READWRITE));
790 g_object_class_install_property
791 (gobject_class,
792 PROP_QUERY,
793 g_param_spec_boolean ("query",
794 P_("Query"),
795 P_("Should we query for each replacement?"),
796 FALSE,
797 GSF_PARAM_STATIC |
798 G_PARAM_READWRITE));
799 g_object_class_install_property
800 (gobject_class,
801 PROP_REPLACE_KEEP_STRINGS,
802 g_param_spec_boolean ("replace-keep-strings",
803 P_("Keep Strings"),
804 P_("Should replacement keep strings as strings?"),
805 FALSE,
806 GSF_PARAM_STATIC |
807 G_PARAM_READWRITE));
808 g_object_class_install_property
809 (gobject_class,
810 PROP_SHEET,
811 g_param_spec_object ("sheet",
812 P_("Sheet"),
813 P_("The sheet in which to search."),
814 GNM_SHEET_TYPE,
815 GSF_PARAM_STATIC |
816 G_PARAM_READWRITE));
817 g_object_class_install_property
818 (gobject_class,
819 PROP_SCOPE,
820 g_param_spec_enum ("scope",
821 P_("Scope"),
822 P_("Where to search."),
823 GNM_SEARCH_REPLACE_SCOPE_TYPE,
824 GNM_SRS_SHEET,
825 GSF_PARAM_STATIC |
826 G_PARAM_READWRITE));
827 g_object_class_install_property
828 (gobject_class,
829 PROP_RANGE_TEXT,
830 g_param_spec_string ("range-text",
831 P_("Range as Text"),
832 P_("The range in which to search."),
833 NULL,
834 GSF_PARAM_STATIC |
835 G_PARAM_READWRITE));
838 /* ------------------------------------------------------------------------- */
840 GSF_CLASS (GnmSearchReplace, gnm_search_replace,
841 gnm_search_replace_class_init, gnm_search_replace_init, GO_TYPE_SEARCH_REPLACE)