1 /*
2 * search.c: Search-and-replace for Gnumeric.
3 *
4 * Copyright (C) 2001-2009 Morten Welinder (terra@gnome.org)
5 */
6
7 #include <gnumeric-config.h>
8 #include <gnm-i18n.h>
9 #include <gnumeric.h>
10 #include <search.h>
11
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>
22
23 #include <string.h>
24 #include <stdlib.h>
25
26 static GObjectClass *parent_class;
27
28 typedef struct {
29 GOSearchReplaceClass base_class;
30 } GnmSearchReplaceClass;
31
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
48 };
49
50 /* ------------------------------------------------------------------------- */
51
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);
59
60 /* ------------------------------------------------------------------------- */
61
62 char *
gnm_search_normalize(const char * txt)63 gnm_search_normalize (const char *txt)
64 {
65 return g_utf8_normalize (txt, -1, G_NORMALIZE_NFD);
66 }
67
68 static char *
gnm_search_normalize_result(const char * txt)69 gnm_search_normalize_result (const char *txt)
70 {
71 return g_utf8_normalize (txt, -1, G_NORMALIZE_NFC);
72 }
73
74 /* ------------------------------------------------------------------------- */
75
76 static gboolean
check_number(GnmSearchReplace * sr)77 check_number (GnmSearchReplace *sr)
78 {
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);
82
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);
91 }
92 value_release (v);
93 return TRUE;
94 } else {
95 sr->low_number = sr->high_number = gnm_nan;
96 return FALSE;
97 }
98 }
99
100 static gboolean
gnm_search_match_value(GnmSearchReplace const * sr,GnmValue const * val)101 gnm_search_match_value (GnmSearchReplace const *sr, GnmValue const *val)
102 {
103 gnm_float f;
104 if (!VALUE_IS_NUMBER (val))
105 return FALSE;
106 f = value_get_as_float (val);
107
108 return (sr->low_number <= f && f <= sr->high_number);
109 }
110
111
112 char *
gnm_search_replace_verify(GnmSearchReplace * sr,gboolean repl)113 gnm_search_replace_verify (GnmSearchReplace *sr, gboolean repl)
114 {
115 GError *error = NULL;
116 GOSearchReplace *gosr = (GOSearchReplace *)sr;
117 g_return_val_if_fail (sr != NULL, NULL);
118
119 if (!go_search_replace_verify (gosr, repl, &error)) {
120 char *msg = g_strdup (error->message);
121 g_error_free (error);
122 return msg;
123 }
124
125 if (sr->is_number && gosr->is_regexp)
126 return g_strdup (_("Searching for regular expressions and numbers are mutually exclusive."));
127
128 if (sr->is_number) {
129 if (!check_number (sr))
130 return g_strdup (_("The search text must be a number."));
131 }
132
133 if (sr->scope == GNM_SRS_RANGE) {
134 GSList *range_list;
135
136 if (!sr->range_text || sr->range_text[0] == 0)
137 return g_strdup (_("You must specify a range to search."));
138
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);
143 }
144
145 return NULL;
146 }
147
148 /* ------------------------------------------------------------------------- */
149
150 static int
cb_order_sheet_row_col(void const * _a,void const * _b)151 cb_order_sheet_row_col (void const *_a, void const *_b)
152 {
153 GnmEvalPos const *a = *(GnmEvalPos const **)_a;
154 GnmEvalPos const *b = *(GnmEvalPos const **)_b;
155 int i;
156
157 i = strcmp (a->sheet->name_unquoted_collate_key,
158 b->sheet->name_unquoted_collate_key);
159
160 /* By row number. */
161 if (!i) i = (a->eval.row - b->eval.row);
162
163 /* By column number. */
164 if (!i) i = (a->eval.col - b->eval.col);
165
166 return i;
167 }
168
169 static int
cb_order_sheet_col_row(void const * _a,void const * _b)170 cb_order_sheet_col_row (void const *_a, void const *_b)
171 {
172 GnmEvalPos const *a = *(GnmEvalPos const **)_a;
173 GnmEvalPos const *b = *(GnmEvalPos const **)_b;
174 int i;
175
176 i = strcmp (a->sheet->name_unquoted_collate_key,
177 b->sheet->name_unquoted_collate_key);
178
179 /* By column number. */
180 if (!i) i = (a->eval.col - b->eval.col);
181
182 /* By row number. */
183 if (!i) i = (a->eval.row - b->eval.row);
184
185 return i;
186 }
187
188 static GnmValue *
search_collect_cells_cb(GnmCellIter const * iter,gpointer user)189 search_collect_cells_cb (GnmCellIter const *iter, gpointer user)
190 {
191 GPtrArray *cells = user;
192 GnmEvalPos *ep = g_new (GnmEvalPos, 1);
193
194 g_ptr_array_add (cells, eval_pos_init_cell (ep, iter->cell));
195
196 return NULL;
197 }
198
199 /**
200 * gnm_search_collect_cells:
201 * @sr: #GnmSearchReplace
202 *
203 * Collect a list of all cells subject to search.
204 * Returns: (element-type GnmEvalPos) (transfer full): the newly created array.
205 **/
206 GPtrArray *
gnm_search_collect_cells(GnmSearchReplace * sr)207 gnm_search_collect_cells (GnmSearchReplace *sr)
208 {
209 GPtrArray *cells;
210
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;
217
218 case GNM_SRS_SHEET:
219 cells = sheet_cell_positions (sr->sheet, TRUE);
220 break;
221
222 case GNM_SRS_RANGE:
223 {
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;
234 }
235
236 default:
237 cells = NULL;
238 g_assert_not_reached ();
239 }
240
241 /* Sort our cells. */
242 g_ptr_array_sort (cells,
243 sr->by_row ? cb_order_sheet_row_col : cb_order_sheet_col_row);
244
245 return cells;
246 }
247
248 /**
249 * gnm_search_collect_cells_free:
250 * @cells: (element-type GnmEvalPos) (transfer full):
251 */
252 void
gnm_search_collect_cells_free(GPtrArray * cells)253 gnm_search_collect_cells_free (GPtrArray *cells)
254 {
255 unsigned i;
256
257 for (i = 0; i < cells->len; i++)
258 g_free (g_ptr_array_index (cells, i));
259 g_ptr_array_free (cells, TRUE);
260 }
261
262 /* ------------------------------------------------------------------------- */
263 /**
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.
267 *
268 * Returns: (element-type GnmSearchFilterResult) (transfer full): matches
269 */
270
271 GPtrArray *
gnm_search_filter_matching(GnmSearchReplace * sr,const GPtrArray * cells)272 gnm_search_filter_matching (GnmSearchReplace *sr, const GPtrArray *cells)
273 {
274 unsigned i;
275 GPtrArray *result = g_ptr_array_new ();
276
277 if (sr->is_number)
278 check_number (sr);
279
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);
286
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);
294 }
295
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);
302 }
303
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);
310 }
311 }
312
313 return result;
314 }
315
316 /**
317 * gnm_search_filter_matching_free:
318 * @matches: (element-type GnmSearchFilterResult) (transfer full): matches
319 */
320 void
gnm_search_filter_matching_free(GPtrArray * matches)321 gnm_search_filter_matching_free (GPtrArray *matches)
322 {
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);
327 }
328
329 /* ------------------------------------------------------------------------- */
330
331 gboolean
gnm_search_replace_comment(GnmSearchReplace * sr,const GnmEvalPos * ep,gboolean repl,GnmSearchReplaceCommentResult * res)332 gnm_search_replace_comment (GnmSearchReplace *sr,
333 const GnmEvalPos *ep,
334 gboolean repl,
335 GnmSearchReplaceCommentResult *res)
336 {
337 gboolean found;
338 char *norm_text;
339
340 g_return_val_if_fail (res, FALSE);
341
342 res->comment = NULL;
343 res->old_text = NULL;
344 res->new_text = NULL;
345
346 g_return_val_if_fail (sr, FALSE);
347
348 if (!sr->search_comments) return FALSE;
349 if (sr->is_number) return FALSE;
350
351 res->comment = sheet_get_comment (ep->sheet, &ep->eval);
352 if (!res->comment) return FALSE;
353
354 res->old_text = cell_comment_text_get (res->comment);
355
356 norm_text = gnm_search_normalize (res->old_text);
357
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;
366 }
367 } else
368 found = go_search_match_string (GO_SEARCH_REPLACE (sr),
369 norm_text);
370
371 g_free (norm_text);
372
373 return found;
374 }
375
376 /* ------------------------------------------------------------------------- */
377
378 gboolean
gnm_search_replace_cell(GnmSearchReplace * sr,const GnmEvalPos * ep,gboolean repl,GnmSearchReplaceCellResult * res)379 gnm_search_replace_cell (GnmSearchReplace *sr,
380 const GnmEvalPos *ep,
381 gboolean repl,
382 GnmSearchReplaceCellResult *res)
383 {
384 GnmCell *cell;
385 GnmValue *v;
386 gboolean is_expr, is_value, is_string, is_other;
387 gboolean found = FALSE;
388
389 g_return_val_if_fail (res, FALSE);
390
391 res->cell = NULL;
392 res->old_text = NULL;
393 res->new_text = NULL;
394
395 g_return_val_if_fail (sr, FALSE);
396
397 cell = res->cell = sheet_cell_get (ep->sheet, ep->eval.col, ep->eval.row);
398 if (!cell) return FALSE;
399
400 v = cell->value;
401
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;
406
407 if (sr->is_number) {
408 if (!is_value || !VALUE_IS_NUMBER (v))
409 return FALSE;
410 return gnm_search_match_value (sr, v);
411 }
412
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;
418
419 res->old_text = gnm_cell_get_entered_text (cell);
420 initial_quote = (is_string && res->old_text[0] == '\'');
421
422 actual_src = gnm_search_normalize (res->old_text + initial_quote);
423
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;
431
432 if (sr->replace_keep_strings && is_string) {
433 /*
434 * The initial quote was not part of the s-a-r,
435 * so tack it back on.
436 */
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;
442 }
443 found = TRUE;
444 }
445 } else
446 found = go_search_match_string (GO_SEARCH_REPLACE (sr), actual_src);
447
448 g_free (actual_src);
449 }
450
451 return found;
452 }
453
454 /* ------------------------------------------------------------------------- */
455
456 static gboolean
gnm_search_replace_value(GnmSearchReplace * sr,const GnmEvalPos * ep,GnmSearchReplaceValueResult * res)457 gnm_search_replace_value (GnmSearchReplace *sr,
458 const GnmEvalPos *ep,
459 GnmSearchReplaceValueResult *res)
460 {
461 GnmCell *cell;
462
463 g_return_val_if_fail (res, FALSE);
464
465 res->cell = NULL;
466
467 g_return_val_if_fail (sr, FALSE);
468
469 if (!sr->search_expression_results)
470 return FALSE;
471
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;
482 }
483 }
484
485 /* ------------------------------------------------------------------------- */
486
487 void
gnm_search_replace_query_fail(GnmSearchReplace * sr,const GnmSearchReplaceCellResult * res)488 gnm_search_replace_query_fail (GnmSearchReplace *sr,
489 const GnmSearchReplaceCellResult *res)
490 {
491 if (!sr->query_func)
492 return;
493
494 sr->query_func (GNM_SRQ_FAIL, sr,
495 res->cell, res->old_text, res->new_text);
496 }
497
498 int
gnm_search_replace_query_cell(GnmSearchReplace * sr,const GnmSearchReplaceCellResult * res)499 gnm_search_replace_query_cell (GnmSearchReplace *sr,
500 const GnmSearchReplaceCellResult *res)
501 {
502 if (!sr->query || !sr->query_func)
503 return GTK_RESPONSE_YES;
504
505 return sr->query_func (GNM_SRQ_QUERY, sr,
506 res->cell, res->old_text, res->new_text);
507 }
508
509
510 int
gnm_search_replace_query_comment(GnmSearchReplace * sr,const GnmEvalPos * ep,const GnmSearchReplaceCommentResult * res)511 gnm_search_replace_query_comment (GnmSearchReplace *sr,
512 const GnmEvalPos *ep,
513 const GnmSearchReplaceCommentResult *res)
514 {
515 if (!sr->query || !sr->query_func)
516 return GTK_RESPONSE_YES;
517
518 return sr->query_func (GNM_SRQ_QUERY_COMMENT, sr,
519 ep->sheet, &ep->eval,
520 res->old_text, res->new_text);
521 }
522
523 /* ------------------------------------------------------------------------- */
524
525 GType
gnm_search_replace_scope_get_type(void)526 gnm_search_replace_scope_get_type (void)
527 {
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 }
535 };
536 etype = g_enum_register_static ("GnmSearchReplaceScope", values);
537 }
538 return etype;
539 }
540
541 /* ------------------------------------------------------------------------- */
542
543 static void
gnm_search_replace_init(GObject * obj)544 gnm_search_replace_init (GObject *obj)
545 {
546 }
547
548 /* ------------------------------------------------------------------------- */
549
550 static void
gnm_search_replace_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)551 gnm_search_replace_get_property (GObject *object,
552 guint property_id,
553 GValue *value,
554 GParamSpec *pspec)
555 {
556 GnmSearchReplace *sr = (GnmSearchReplace *)object;
557
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;
604 }
605 }
606
607 /* ------------------------------------------------------------------------- */
608
609 static void
gnm_search_replace_set_sheet(GnmSearchReplace * sr,Sheet * sheet)610 gnm_search_replace_set_sheet (GnmSearchReplace *sr, Sheet *sheet)
611 {
612 if (sheet)
613 g_object_ref (sheet);
614 if (sr->sheet)
615 g_object_unref (sr->sheet);
616 sr->sheet = sheet;
617 }
618
619 static void
gnm_search_replace_set_range_text(GnmSearchReplace * sr,char const * text)620 gnm_search_replace_set_range_text (GnmSearchReplace *sr, char const *text)
621 {
622 char *text_copy = g_strdup (text);
623 g_free (sr->range_text);
624 sr->range_text = text_copy;
625 }
626
627 static void
gnm_search_replace_set_property(GObject * object,guint property_id,GValue const * value,GParamSpec * pspec)628 gnm_search_replace_set_property (GObject *object,
629 guint property_id,
630 GValue const *value,
631 GParamSpec *pspec)
632 {
633 GnmSearchReplace *sr = (GnmSearchReplace *)object;
634
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;
681 }
682 }
683
684 /* ------------------------------------------------------------------------- */
685
686 static void
gnm_search_replace_finalize(GObject * obj)687 gnm_search_replace_finalize (GObject *obj)
688 {
689 GnmSearchReplace *sr = (GnmSearchReplace *)obj;
690
691 gnm_search_replace_set_sheet (sr, NULL);
692 g_free (sr->range_text);
693
694 G_OBJECT_CLASS (parent_class)->finalize (obj);
695 }
696
697 /* ------------------------------------------------------------------------- */
698
699 static void
gnm_search_replace_class_init(GObjectClass * gobject_class)700 gnm_search_replace_class_init (GObjectClass *gobject_class)
701 {
702 parent_class = g_type_class_peek_parent (gobject_class);
703
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;
707
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));
835 }
836
837 /* ------------------------------------------------------------------------- */
838
839 GSF_CLASS (GnmSearchReplace, gnm_search_replace,
840 gnm_search_replace_class_init, gnm_search_replace_init, GO_TYPE_SEARCH_REPLACE)
841