1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * dialog-define-names.c: Edit named regions.
4 *
5 * Author:
6 * Jody Goldberg <jody@gnome.org>
7 * Michael Meeks <michael@ximian.com>
8 * Chema Celorio <chema@celorio.com>
9 * Andreas J. Guelzow <aguelzow@pyrshep.ca>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses/>.
23 */
24 #include <gnumeric-config.h>
25 #include <glib/gi18n-lib.h>
26 #include <gnumeric.h>
27 #include <dialogs/dialogs.h>
28 #include <dialogs/help.h>
29
30 #include <expr.h>
31 #include <expr-name.h>
32 #include <selection.h>
33 #include <sheet.h>
34 #include <sheet-view.h>
35 #include <workbook.h>
36 #include <workbook-control.h>
37 #include <wbc-gtk.h>
38 #include <workbook-view.h>
39 #include <gui-util.h>
40 #include <parse-util.h>
41 #include <commands.h>
42 #include <widgets/gnm-expr-entry.h>
43 #include <widgets/gnm-cell-renderer-expr-entry.h>
44 #include <widgets/gnm-cell-renderer-toggle.h>
45
46 #include <string.h>
47
48 #define DEFINE_NAMES_KEY "define-names-dialog"
49 #define PASTE_NAMES_KEY "paste-names-dialog"
50
51 typedef struct {
52 GtkBuilder *gui;
53 GtkWidget *dialog;
54 GtkWidget *treeview;
55 GtkTreeStore *model;
56 GtkTreeModel *model_f;
57
58 GtkWidget *close_button;
59 GtkWidget *paste_button;
60 GtkWidget *search_entry;
61
62 Sheet *sheet;
63 SheetView *sv;
64 Workbook *wb;
65 WBCGtk *wbcg;
66 GnmParsePos pp;
67
68 GdkPixbuf *image_add;
69 GdkPixbuf *image_delete;
70 GdkPixbuf *image_lock;
71 GdkPixbuf *image_up;
72 GdkPixbuf *image_down;
73 GdkPixbuf *image_paste;
74
75 gboolean is_paste_dialog;
76 gboolean has_pasted;
77 } NameGuruState;
78
79 enum {
80 ITEM_NAME,
81 ITEM_NAME_POINTER,
82 ITEM_CONTENT,
83 ITEM_TYPE,
84 ITEM_CONTENT_IS_EDITABLE,
85 ITEM_NAME_IS_EDITABLE,
86 ITEM_UPDOWN_IMAGE,
87 ITEM_ADDDELETE_IMAGE,
88 ITEM_UPDOWN_ACTIVE,
89 ITEM_ADDDELETE_ACTIVE,
90 ITEM_PASTABLE,
91 ITEM_PASTE_IMAGE,
92 ITEM_VISIBLE,
93 NUM_COLUMNS
94 };
95
96 typedef enum {
97 item_type_workbook = 0,
98 item_type_main_sheet,
99 item_type_other_sheet,
100 item_type_locked_name,
101 item_type_available_wb_name,
102 item_type_available_sheet_name,
103 item_type_foreign_name,
104 item_type_new_unsaved_wb_name,
105 item_type_new_unsaved_sheet_name,
106 } item_type_t;
107
108
109 /**
110 * name_guru_translate_pathstring_to_iter:
111 * @state:
112 * @path_string: in the filter_model
113 * @iter: in the base model
114 *
115 **/
116
117 static gboolean
name_guru_translate_pathstring_to_iter(NameGuruState * state,GtkTreeIter * iter,gchar const * path_string)118 name_guru_translate_pathstring_to_iter (NameGuruState *state,
119 GtkTreeIter *iter,
120 gchar const *path_string)
121 {
122 GtkTreeIter iter_f;
123
124 if (!gtk_tree_model_get_iter_from_string
125 (state->model_f, &iter_f, path_string))
126 return FALSE;
127
128 gtk_tree_model_filter_convert_iter_to_child_iter
129 (GTK_TREE_MODEL_FILTER (state->model_f), iter, &iter_f);
130 return TRUE;
131 }
132
133
134
135
136 /**
137 * name_guru_expand_at_iter:
138 * @state:
139 * @iter:
140 *
141 * expand the treeview at the given iter.
142 *
143 **/
144 static void
name_guru_expand_at_iter(NameGuruState * state,GtkTreeIter * iter)145 name_guru_expand_at_iter (NameGuruState *state, GtkTreeIter *iter)
146 {
147 GtkTreePath *path;
148
149 path = gtk_tree_model_get_path
150 (GTK_TREE_MODEL (state->model), iter);
151 gtk_tree_view_expand_to_path
152 (GTK_TREE_VIEW (state->treeview), path);
153 gtk_tree_path_free (path);
154
155 }
156
157 /**
158 * name_guru_warned_if_used:
159 * @state:
160 * @nexpr: expression to be deleted
161 *
162 * If the expression that is about to be deleted is being used,
163 * warn the user about it. Ask if we should proceed or not
164 *
165 * Returns: %TRUE if users confirms deletion, %FALSE otherwise
166 **/
167
168 static gboolean
name_guru_warn(NameGuruState * state,GnmNamedExpr * nexpr)169 name_guru_warn (NameGuruState *state,
170 GnmNamedExpr *nexpr)
171 {
172 return (!expr_name_in_use (nexpr) ||
173 go_gtk_query_yes_no
174 (GTK_WINDOW (state->dialog), FALSE,
175 "The defined name '%s' is in use. "
176 "Do you really want to delete it?",
177 expr_name_name (nexpr)));
178 }
179
180 static gboolean
cb_name_guru_show_all(G_GNUC_UNUSED GtkTreeModel * model,G_GNUC_UNUSED GtkTreePath * path,GtkTreeIter * iter,gpointer data)181 cb_name_guru_show_all (G_GNUC_UNUSED GtkTreeModel *model,
182 G_GNUC_UNUSED GtkTreePath *path,
183 GtkTreeIter *iter, gpointer data)
184 {
185 NameGuruState *state = data;
186 gtk_tree_store_set (state->model, iter,
187 ITEM_VISIBLE, TRUE,
188 -1);
189 return FALSE;
190 }
191
192 static void
name_guru_erase_search_entry(GtkEntry * entry,G_GNUC_UNUSED GtkEntryIconPosition icon_pos,G_GNUC_UNUSED GdkEvent * event,gpointer data)193 name_guru_erase_search_entry (GtkEntry *entry,
194 G_GNUC_UNUSED GtkEntryIconPosition icon_pos,
195 G_GNUC_UNUSED GdkEvent *event,
196 gpointer data)
197 {
198 NameGuruState *state = data;
199 gtk_entry_set_text (entry, "");
200 gtk_tree_model_foreach (GTK_TREE_MODEL (state->model),
201 cb_name_guru_show_all, state);
202 }
203
204 static gboolean
cb_name_guru_search(GtkTreeModel * model,G_GNUC_UNUSED GtkTreePath * path,GtkTreeIter * iter,gpointer data)205 cb_name_guru_search (GtkTreeModel *model,
206 G_GNUC_UNUSED GtkTreePath *path,
207 GtkTreeIter *iter, gpointer data)
208 {
209 char const *text = data;
210 gchar *name;
211 gboolean visible = TRUE, was_visible;
212 item_type_t type;
213
214 gtk_tree_model_get (model, iter,
215 ITEM_TYPE, &type,
216 ITEM_NAME, &name,
217 ITEM_VISIBLE, &was_visible,
218 -1);
219
220 if (type != item_type_workbook &&
221 type != item_type_main_sheet &&
222 type != item_type_other_sheet) {
223 gchar *name_n, *name_cf, *text_n, *text_cf;
224
225 text_n = g_utf8_normalize (text, -1, G_NORMALIZE_ALL);
226 text_cf = g_utf8_casefold(text_n, -1);
227 name_n = g_utf8_normalize (name, -1, G_NORMALIZE_ALL);
228 name_cf = g_utf8_casefold(name_n, -1);
229 visible = (NULL != g_strstr_len (name_cf, -1, text_cf));
230 g_free (text_n);
231 g_free (text_cf);
232 g_free (name_n);
233 g_free (name_cf);
234 }
235
236 if (visible != was_visible)
237 gtk_tree_store_set (GTK_TREE_STORE (model), iter,
238 ITEM_VISIBLE, visible,
239 -1);
240
241 g_free (name);
242 return FALSE;
243 }
244
245 static void
name_guru_search(GtkEntry * entry,gpointer data)246 name_guru_search (GtkEntry *entry, gpointer data)
247 {
248 gchar const *text;
249 NameGuruState *state = data;
250
251 if (0 == gtk_entry_get_text_length (entry)){
252 name_guru_erase_search_entry
253 (entry,
254 GTK_ENTRY_ICON_SECONDARY, NULL,
255 data);
256 return;
257 }
258 text = gtk_entry_get_text (entry);
259 gtk_tree_model_foreach (GTK_TREE_MODEL (state->model),
260 cb_name_guru_search, (gpointer) text);
261 }
262
263 static void
cb_get_names(G_GNUC_UNUSED gpointer key,GnmNamedExpr * nexpr,GList ** accum)264 cb_get_names (G_GNUC_UNUSED gpointer key, GnmNamedExpr *nexpr,
265 GList **accum)
266 {
267 if (!nexpr->is_hidden)
268 *accum = g_list_prepend (*accum, nexpr);
269 }
270
271 static GList *
name_guru_get_available_sheet_names(Sheet const * sheet)272 name_guru_get_available_sheet_names (Sheet const *sheet)
273 {
274 GList *res = NULL;
275
276 gnm_sheet_foreach_name (sheet, (GHFunc) cb_get_names, &res);
277 return g_list_sort (res, (GCompareFunc)expr_name_cmp_by_name);
278 }
279
280 static GList *
name_guru_get_available_wb_names(Workbook const * wb)281 name_guru_get_available_wb_names (Workbook const *wb)
282 {
283 GList *res = NULL;
284
285 workbook_foreach_name (wb, TRUE,
286 (GHFunc) cb_get_names,
287 &res);
288 return g_list_sort (res, (GCompareFunc)expr_name_cmp_by_name);
289 }
290
291 static void
name_guru_set_images(NameGuruState * state,GtkTreeIter * name_iter,item_type_t type,gboolean pastable)292 name_guru_set_images (NameGuruState *state, GtkTreeIter *name_iter,
293 item_type_t type, gboolean pastable)
294 {
295 GdkPixbuf *button1 = NULL, *button2 = NULL;
296
297 switch (type) {
298 case item_type_workbook:
299 case item_type_main_sheet:
300 button2 = state->image_add;
301 break;
302 case item_type_locked_name:
303 button2 = state->image_lock;
304 break;
305 case item_type_available_wb_name:
306 case item_type_new_unsaved_wb_name:
307 button1 = state->image_down;
308 button2 = state->image_delete;
309 break;
310 case item_type_available_sheet_name:
311 case item_type_new_unsaved_sheet_name:
312 button1 = state->image_up;
313 button2 = state->image_delete;
314 break;
315 case item_type_other_sheet:
316 case item_type_foreign_name:
317 default:
318 break;
319 }
320
321 gtk_tree_store_set (state->model, name_iter,
322 ITEM_UPDOWN_IMAGE, button1,
323 ITEM_ADDDELETE_IMAGE, button2,
324 ITEM_PASTE_IMAGE,
325 pastable ? state->image_paste : NULL,
326 ITEM_UPDOWN_ACTIVE, button1 != NULL,
327 ITEM_ADDDELETE_ACTIVE, button2 != NULL,
328 -1);
329 }
330
331 static void
name_guru_store_names(GList * list,GtkTreeIter * iter,NameGuruState * state,item_type_t type)332 name_guru_store_names (GList *list,
333 GtkTreeIter *iter,
334 NameGuruState *state,
335 item_type_t type)
336 {
337 GtkTreeIter name_iter;
338 char *content;
339 item_type_t adj_type;
340 GList *l;
341
342 for (l = list; l != NULL; l = l->next) {
343 GnmNamedExpr *nexpr = l->data;
344 gboolean ciseditable, ispastable;
345
346 if (nexpr->is_hidden || expr_name_is_placeholder (nexpr))
347 continue;
348
349 ispastable = ciseditable =
350 type == item_type_available_wb_name
351 || type == item_type_available_sheet_name;
352
353 if (nexpr->is_permanent) {
354 adj_type = item_type_locked_name;
355 ciseditable = FALSE;
356 } else
357 adj_type = type;
358
359 content = expr_name_as_string (nexpr, &state->pp,
360 sheet_get_conventions (state->sheet));
361
362
363 gtk_tree_store_append (state->model, &name_iter,
364 iter);
365 gtk_tree_store_set (state->model, &name_iter,
366 ITEM_NAME, expr_name_name (nexpr),
367 ITEM_NAME_POINTER, nexpr,
368 ITEM_CONTENT, content,
369 ITEM_TYPE, adj_type,
370 ITEM_CONTENT_IS_EDITABLE, ciseditable,
371 ITEM_NAME_IS_EDITABLE, FALSE,
372 ITEM_PASTABLE, ispastable,
373 ITEM_VISIBLE, TRUE,
374 -1);
375 g_free (content);
376
377 name_guru_set_images (state, &name_iter, adj_type, ispastable);
378 }
379 g_list_free (list);
380 }
381
382 static void
name_guru_populate_list(NameGuruState * state)383 name_guru_populate_list (NameGuruState *state)
384 {
385 GtkTreeIter iter;
386
387 g_return_if_fail (state != NULL);
388 g_return_if_fail (state->treeview != NULL);
389
390 gtk_tree_store_clear (state->model);
391
392 gtk_tree_store_append (state->model, &iter, NULL);
393 gtk_tree_store_set (state->model, &iter,
394 ITEM_NAME, _("Workbook"),
395 ITEM_NAME_POINTER, NULL,
396 ITEM_TYPE, item_type_workbook,
397 ITEM_CONTENT_IS_EDITABLE, FALSE,
398 ITEM_NAME_IS_EDITABLE, FALSE,
399 ITEM_PASTABLE, FALSE,
400 ITEM_VISIBLE, TRUE,
401 -1);
402 name_guru_set_images (state, &iter, item_type_workbook, FALSE);
403 name_guru_store_names (name_guru_get_available_wb_names (state->wb),
404 &iter,
405 state,
406 item_type_available_wb_name);
407 name_guru_expand_at_iter (state, &iter);
408
409 gtk_tree_store_append (state->model, &iter, NULL);
410 gtk_tree_store_set (state->model, &iter,
411 ITEM_NAME, state->sheet->name_unquoted,
412 ITEM_NAME_POINTER, state->sheet,
413 ITEM_TYPE, item_type_main_sheet,
414 ITEM_CONTENT_IS_EDITABLE, FALSE,
415 ITEM_NAME_IS_EDITABLE, FALSE,
416 ITEM_PASTABLE, FALSE,
417 ITEM_VISIBLE, TRUE,
418 -1);
419 name_guru_set_images (state, &iter, item_type_main_sheet, FALSE);
420
421 name_guru_store_names (name_guru_get_available_sheet_names
422 (state->sheet),
423 &iter,
424 state,
425 item_type_available_sheet_name);
426 name_guru_expand_at_iter (state, &iter);
427
428 WORKBOOK_FOREACH_SHEET
429 (state->wb, sheet,
430 {
431 if (sheet == state->sheet)
432 continue;
433
434 gtk_tree_store_append (state->model, &iter, NULL);
435 gtk_tree_store_set (state->model, &iter,
436 ITEM_NAME, sheet->name_unquoted,
437 ITEM_NAME_POINTER, sheet,
438 ITEM_TYPE, item_type_other_sheet,
439 ITEM_CONTENT_IS_EDITABLE, FALSE,
440 ITEM_NAME_IS_EDITABLE, FALSE,
441 ITEM_VISIBLE, TRUE,
442 ITEM_PASTABLE, FALSE,
443 -1);
444
445 name_guru_store_names
446 (name_guru_get_available_sheet_names (sheet),
447 &iter, state, item_type_foreign_name);
448 });
449 }
450
451 static gboolean
name_guru_paste(NameGuruState * state,GtkTreeIter * iter)452 name_guru_paste (NameGuruState *state, GtkTreeIter *iter)
453 {
454 char *name;
455 gboolean is_pastable;
456
457 gtk_tree_model_get (GTK_TREE_MODEL (state->model),
458 iter,
459 ITEM_PASTABLE, &is_pastable,
460 ITEM_NAME, &name,
461 -1);
462
463 if (!is_pastable)
464 return FALSE;
465
466 if (wbcg_edit_start (state->wbcg, FALSE, FALSE)) {
467 GtkEntry *entry;
468 gint position;
469 entry = wbcg_get_entry (state->wbcg);
470
471 position = gtk_entry_get_text_length (entry);
472 if (position == 0)
473 gtk_editable_insert_text (GTK_EDITABLE (entry), "=",
474 -1, &position);
475 else {
476 gtk_editable_delete_selection (GTK_EDITABLE (entry));
477 position = gtk_editable_get_position
478 (GTK_EDITABLE (entry));
479 }
480 if (state->has_pasted) {
481 char sep = go_locale_get_arg_sep ();
482 gtk_editable_insert_text (GTK_EDITABLE (entry), &sep,
483 1, &position);
484 }
485 gtk_editable_insert_text (GTK_EDITABLE (entry), name,
486 -1, &position);
487 gtk_editable_set_position (GTK_EDITABLE (entry), position);
488 }
489
490 g_free (name);
491
492 state->has_pasted = TRUE;
493 return TRUE;
494 }
495
496
497
498
499 static void
cb_name_guru_clicked(GtkWidget * button,NameGuruState * state)500 cb_name_guru_clicked (GtkWidget *button, NameGuruState *state)
501 {
502 if (state->dialog == NULL)
503 return;
504
505 wbcg_set_entry (state->wbcg, NULL);
506
507 if (button == state->close_button) {
508 gtk_widget_destroy (state->dialog);
509 return;
510 }
511 if (button == state->paste_button) {
512 GtkTreeIter iter_f;
513 GtkTreeIter iter;
514 if (gtk_tree_selection_get_selected
515 (gtk_tree_view_get_selection
516 (GTK_TREE_VIEW (state->treeview)), NULL, &iter_f)) {
517 gtk_tree_model_filter_convert_iter_to_child_iter
518 (GTK_TREE_MODEL_FILTER (state->model_f),
519 &iter, &iter_f);
520 if (name_guru_paste (state, &iter))
521 gtk_widget_destroy (state->dialog);
522 }
523 return;
524 }
525 }
526
527 static GtkWidget *
name_guru_init_button(NameGuruState * state,char const * name)528 name_guru_init_button (NameGuruState *state, char const *name)
529 {
530 GtkWidget *tmp = go_gtk_builder_get_widget (state->gui, name);
531
532 g_return_val_if_fail (tmp != NULL, NULL);
533
534 g_signal_connect (G_OBJECT (tmp),
535 "clicked",
536 G_CALLBACK (cb_name_guru_clicked), state);
537 return tmp;
538 }
539
540 static void
cb_name_guru_destroy(NameGuruState * state)541 cb_name_guru_destroy (NameGuruState *state)
542 {
543 WorkbookControl *wbc = GNM_WBC (state->wbcg);
544
545 wb_view_selection_desc (wb_control_view (wbc), TRUE, wbc);
546 g_clear_object (&state->gui);
547 g_clear_object (&state->model);
548
549 if (!state->is_paste_dialog)
550 wbcg_edit_finish (state->wbcg, WBC_EDIT_REJECT, NULL);
551
552 g_clear_object (&state->image_paste);
553 g_clear_object (&state->image_add);
554 g_clear_object (&state->image_delete);
555 g_clear_object (&state->image_lock);
556 g_clear_object (&state->image_up);
557 g_clear_object (&state->image_down);
558
559 state->dialog = NULL;
560 g_free (state);
561 }
562
563
564 static void
cb_name_guru_paste(G_GNUC_UNUSED GtkCellRendererToggle * cell,gchar * path_string,gpointer data)565 cb_name_guru_paste (G_GNUC_UNUSED GtkCellRendererToggle *cell,
566 gchar *path_string,
567 gpointer data)
568 {
569 NameGuruState *state = data;
570 GtkTreeIter iter;
571
572 if (name_guru_translate_pathstring_to_iter
573 (state, &iter, path_string))
574 name_guru_paste (state, &iter);
575 }
576
577 static void
name_guru_add(NameGuruState * state,GtkTreeIter * iter,gchar const * path_string)578 name_guru_add (NameGuruState *state, GtkTreeIter *iter, gchar const *path_string)
579 {
580 GtkTreeIter name_iter;
581 char *content;
582 GtkTreePath *path;
583 item_type_t type;
584
585 path = gtk_tree_path_new_from_string (path_string);
586
587 type = ((gtk_tree_path_get_indices (path))[0] == 0) ?
588 item_type_new_unsaved_wb_name :
589 item_type_new_unsaved_sheet_name;
590 content = selection_to_string (state->sv, FALSE);
591
592 gtk_tree_store_insert (state->model, &name_iter,
593 iter, 0);
594 gtk_tree_store_set (state->model, &name_iter,
595 ITEM_NAME, _("<new name>"),
596 ITEM_NAME_POINTER, NULL,
597 ITEM_CONTENT,
598 ((content == NULL) ? "#REF!" : content),
599 ITEM_TYPE, type,
600 ITEM_CONTENT_IS_EDITABLE, TRUE,
601 ITEM_NAME_IS_EDITABLE, TRUE,
602 ITEM_PASTABLE, FALSE,
603 ITEM_VISIBLE, TRUE,
604 -1);
605 name_guru_set_images (state, &name_iter, type, FALSE);
606 name_guru_expand_at_iter (state, iter);
607 g_free (content);
608 }
609
610 static void
name_guru_delete(NameGuruState * state,GtkTreeIter * iter,item_type_t type)611 name_guru_delete (NameGuruState *state, GtkTreeIter *iter, item_type_t type)
612 {
613 GnmNamedExpr *nexpr;
614
615 if (type != item_type_new_unsaved_wb_name &&
616 type != item_type_new_unsaved_sheet_name) {
617 gtk_tree_model_get (GTK_TREE_MODEL (state->model),
618 iter,
619 ITEM_NAME_POINTER, &nexpr,
620 -1);
621
622 if (!name_guru_warn (state, nexpr))
623 return;
624
625 cmd_remove_name (GNM_WBC (state->wbcg), nexpr);
626 }
627 gtk_tree_store_remove (state->model, iter);
628 }
629
630
631 static void
cb_name_guru_add_delete(G_GNUC_UNUSED GtkCellRendererToggle * cell,gchar * path_string,gpointer data)632 cb_name_guru_add_delete (G_GNUC_UNUSED GtkCellRendererToggle *cell,
633 gchar *path_string,
634 gpointer data)
635 {
636 NameGuruState *state = data;
637 GtkTreeIter iter;
638
639 if (name_guru_translate_pathstring_to_iter
640 (state, &iter, path_string)) {
641 item_type_t type;
642
643 gtk_tree_model_get (GTK_TREE_MODEL (state->model),
644 &iter,
645 ITEM_TYPE, &type,
646 -1);
647
648 switch (type) {
649 case item_type_workbook:
650 case item_type_main_sheet:
651 name_guru_add (state, &iter, path_string);
652 break;
653 case item_type_available_wb_name:
654 case item_type_available_sheet_name:
655 case item_type_new_unsaved_wb_name:
656 case item_type_new_unsaved_sheet_name:
657 name_guru_delete (state, &iter, type);
658 break;
659 case item_type_other_sheet:
660 case item_type_locked_name:
661 case item_type_foreign_name:
662 default:
663 break;
664 }
665 }
666 }
667
668 static void
name_guru_find_place(NameGuruState * state,GtkTreeIter * iter,GtkTreeIter * parent_iter,GnmNamedExpr * nexpr)669 name_guru_find_place (NameGuruState *state, GtkTreeIter *iter,
670 GtkTreeIter *parent_iter, GnmNamedExpr *nexpr)
671 {
672 GtkTreeIter next_iter;
673 GnmNamedExpr *next_nexpr;
674 if (nexpr != NULL &&
675 gtk_tree_model_iter_children (GTK_TREE_MODEL (state->model),
676 &next_iter,
677 parent_iter)) {
678 do {
679 gtk_tree_model_get (GTK_TREE_MODEL (state->model),
680 &next_iter,
681 ITEM_NAME_POINTER, &next_nexpr,
682 -1);
683 if (next_nexpr != NULL &&
684 expr_name_cmp_by_name (nexpr, next_nexpr) < 0) {
685 gtk_tree_store_insert_before
686 (state->model,
687 iter,
688 parent_iter,
689 &next_iter);
690 return;
691 }
692 } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (state->model),
693 &next_iter));
694
695 gtk_tree_store_append (state->model, iter,
696 parent_iter);
697 } else {
698 gtk_tree_store_prepend (state->model, iter,
699 parent_iter);
700 }
701 }
702
703
704 static void
name_guru_move_record(NameGuruState * state,GtkTreeIter * from_iter,GtkTreeIter * new_parent_iter,item_type_t new_type)705 name_guru_move_record (NameGuruState *state, GtkTreeIter *from_iter,
706 GtkTreeIter *new_parent_iter, item_type_t new_type)
707 {
708 GnmNamedExpr *nexpr;
709 gchar *name, *content;
710 gboolean ceditable, neditable, pastable, visible;
711 GtkTreeIter new_iter;
712
713 gtk_tree_model_get (GTK_TREE_MODEL (state->model),
714 from_iter,
715 ITEM_NAME, &name,
716 ITEM_NAME_POINTER, &nexpr,
717 ITEM_CONTENT, &content,
718 ITEM_CONTENT_IS_EDITABLE, &ceditable,
719 ITEM_NAME_IS_EDITABLE, &neditable,
720 ITEM_PASTABLE, &pastable,
721 ITEM_VISIBLE, &visible,
722 -1);
723
724 gtk_tree_store_remove (state->model, from_iter);
725
726 name_guru_find_place (state, &new_iter, new_parent_iter, nexpr);
727
728 gtk_tree_store_set (state->model, &new_iter,
729 ITEM_NAME, name,
730 ITEM_NAME_POINTER, nexpr,
731 ITEM_CONTENT, content,
732 ITEM_TYPE, new_type,
733 ITEM_CONTENT_IS_EDITABLE, ceditable,
734 ITEM_NAME_IS_EDITABLE, neditable,
735 ITEM_PASTABLE, pastable,
736 ITEM_VISIBLE, visible,
737 -1);
738 name_guru_set_images (state, &new_iter, new_type, pastable);
739 name_guru_expand_at_iter (state, &new_iter);
740 g_free (name);
741 g_free (content);
742 }
743
744 static void
cb_name_guru_switch_scope(G_GNUC_UNUSED GtkCellRendererToggle * cell,gchar * path_string,gpointer data)745 cb_name_guru_switch_scope (G_GNUC_UNUSED GtkCellRendererToggle *cell,
746 gchar *path_string,
747 gpointer data)
748 {
749 NameGuruState *state = data;
750 GtkTreeIter iter;
751
752 if (name_guru_translate_pathstring_to_iter
753 (state, &iter, path_string)) {
754 item_type_t type, new_type;
755 gchar const *new_path;
756 GnmNamedExpr *nexpr;
757 GtkTreeIter new_parent_iter;
758
759 gtk_tree_model_get (GTK_TREE_MODEL (state->model),
760 &iter,
761 ITEM_TYPE, &type,
762 ITEM_NAME_POINTER, &nexpr,
763 -1);
764
765 switch (type) {
766 case item_type_available_wb_name:
767 if (cmd_rescope_name
768 (GNM_WBC (state->wbcg),
769 nexpr, state->sheet))
770 return;
771 new_path = "1";
772 new_type = item_type_available_sheet_name;
773 break;
774 case item_type_new_unsaved_wb_name:
775 new_path = "1";
776 new_type = item_type_new_unsaved_sheet_name;
777 break;
778 case item_type_available_sheet_name:
779 if (cmd_rescope_name
780 (GNM_WBC (state->wbcg),
781 nexpr, NULL))
782 return;
783 new_path = "0";
784 new_type = item_type_available_wb_name;
785 break;
786 case item_type_new_unsaved_sheet_name:
787 new_path = "0";
788 new_type = item_type_new_unsaved_wb_name;
789 break;
790 case item_type_workbook:
791 case item_type_main_sheet:
792 case item_type_other_sheet:
793 case item_type_locked_name:
794 case item_type_foreign_name:
795 default:
796 return;
797 }
798
799 if (gtk_tree_model_get_iter_from_string
800 (GTK_TREE_MODEL (state->model),
801 &new_parent_iter, new_path)) {
802 name_guru_move_record
803 (state, &iter, &new_parent_iter, new_type);
804 }
805 }
806 }
807
808 static gboolean
name_guru_parse_pos_init(NameGuruState * state,GnmParsePos * pp,item_type_t type)809 name_guru_parse_pos_init (NameGuruState *state,
810 GnmParsePos *pp, item_type_t type)
811 {
812 switch (type) {
813 case item_type_available_wb_name:
814 case item_type_new_unsaved_wb_name:
815 parse_pos_init (pp, state->wb, NULL,
816 state->pp.eval.col, state->pp.eval.row);
817 return TRUE;
818 case item_type_available_sheet_name:
819 case item_type_new_unsaved_sheet_name:
820 parse_pos_init (pp, state->wb, state->sheet,
821 state->pp.eval.col, state->pp.eval.row);
822 return TRUE;
823 case item_type_workbook:
824 case item_type_main_sheet:
825 case item_type_other_sheet:
826 case item_type_locked_name:
827 case item_type_foreign_name:
828 default:
829 return FALSE;
830 }
831 }
832
833 /*
834 * Return the expression if it is acceptable.
835 * The parse position will be initialized then.
836 */
837
838 static GnmExprTop const*
name_guru_check_expression(NameGuruState * state,gchar * text,GnmParsePos * pp,item_type_t type)839 name_guru_check_expression (NameGuruState *state, gchar *text,
840 GnmParsePos *pp, item_type_t type)
841 {
842 GnmExprTop const *texpr;
843 GnmParseError perr;
844
845 if (!name_guru_parse_pos_init (state, pp, type))
846 return NULL; /* We should have never gotten here. */
847
848 if (text == NULL || text[0] == '\0') {
849 go_gtk_notice_dialog (GTK_WINDOW (state->dialog),
850 GTK_MESSAGE_ERROR,
851 _("Why would you want to define a "
852 "name for the empty string?"));
853 return NULL;
854 }
855
856 texpr = gnm_expr_parse_str (text, pp,
857 GNM_EXPR_PARSE_DEFAULT |
858 GNM_EXPR_PARSE_UNKNOWN_NAMES_ARE_INVALID |
859 GNM_EXPR_PARSE_PERMIT_MULTIPLE_EXPRESSIONS,
860 NULL,
861 parse_error_init (&perr));
862 if (texpr == NULL) {
863 if (perr.err == NULL)
864 return NULL;
865
866 go_gtk_notice_dialog (GTK_WINDOW (state->dialog),
867 GTK_MESSAGE_ERROR,
868 "%s", perr.err->message);
869 parse_error_free (&perr);
870 return NULL;
871 }
872 /* don't allow user to define a nexpr that looks like a placeholder *
873 * because it will be would disappear from the lists. */
874 if (gnm_expr_top_is_err (texpr, GNM_ERROR_NAME)) {
875 go_gtk_notice_dialog (GTK_WINDOW (state->dialog), GTK_MESSAGE_ERROR,
876 _("Why would you want to define a name to be #NAME?"));
877 parse_error_free (&perr);
878 gnm_expr_top_unref (texpr);
879 return NULL;
880 }
881
882 return texpr;
883 }
884
885
886 static void
cb_name_guru_content_edited(G_GNUC_UNUSED GnmCellRendererExprEntry * cell,gchar * path_string,gchar * new_text,NameGuruState * state)887 cb_name_guru_content_edited
888 (G_GNUC_UNUSED GnmCellRendererExprEntry *cell,
889 gchar *path_string,
890 gchar *new_text,
891 NameGuruState *state)
892 {
893 GtkTreeIter iter;
894 item_type_t type;
895 GnmParsePos pp;
896 GnmExprTop const *texpr;
897 GnmNamedExpr *nexpr;
898
899 if (!name_guru_translate_pathstring_to_iter
900 (state, &iter, path_string))
901 return;
902
903 gtk_tree_model_get (GTK_TREE_MODEL (state->model), &iter,
904 ITEM_TYPE, &type,
905 ITEM_NAME_POINTER, &nexpr,
906 -1);
907
908 /* check whether the content is valid */
909
910
911 texpr = name_guru_check_expression (state, new_text, &pp , type);
912 if (texpr == NULL)
913 return;
914
915 /* content is valid */
916
917 if (type != item_type_new_unsaved_wb_name
918 && type != item_type_new_unsaved_sheet_name) {
919 /* save the changes (if the name is already saved) */
920 cmd_define_name (GNM_WBC (state->wbcg),
921 expr_name_name (nexpr),
922 &pp, texpr, NULL);
923 } else
924 gnm_expr_top_unref (texpr);
925
926 /* set the model */
927 gtk_tree_store_set (state->model, &iter, ITEM_CONTENT, new_text, -1);
928 }
929
930 static void
cb_name_guru_name_edited(G_GNUC_UNUSED GtkCellRendererText * cell,gchar * path_string,gchar * new_text,NameGuruState * state)931 cb_name_guru_name_edited (G_GNUC_UNUSED GtkCellRendererText *cell,
932 gchar *path_string,
933 gchar *new_text,
934 NameGuruState *state)
935 {
936 GtkTreeIter iter;
937 GtkTreeIter parent_iter;
938 item_type_t type;
939 GnmParsePos pp;
940 GnmExprTop const *texpr;
941 gchar *content;
942 GnmNamedExpr *nexpr;
943
944 g_return_if_fail (new_text != NULL);
945
946 if (!name_guru_translate_pathstring_to_iter
947 (state, &iter, path_string))
948 return;
949
950 gtk_tree_model_get (GTK_TREE_MODEL (state->model), &iter,
951 ITEM_TYPE, &type,
952 ITEM_CONTENT, &content,
953 -1);
954
955 if (type != item_type_new_unsaved_wb_name &&
956 type != item_type_new_unsaved_sheet_name)
957 return;
958
959 name_guru_parse_pos_init (state, &pp, type);
960 nexpr = expr_name_lookup (&pp, new_text);
961
962 if (nexpr != NULL && !nexpr->is_placeholder) {
963 Sheet *scope = nexpr->pos.sheet;
964 if ((type == item_type_new_unsaved_wb_name &&
965 scope == NULL) ||
966 (type == item_type_new_unsaved_sheet_name)) {
967 go_gtk_notice_dialog
968 (GTK_WINDOW (state->dialog),
969 GTK_MESSAGE_ERROR,
970 _("This name is already in use!"));
971 return;
972 }
973 }
974
975 texpr = name_guru_check_expression (state, content, &pp , type);
976 if (texpr == NULL)
977 return;
978
979 if (!cmd_define_name (GNM_WBC (state->wbcg),
980 new_text, &pp,
981 texpr, NULL)) {
982 nexpr = expr_name_lookup (&pp, new_text);
983
984 type = (type == item_type_new_unsaved_wb_name) ?
985 item_type_available_wb_name :
986 item_type_available_sheet_name;
987
988 gtk_tree_store_set
989 (state->model, &iter,
990 ITEM_NAME, new_text,
991 ITEM_NAME_POINTER, nexpr,
992 ITEM_TYPE, type,
993 ITEM_PASTABLE, TRUE,
994 ITEM_NAME_IS_EDITABLE, FALSE,
995 -1);
996 name_guru_set_images (state, &iter, type, TRUE);
997
998 if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (state->model),
999 &parent_iter, &iter))
1000 name_guru_move_record (state, &iter, &parent_iter, type);
1001 }
1002 }
1003
1004 static void
name_guru_update_sensitivity(GtkTreeSelection * treeselection,gpointer user_data)1005 name_guru_update_sensitivity (GtkTreeSelection *treeselection,
1006 gpointer user_data)
1007 {
1008 NameGuruState *state = user_data;
1009 gboolean is_pastable = FALSE;
1010 GtkTreeIter iter;
1011
1012 if (gtk_tree_selection_get_selected
1013 (treeselection, NULL, &iter))
1014 gtk_tree_model_get (state->model_f, &iter,
1015 ITEM_PASTABLE, &is_pastable,
1016 -1);
1017 gtk_widget_set_sensitive (GTK_WIDGET (state->paste_button),
1018 is_pastable);
1019
1020 }
1021
1022 static gboolean
cb_name_guru_selection_function(G_GNUC_UNUSED GtkTreeSelection * selection,GtkTreeModel * model,GtkTreePath * path,gboolean path_currently_selected,G_GNUC_UNUSED gpointer data)1023 cb_name_guru_selection_function (G_GNUC_UNUSED GtkTreeSelection *selection,
1024 GtkTreeModel *model,
1025 GtkTreePath *path,
1026 gboolean path_currently_selected,
1027 G_GNUC_UNUSED gpointer data)
1028 {
1029 GtkTreeIter iter;
1030
1031 if (path_currently_selected)
1032 return TRUE;
1033 if (gtk_tree_model_get_iter (model, &iter, path)) {
1034 gboolean is_pastable, is_editable;
1035 gtk_tree_model_get (model,
1036 &iter,
1037 ITEM_PASTABLE, &is_pastable,
1038 ITEM_CONTENT_IS_EDITABLE, &is_editable,
1039 -1);
1040 return (is_pastable || is_editable);
1041 }
1042 return FALSE;
1043 }
1044
1045 static gboolean
name_guru_init(NameGuruState * state,WBCGtk * wbcg,gboolean is_paste_dialog)1046 name_guru_init (NameGuruState *state, WBCGtk *wbcg, gboolean is_paste_dialog)
1047 {
1048 Workbook *wb = wb_control_get_workbook (GNM_WBC (wbcg));
1049 GtkTreeViewColumn *column;
1050 GtkCellRenderer *renderer;
1051 GtkTreeSelection *selection;
1052 GtkWidget *widget = GTK_WIDGET (wbcg_toplevel (wbcg));
1053
1054 state->is_paste_dialog = is_paste_dialog;
1055 state->has_pasted = FALSE;
1056
1057 state->gui = gnm_gtk_builder_load ("res:ui/define-name.ui", NULL,
1058 GO_CMD_CONTEXT (wbcg));
1059 if (state->gui == NULL)
1060 return TRUE;
1061
1062 state->wbcg = wbcg;
1063 state->wb = wb;
1064 state->sv = wb_control_cur_sheet_view (GNM_WBC (wbcg));
1065 state->sheet = sv_sheet (state->sv);
1066 parse_pos_init_editpos (&state->pp, state->sv);
1067
1068 state->dialog = go_gtk_builder_get_widget (state->gui, "NameGuru");
1069
1070 gnm_dialog_setup_destroy_handlers (GTK_DIALOG (state->dialog),
1071 state->wbcg,
1072 GNM_DIALOG_DESTROY_SHEET_REMOVED);
1073 state->model = gtk_tree_store_new
1074 (NUM_COLUMNS,
1075 G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING,
1076 G_TYPE_INT, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1077 GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF,
1078 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1079 GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN);
1080
1081 state->treeview = go_gtk_builder_get_widget (state->gui, "name_list");
1082
1083 state->model_f = gtk_tree_model_filter_new
1084 (GTK_TREE_MODEL (state->model), NULL);
1085 gtk_tree_model_filter_set_visible_column
1086 (GTK_TREE_MODEL_FILTER (state->model_f), ITEM_VISIBLE);
1087
1088 gtk_tree_view_set_model (GTK_TREE_VIEW (state->treeview),
1089 state->model_f);
1090 g_object_unref (state->model_f);
1091 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (state->treeview),
1092 FALSE);
1093 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (state->treeview),
1094 GTK_TREE_VIEW_GRID_LINES_NONE);
1095 gtk_tree_view_set_reorderable (GTK_TREE_VIEW (state->treeview),
1096 FALSE);
1097
1098 renderer = gtk_cell_renderer_text_new ();
1099 g_signal_connect (G_OBJECT (renderer), "edited",
1100 G_CALLBACK (cb_name_guru_name_edited), state);
1101 column = gtk_tree_view_column_new_with_attributes
1102 ("name",
1103 renderer,
1104 "text", ITEM_NAME,
1105 "editable", ITEM_NAME_IS_EDITABLE,
1106 NULL);
1107 gtk_tree_view_append_column (GTK_TREE_VIEW (state->treeview), column);
1108
1109 if (is_paste_dialog) {
1110 renderer = gnm_cell_renderer_toggle_new ();
1111 g_signal_connect (G_OBJECT (renderer),
1112 "toggled",
1113 G_CALLBACK (cb_name_guru_paste), state);
1114 column = gtk_tree_view_column_new_with_attributes
1115 ("Paste",
1116 renderer,
1117 "active", ITEM_PASTABLE,
1118 "pixbuf", ITEM_PASTE_IMAGE,
1119 NULL);
1120 gtk_tree_view_append_column (GTK_TREE_VIEW (state->treeview),
1121 column);
1122 } else {
1123 renderer = gnm_cell_renderer_toggle_new ();
1124 g_signal_connect (G_OBJECT (renderer),
1125 "toggled",
1126 G_CALLBACK (cb_name_guru_add_delete), state);
1127 column = gtk_tree_view_column_new_with_attributes
1128 ("Lock",
1129 renderer,
1130 "active", ITEM_ADDDELETE_ACTIVE,
1131 "pixbuf", ITEM_ADDDELETE_IMAGE,
1132 NULL);
1133 gtk_tree_view_append_column (GTK_TREE_VIEW (state->treeview),
1134 column);
1135
1136 renderer = gnm_cell_renderer_toggle_new ();
1137 g_signal_connect (G_OBJECT (renderer),
1138 "toggled",
1139 G_CALLBACK (cb_name_guru_switch_scope),
1140 state);
1141 column = gtk_tree_view_column_new_with_attributes
1142 ("Scope",
1143 renderer,
1144 "active", ITEM_UPDOWN_ACTIVE,
1145 "pixbuf", ITEM_UPDOWN_IMAGE,
1146 NULL);
1147 gtk_tree_view_append_column (GTK_TREE_VIEW (state->treeview),
1148 column);
1149 }
1150
1151 renderer = gnm_cell_renderer_expr_entry_new (state->wbcg);
1152 g_signal_connect (G_OBJECT (renderer), "edited",
1153 G_CALLBACK (cb_name_guru_content_edited), state);
1154 column = gtk_tree_view_column_new_with_attributes
1155 (_("content"),
1156 renderer,
1157 "text", ITEM_CONTENT,
1158 "editable", ITEM_CONTENT_IS_EDITABLE,
1159 NULL);
1160 gtk_tree_view_append_column (GTK_TREE_VIEW (state->treeview), column);
1161
1162
1163 selection = gtk_tree_view_get_selection
1164 (GTK_TREE_VIEW (state->treeview));
1165 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1166 gtk_tree_selection_set_select_function
1167 (selection, cb_name_guru_selection_function,
1168 state, NULL);
1169
1170 state->close_button = name_guru_init_button (state, "close_button");
1171 state->paste_button = name_guru_init_button (state, "paste_button");
1172
1173 if (is_paste_dialog) {
1174 g_signal_connect (G_OBJECT (selection),
1175 "changed",
1176 G_CALLBACK (name_guru_update_sensitivity),
1177 state);
1178 state->image_paste = go_gtk_widget_render_icon_pixbuf (widget, "edit-paste", GTK_ICON_SIZE_MENU);
1179 state->image_add = NULL;
1180 state->image_delete = NULL;
1181 state->image_lock = NULL;
1182 state->image_up = NULL;
1183 state->image_down = NULL;
1184 } else {
1185 state->image_paste = NULL;
1186 state->image_add = go_gtk_widget_render_icon_pixbuf (widget, "list-add", GTK_ICON_SIZE_MENU);
1187 state->image_delete = go_gtk_widget_render_icon_pixbuf (widget, "list-remove", GTK_ICON_SIZE_MENU);
1188 state->image_lock = go_gtk_widget_render_icon_pixbuf (widget, "gnumeric-protection-yes", GTK_ICON_SIZE_MENU);
1189 state->image_up = go_gtk_widget_render_icon_pixbuf (widget, "go-up", GTK_ICON_SIZE_MENU);
1190 state->image_down = go_gtk_widget_render_icon_pixbuf (widget, "go-down", GTK_ICON_SIZE_MENU);
1191 }
1192
1193 state->search_entry = go_gtk_builder_get_widget (state->gui, "search_entry");
1194
1195 g_signal_connect (G_OBJECT (state->search_entry),
1196 "icon-press",
1197 G_CALLBACK (name_guru_erase_search_entry),
1198 state);
1199
1200 g_signal_connect (G_OBJECT (state->search_entry),
1201 "activate",
1202 G_CALLBACK (name_guru_search),
1203 state);
1204
1205 name_guru_populate_list (state);
1206 name_guru_update_sensitivity (selection, state);
1207
1208 gnm_init_help_button (
1209 go_gtk_builder_get_widget (state->gui, "help_button"),
1210 is_paste_dialog ? GNUMERIC_HELP_LINK_PASTE_NAMES
1211 : GNUMERIC_HELP_LINK_DEFINE_NAMES);
1212
1213 /* a candidate for merging into attach guru */
1214 gnm_keyed_dialog (state->wbcg, GTK_WINDOW (state->dialog),
1215 is_paste_dialog ? PASTE_NAMES_KEY
1216 : DEFINE_NAMES_KEY);
1217 go_gtk_nonmodal_dialog (wbcg_toplevel (state->wbcg),
1218 GTK_WINDOW (state->dialog));
1219
1220 g_object_set_data_full (G_OBJECT (state->dialog),
1221 "state", state, (GDestroyNotify)cb_name_guru_destroy);
1222
1223 if (is_paste_dialog) {
1224 gtk_window_set_title (GTK_WINDOW (state->dialog),
1225 _("Paste Defined Names"));
1226 gtk_widget_show_all (GTK_WIDGET (state->dialog));
1227 } else {
1228 wbc_gtk_attach_guru (state->wbcg, state->dialog);
1229 gtk_widget_show (GTK_WIDGET (state->dialog));
1230 }
1231
1232 return FALSE;
1233 }
1234
1235 /**
1236 * dialog_define_names:
1237 * @wbcg:
1238 *
1239 * Create and show the define names dialog.
1240 **/
1241 void
dialog_define_names(WBCGtk * wbcg)1242 dialog_define_names (WBCGtk *wbcg)
1243 {
1244 NameGuruState *state;
1245
1246 g_return_if_fail (wbcg != NULL);
1247
1248 /* Only one guru per workbook. */
1249 if (wbc_gtk_get_guru (wbcg))
1250 return;
1251
1252 /* Only pop up one copy per workbook */
1253 if (gnm_dialog_raise_if_exists (wbcg, DEFINE_NAMES_KEY))
1254 return;
1255
1256 state = g_new0 (NameGuruState, 1);
1257 if (name_guru_init (state, wbcg, FALSE)) {
1258 go_gtk_notice_dialog (wbcg_toplevel (wbcg), GTK_MESSAGE_ERROR,
1259 _("Could not create the Name Guru."));
1260 g_free (state);
1261 return;
1262 }
1263 }
1264
1265 /**
1266 * dialog_paste_names:
1267 * @wbcg:
1268 *
1269 * Create and show the define names dialog.
1270 **/
1271 void
dialog_paste_names(WBCGtk * wbcg)1272 dialog_paste_names (WBCGtk *wbcg)
1273 {
1274 NameGuruState *state;
1275
1276 g_return_if_fail (wbcg != NULL);
1277
1278 /* Only one guru per workbook. */
1279 if (wbc_gtk_get_guru (wbcg))
1280 return;
1281
1282 /* Only pop up one copy per workbook */
1283 if (gnm_dialog_raise_if_exists (wbcg, PASTE_NAMES_KEY))
1284 return;
1285
1286 state = g_new0 (NameGuruState, 1);
1287 if (name_guru_init (state, wbcg, TRUE)) {
1288 go_gtk_notice_dialog (wbcg_toplevel (wbcg), GTK_MESSAGE_ERROR,
1289 _("Could not create the Name Guru."));
1290 g_free (state);
1291 return;
1292 }
1293 }
1294