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