GUI: Dead kittens.
[gnumeric.git] / src / dialogs / dialog-function-select.c
blob2429efbe521e8933c3d530fb80647caaedcbc644
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * dialog-function-select.c: Implements the function selector
5 * Authors:
6 * Michael Meeks <michael@ximian.com>
7 * Andreas J. Guelzow <aguelzow@pyrshep.ca>
9 * Copyright (C) 2003-2010 Andreas J. Guelzow <aguelzow@pyrshep.ca>
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.
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.
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/>.
25 #include <gnumeric-config.h>
26 #include <glib/gi18n-lib.h>
27 #include <gnumeric.h>
28 #include "dialogs.h"
29 #include "help.h"
31 #include <gui-util.h>
32 #include <gutils.h>
33 #include <func.h>
34 #include <workbook.h>
35 #include <wbc-gtk.h>
36 #include <application.h>
37 #include <position.h>
38 #include <expr.h>
39 #include <value.h>
40 #include <sheet.h>
41 #include <gnumeric-conf.h>
42 #include <gnm-format.h>
43 #include <auto-format.h>
45 #include <gsf/gsf-impl-utils.h>
46 #include <gtk/gtk.h>
47 #include <string.h>
49 #define F2(func,s) dgettext ((func)->tdomain->str, (s))
51 #define FUNCTION_SELECT_KEY "function-selector-dialog"
52 #define FUNCTION_SELECT_HELP_KEY "function-selector-dialog-help-mode"
53 #define FUNCTION_SELECT_PASTE_KEY "function-selector-dialog-paste-mode"
54 #define FUNCTION_SELECT_DIALOG_KEY "function-selector-dialog"
56 #define UNICODE_ELLIPSIS "\xe2\x80\xa6"
58 typedef enum {
59 GURU_MODE = 0,
60 HELP_MODE,
61 PASTE_MODE
62 } DialogMode;
64 typedef struct {
65 WBCGtk *wbcg;
66 Workbook *wb;
67 Sheet *sheet;
69 gboolean localized_function_names;
71 GtkBuilder *gui;
72 GtkWidget *dialog;
73 GtkWidget *ok_button;
74 GtkWidget *paste_button;
75 GtkListStore *model;
76 GtkComboBox *cb;
77 GtkListStore *model_functions;
78 GtkTreeModel *model_filter;
79 GtkTreeView *treeview;
80 GtkTextView *description_view;
81 GtkWidget *search_entry;
83 GSList *recent_funcs;
85 struct {
86 gint from;
87 gint to;
88 char *prefix;
89 } paste;
91 DialogMode mode;
92 char const *formula_guru_key;
93 } FunctionSelectState;
95 enum {
96 CAT_NAME,
97 CATEGORY,
98 CAT_SEPARATOR,
99 NUM_CAT_COLUMNS
101 enum {
102 FUN_NAME,
103 FUNCTION,
104 FUNCTION_DESC,
105 FUNCTION_PAL,
106 FUNCTION_CAT,
107 FUNCTION_VISIBLE,
108 FUNCTION_RECENT,
109 FUNCTION_USED,
110 NUM_COLUMNS
113 /*************************************************************************/
114 /* Search Functions */
115 /*************************************************************************/
117 typedef struct {
118 char const *text;
119 gboolean recent_only;
120 gboolean used_only;
121 GnmFuncGroup const * cat;
122 } search_t;
124 static gboolean
125 cb_dialog_function_select_search_all (GtkTreeModel *model,
126 G_GNUC_UNUSED GtkTreePath *path,
127 GtkTreeIter *iter, gpointer data)
129 search_t *specs = data;
130 gchar *name;
131 gchar *desc;
132 gboolean visible, was_visible, recent, used;
133 GnmFuncGroup const * cat;
135 gtk_tree_model_get (model, iter,
136 FUN_NAME, &name,
137 FUNCTION_DESC, &desc,
138 FUNCTION_VISIBLE, &was_visible,
139 FUNCTION_RECENT, &recent,
140 FUNCTION_USED, &used,
141 FUNCTION_CAT, &cat,
142 -1);
144 if (specs->recent_only && !recent)
145 visible = FALSE;
146 else if (specs->used_only && !used)
147 visible = FALSE;
148 else if (specs->cat != NULL && specs->cat != cat)
149 visible = FALSE;
150 else if (specs->text == NULL)
151 visible = TRUE;
152 else {
153 gchar *name_n, *name_cf, *text_n, *text_cf;
155 text_n = g_utf8_normalize (specs->text, -1, G_NORMALIZE_ALL);
156 text_cf = g_utf8_casefold(text_n, -1);
158 name_n = g_utf8_normalize (name, -1, G_NORMALIZE_ALL);
159 name_cf = g_utf8_casefold(name_n, -1);
160 visible = (NULL != g_strstr_len (name_cf, -1, text_cf));
161 g_free (name_n);
162 g_free (name_cf);
164 if (!visible) {
165 name_n = g_utf8_normalize (desc, -1, G_NORMALIZE_ALL);
166 name_cf = g_utf8_casefold(name_n, -1);
167 visible = (NULL != g_strstr_len (name_cf, -1, text_cf));
168 g_free (name_n);
169 g_free (name_cf);
172 g_free (text_n);
173 g_free (text_cf);
176 g_free (name);
177 g_free (desc);
179 if (visible != was_visible)
180 gtk_list_store_set (GTK_LIST_STORE (model), iter,
181 FUNCTION_VISIBLE, visible,
182 -1);
183 return FALSE;
186 static void
187 dialog_function_select_search (GtkEntry *entry, gpointer data)
189 search_t specs = {NULL, FALSE, FALSE, NULL};
190 FunctionSelectState *state = data;
191 GtkTreeIter iter;
193 if (0 != gtk_entry_get_text_length (entry))
194 specs.text = gtk_entry_get_text (entry);
196 if (gtk_combo_box_get_active_iter (state->cb, &iter)) {
197 gtk_tree_model_get (GTK_TREE_MODEL (state->model), &iter,
198 CATEGORY, &specs.cat,
199 -1);
200 specs.recent_only
201 = (specs.cat != NULL &&
202 specs.cat == GINT_TO_POINTER(-1));
203 specs.used_only
204 = (specs.cat != NULL &&
205 specs.cat == GINT_TO_POINTER(-2));
206 if (specs.recent_only || specs.used_only)
207 specs.cat = NULL;
210 gtk_tree_model_foreach (GTK_TREE_MODEL (state->model_functions),
211 cb_dialog_function_select_search_all,
212 (gpointer) &specs);
215 static void
216 dialog_function_select_erase_search_entry (GtkEntry *entry,
217 G_GNUC_UNUSED GtkEntryIconPosition icon_pos,
218 G_GNUC_UNUSED GdkEvent *event,
219 gpointer data)
221 gtk_entry_set_text (entry, "");
222 dialog_function_select_search (entry, data);
225 static void
226 dialog_function_select_cat_changed (G_GNUC_UNUSED GtkComboBox *widget,
227 gpointer data)
229 FunctionSelectState *state = data;
231 dialog_function_select_search (GTK_ENTRY (state->search_entry),
232 data);
235 /*************************************************************************/
237 static gboolean
238 cb_dialog_function_load_recent_funcs(GtkTreeModel *model,
239 G_GNUC_UNUSED GtkTreePath *path,
240 GtkTreeIter *iter,
241 gpointer data)
243 gpointer this;
245 gtk_tree_model_get (model, iter,
246 FUNCTION, &this,
247 -1);
248 if (this == data) {
249 gtk_list_store_set (GTK_LIST_STORE (model), iter,
250 FUNCTION_RECENT, TRUE,
251 -1);
252 return TRUE;
254 return FALSE;
257 static void
258 dialog_function_load_recent_funcs (FunctionSelectState *state)
260 GSList const *recent_funcs;
262 for (recent_funcs = gnm_conf_get_functionselector_recentfunctions ();
263 recent_funcs;
264 recent_funcs = recent_funcs->next) {
265 char const *name = recent_funcs->data;
266 GnmFunc *fd;
268 if (name == NULL)
269 continue;
271 fd = gnm_func_lookup (name, NULL);
272 if (fd) {
273 state->recent_funcs = g_slist_prepend (state->recent_funcs, fd);
274 gtk_tree_model_foreach (GTK_TREE_MODEL (state->model_functions),
275 cb_dialog_function_load_recent_funcs,
276 fd);
281 static void
282 dialog_function_write_recent_func (FunctionSelectState *state, GnmFunc const *fd)
284 GSList *rec_funcs;
285 GSList *gconf_value_list = NULL;
286 guint ulimit = gnm_conf_get_functionselector_num_of_recent ();
288 state->recent_funcs = g_slist_remove (state->recent_funcs, (gpointer) fd);
289 state->recent_funcs = g_slist_prepend (state->recent_funcs, (gpointer) fd);
291 while (g_slist_length (state->recent_funcs) > ulimit)
292 state->recent_funcs = g_slist_remove (state->recent_funcs,
293 g_slist_last (state->recent_funcs)->data);
295 for (rec_funcs = state->recent_funcs; rec_funcs; rec_funcs = rec_funcs->next) {
296 gconf_value_list = g_slist_prepend
297 (gconf_value_list,
298 g_strdup (gnm_func_get_name (rec_funcs->data,
299 state->localized_function_names)));
301 gnm_conf_set_functionselector_recentfunctions (gconf_value_list);
302 g_slist_free_full (gconf_value_list, g_free);
305 static gboolean
306 cb_unref (GtkTreeModel *model, G_GNUC_UNUSED GtkTreePath *path,
307 GtkTreeIter *iter, G_GNUC_UNUSED gpointer data)
309 GnmFunc *f;
311 gtk_tree_model_get (model, iter,
312 FUNCTION, &f,
313 -1);
314 gnm_func_unref (f);
315 return FALSE;
318 static void
319 cb_dialog_function_select_destroy (FunctionSelectState *state)
321 if (state->formula_guru_key &&
322 gnm_dialog_raise_if_exists (state->wbcg, state->formula_guru_key)) {
323 /* The formula guru is waiting for us.*/
324 state->formula_guru_key = NULL;
325 dialog_formula_guru (state->wbcg, NULL);
328 if (state->gui != NULL)
329 g_object_unref (state->gui);
330 g_slist_free (state->recent_funcs);
331 gtk_tree_model_foreach (GTK_TREE_MODEL (state->model_functions),
332 cb_unref,
333 NULL);
334 g_free (state->paste.prefix);
335 g_free (state);
339 * cb_dialog_function_select_cancel_clicked:
340 * @button:
341 * @state:
343 * Close (destroy) the dialog
345 static void
346 cb_dialog_function_select_cancel_clicked (G_GNUC_UNUSED GtkWidget *button,
347 FunctionSelectState *state)
349 gtk_widget_destroy (state->dialog);
350 return;
354 * cb_dialog_function_select_ok_clicked:
355 * @button:
356 * @state:
358 * Close (destroy) the dialog
360 static void
361 cb_dialog_function_select_ok_clicked (G_GNUC_UNUSED GtkWidget *button,
362 FunctionSelectState *state)
364 GtkTreeIter iter;
365 GtkTreeModel *model;
366 GnmFunc *func;
367 GtkTreeSelection *the_selection = gtk_tree_view_get_selection (state->treeview);
369 if (state->formula_guru_key != NULL &&
370 gtk_tree_selection_get_selected (the_selection, &model, &iter)) {
371 WBCGtk *wbcg = state->wbcg;
372 gtk_tree_model_get (model, &iter,
373 FUNCTION, &func,
374 -1);
375 dialog_function_write_recent_func (state, func);
376 state->formula_guru_key = NULL;
377 gtk_widget_destroy (state->dialog);
378 dialog_formula_guru (wbcg, func);
379 return;
382 gtk_widget_destroy (state->dialog);
383 return;
387 * cb_dialog_function_select_paste_clicked:
388 * @button:
389 * @state:
391 * Close (destroy) the dialog
393 static void
394 cb_dialog_function_select_paste_clicked (G_GNUC_UNUSED GtkWidget *button,
395 FunctionSelectState *state)
397 GtkTreeIter iter;
398 GtkTreeModel *model;
399 GnmFunc *func;
400 GtkTreeSelection *the_selection = gtk_tree_view_get_selection (state->treeview);
402 if (gtk_tree_selection_get_selected (the_selection, &model, &iter) &&
403 wbcg_edit_start (state->wbcg, FALSE, FALSE)) {
404 GtkEditable *entry
405 = GTK_EDITABLE (wbcg_get_entry (state->wbcg));
406 gint position;
407 gtk_tree_model_get (model, &iter,
408 FUNCTION, &func,
409 -1);
410 if (func != NULL) {
411 dialog_function_write_recent_func (state, func);
412 if (state->paste.from >= 0)
413 gtk_editable_select_region
414 (entry, state->paste.from,
415 state->paste.to);
416 gtk_editable_delete_selection (entry);
417 position = gtk_editable_get_position (entry);
418 gtk_editable_insert_text
419 (entry, func->name, -1, &position);
420 gtk_editable_set_position (entry, position);
424 gtk_widget_destroy (state->dialog);
425 return;
428 static void
429 cb_dialog_function_row_activated (G_GNUC_UNUSED GtkTreeView *tree_view,
430 G_GNUC_UNUSED GtkTreePath *path,
431 G_GNUC_UNUSED GtkTreeViewColumn *column,
432 FunctionSelectState *state)
434 switch (state->mode) {
435 case GURU_MODE:
436 cb_dialog_function_select_ok_clicked (NULL, state);
437 return;
438 case PASTE_MODE:
439 cb_dialog_function_select_paste_clicked (NULL, state);
440 return;
441 default:
442 return;
446 static gint
447 dialog_function_select_by_name (gconstpointer a_, gconstpointer b_,
448 gpointer user)
450 GnmFunc const * const a = (GnmFunc const * const)a_;
451 GnmFunc const * const b = (GnmFunc const * const)b_;
452 FunctionSelectState const *state = user;
453 gboolean localized = state->localized_function_names;
455 return g_utf8_collate (gnm_func_get_name (a, localized),
456 gnm_func_get_name (b, localized));
459 /*************************************************************************/
460 /* Functions related to the category selector */
461 /*************************************************************************/
463 typedef struct {
464 char const *name;
465 GtkTreeIter *iter;
466 } dialog_function_select_load_cb_t;
468 static gboolean
469 cb_dialog_function_select_load_cb (GtkTreeModel *model,
470 G_GNUC_UNUSED GtkTreePath *path,
471 GtkTreeIter *iter,
472 gpointer data)
474 dialog_function_select_load_cb_t *specs = data;
475 gchar *name;
476 gpointer ptr;
477 gboolean res;
479 gtk_tree_model_get (model, iter,
480 CAT_NAME, &name,
481 CATEGORY, &ptr,
482 -1);
484 if (ptr == NULL || ptr == GINT_TO_POINTER(-1)
485 || ptr == GINT_TO_POINTER(-2))
486 res = FALSE;
487 else if (go_utf8_collate_casefold (specs->name, name) < 0) {
488 specs->iter = gtk_tree_iter_copy (iter);
489 res = TRUE;
490 } else
491 res = FALSE;
493 g_free (name);
495 return res;
498 static void
499 dialog_function_select_load_cb (FunctionSelectState *state)
501 int i = 0;
502 GtkTreeIter p_iter;
503 GnmFuncGroup const * cat;
505 gtk_list_store_clear (state->model);
507 gtk_list_store_insert_before (state->model, &p_iter, NULL);
508 gtk_list_store_set (state->model, &p_iter,
509 CAT_NAME, _("All Functions"),
510 CATEGORY, NULL,
511 CAT_SEPARATOR, FALSE,
512 -1);
513 gtk_list_store_insert_before (state->model, &p_iter, NULL);
514 gtk_list_store_set (state->model, &p_iter,
515 CAT_NAME, _("Recently Used"),
516 CATEGORY, GINT_TO_POINTER(-1),
517 CAT_SEPARATOR, FALSE,
518 -1);
519 gtk_list_store_insert_before (state->model, &p_iter, NULL);
520 gtk_list_store_set (state->model, &p_iter,
521 CAT_NAME, _("In Use"),
522 CATEGORY, GINT_TO_POINTER(-2),
523 CAT_SEPARATOR, FALSE,
524 -1);
526 gtk_list_store_insert_before (state->model, &p_iter, NULL);
527 gtk_list_store_set (state->model, &p_iter,
528 CAT_NAME, "-",
529 CATEGORY, NULL,
530 CAT_SEPARATOR, TRUE,
531 -1);
533 while ((cat = gnm_func_group_get_nth (i++)) != NULL) {
534 dialog_function_select_load_cb_t specs;
535 specs.name = _(cat->display_name->str);
536 specs.iter = NULL;
538 gtk_tree_model_foreach (GTK_TREE_MODEL (state->model),
539 cb_dialog_function_select_load_cb,
540 &specs);
542 gtk_list_store_insert_before (state->model, &p_iter, specs.iter);
543 gtk_list_store_set (state->model, &p_iter,
544 CAT_NAME, specs.name,
545 CATEGORY, cat,
546 CAT_SEPARATOR, FALSE,
547 -1);
548 if (specs.iter != NULL)
549 gtk_tree_iter_free (specs.iter);
553 static gboolean
554 dialog_function_select_cat_row_separator (GtkTreeModel *model,
555 GtkTreeIter *iter,
556 G_GNUC_UNUSED gpointer data)
558 gboolean sep;
560 gtk_tree_model_get (model, iter,
561 CAT_SEPARATOR, &sep,
562 -1);
564 return sep;
567 /*************************************************************************/
568 /* Functions related to the description field */
569 /*************************************************************************/
571 static GtkTextTag *
572 make_link (GtkTextBuffer *description, GtkWidget *target, const char *name,
573 GCallback cb, gpointer user)
575 GtkTextTag *link =
576 gtk_text_tag_table_lookup
577 (gtk_text_buffer_get_tag_table (description), name);
579 if (!link) {
580 GdkRGBA link_color;
581 char *link_color_text;
583 gnm_get_link_color (target, &link_color);
584 link_color_text = gdk_rgba_to_string (&link_color);
586 link = gtk_text_buffer_create_tag
587 (description, name,
588 "underline", PANGO_UNDERLINE_SINGLE,
589 "foreground", link_color_text,
590 NULL);
592 g_free (link_color_text);
594 if (cb)
595 g_signal_connect (link, "event", cb, user);
598 return link;
601 static gboolean
602 cb_link_event (GtkTextTag *link, G_GNUC_UNUSED GObject *trigger,
603 GdkEvent *event, G_GNUC_UNUSED GtkTextIter *iter,
604 G_GNUC_UNUSED gpointer user)
606 switch (event->type) {
607 case GDK_BUTTON_PRESS:
608 case GDK_2BUTTON_PRESS:
609 case GDK_3BUTTON_PRESS: {
610 GdkEventButton *eb = (GdkEventButton *)event;
611 const char *uri = g_object_get_data (G_OBJECT (link), "uri");
612 GError *error = NULL;
614 if (eb->button != 1)
615 break;
616 if (event->type != GDK_BUTTON_PRESS)
617 return TRUE;
619 error = go_gtk_url_show (uri, gdk_event_get_screen (event));
620 if (error) {
621 g_printerr ("Failed to show %s\n(%s)\n",
622 uri,
623 error->message);
624 g_error_free (error);
627 return TRUE;
630 #if 0
631 case GDK_ENTER_NOTIFY:
632 case GDK_LEAVE_NOTIFY:
633 /* We aren't getting these. */
634 #endif
635 default:
636 break;
639 return FALSE;
642 static char *
643 make_expr_example (Sheet *sheet, const char *text,
644 gboolean localized, gboolean consider_format)
646 GnmLocale *oldlocale = NULL;
647 GnmExprTop const *texpr;
648 char *res;
649 GnmParsePos pp;
650 GnmEvalPos ep;
651 GnmConventions const *convs = gnm_conventions_default;
652 char *tmp_text = NULL;
653 GOFormat const *fmt = NULL;
655 if (consider_format &&
656 g_ascii_strncasecmp (text, "TEXT(", 5) == 0 &&
657 text[strlen(text) - 1] == ')') {
658 char *p;
659 tmp_text = g_strdup (text + 5);
660 p = tmp_text + strlen (tmp_text) - 1;
661 while (p >= tmp_text && p[0] != '"') p--;
662 p[0] = 0;
663 while (p >= tmp_text && p[0] != '"') p--;
664 fmt = go_format_new_from_XL (p + 1);
665 while (p >= tmp_text && p[0] != ',') p--;
666 *p = 0;
669 eval_pos_init_sheet (&ep, sheet);
670 parse_pos_init_evalpos (&pp, &ep);
672 if (!localized)
673 oldlocale = gnm_push_C_locale ();
674 texpr = gnm_expr_parse_str (text, &pp,
675 GNM_EXPR_PARSE_DEFAULT,
676 convs,
677 NULL);
678 if (!localized)
679 gnm_pop_C_locale (oldlocale);
681 if (texpr) {
682 char *etxt = gnm_expr_top_as_string (texpr, &pp, convs);
683 GnmValue *val = gnm_expr_top_eval
684 (texpr, &ep, GNM_EXPR_EVAL_PERMIT_NON_SCALAR);
685 char *vtxt;
687 if (!fmt)
688 fmt = gnm_auto_style_format_suggest (texpr, &ep);
689 vtxt = format_value (fmt, val, -1, sheet_date_conv (sheet));
691 gnm_expr_top_unref (texpr);
692 value_release (val);
694 res = g_strdup_printf (_("%s evaluates to %s."), etxt, vtxt);
696 g_free (etxt);
697 g_free (vtxt);
698 } else {
699 g_warning ("Failed to parse [%s]", text);
700 res = g_strdup ("");
703 g_free (tmp_text);
704 go_format_unref (fmt);
706 return res;
711 #define ADD_LTEXT(text,len) gtk_text_buffer_insert (description, &ti, (text), (len))
712 #define ADD_TEXT(text) ADD_LTEXT((text),-1)
713 #define ADD_BOLD_TEXT(text,len) gtk_text_buffer_insert_with_tags (description, &ti, (text), (len), bold, NULL)
714 #define ADD_LINK_TEXT(text,len) gtk_text_buffer_insert_with_tags (description, &ti, (text), (len), link, NULL)
715 #define ADD_TEXT_WITH_ARGS(text) { const char *t = text; while (*t) { const char *at = strstr (t, "@{"); \
716 if (at == NULL) { ADD_TEXT(t); break;} ADD_LTEXT(t, at - t); t = at + 2; at = strchr (t,'}'); \
717 if (at != NULL) { ADD_BOLD_TEXT(t, at - t); t = at + 1; } else {ADD_TEXT (t); break;}}}
718 #define FINISH_ARGS if (seen_args && !args_finished) {\
719 gint min, max; \
720 gnm_func_count_args (func, &min, &max);\
721 if (max == G_MAXINT) { \
722 ADD_BOLD_TEXT(UNICODE_ELLIPSIS, strlen(UNICODE_ELLIPSIS)); \
723 ADD_LTEXT("\n",1); \
724 args_finished = TRUE; \
728 static void
729 describe_new_style (GtkTextBuffer *description,
730 GtkWidget *target,
731 GnmFunc const *func, Sheet *sheet)
733 GnmFuncHelp const *help;
734 GtkTextIter ti;
735 GtkTextTag *bold =
736 gtk_text_buffer_create_tag
737 (description, NULL,
738 "weight", PANGO_WEIGHT_BOLD,
739 NULL);
740 gboolean seen_args = FALSE;
741 gboolean args_finished = FALSE;
742 gboolean seen_examples = FALSE;
743 gboolean seen_extref = FALSE;
744 gboolean is_TEXT =
745 g_ascii_strcasecmp (gnm_func_get_name (func, FALSE), "TEXT") == 0;
747 gtk_text_buffer_get_end_iter (description, &ti);
749 for (help = func->help; 1; help++) {
750 switch (help->type) {
751 case GNM_FUNC_HELP_NAME: {
752 const char *text = F2 (func, help->text);
753 const char *colon = strchr (text, ':');
754 if (!colon)
755 break;
756 ADD_BOLD_TEXT (text, colon - text);
757 ADD_TEXT (": ");
758 ADD_TEXT_WITH_ARGS (colon + 1);
759 ADD_TEXT ("\n\n");
760 break;
762 case GNM_FUNC_HELP_ARG: {
763 const char *text = F2 (func, help->text);
764 const char *colon = strchr (text, ':');
765 if (!colon)
766 break;
768 if (!seen_args) {
769 seen_args = TRUE;
770 ADD_TEXT (_("Arguments:"));
771 ADD_TEXT ("\n");
774 ADD_BOLD_TEXT (text, colon - text);
775 ADD_TEXT (": ");
776 ADD_TEXT_WITH_ARGS (colon + 1);
777 ADD_TEXT ("\n");
778 break;
780 case GNM_FUNC_HELP_DESCRIPTION: {
781 const char *text = F2 (func, help->text);
782 FINISH_ARGS;
783 ADD_TEXT ("\n");
784 ADD_TEXT_WITH_ARGS (text);
785 ADD_TEXT ("\n");
786 break;
788 case GNM_FUNC_HELP_NOTE: {
789 const char *text = F2 (func, help->text);
790 FINISH_ARGS;
791 ADD_TEXT ("\n");
792 ADD_TEXT (_("Note: "));
793 ADD_TEXT_WITH_ARGS (text);
794 ADD_TEXT ("\n");
795 break;
797 case GNM_FUNC_HELP_EXAMPLES: {
798 const char *text = F2 (func, help->text);
799 gboolean was_translated = (text != help->text);
801 FINISH_ARGS;
802 if (!seen_examples) {
803 seen_examples = TRUE;
804 ADD_TEXT ("\n");
805 ADD_TEXT (_("Examples:"));
806 ADD_TEXT ("\n");
809 if (text[0] == '=') {
810 char *example =
811 make_expr_example (sheet, text + 1,
812 was_translated,
813 !is_TEXT);
814 ADD_TEXT (example);
815 g_free (example);
816 } else {
817 ADD_TEXT_WITH_ARGS (text);
819 ADD_TEXT ("\n");
820 break;
822 case GNM_FUNC_HELP_SEEALSO: {
823 const char *text = help->text; /* Not translated */
824 const char *pre = _("See also: ");
825 GtkTextTag *link =
826 make_link (description, target, "LINK",
827 NULL, NULL);
829 FINISH_ARGS;
830 ADD_TEXT ("\n");
832 while (*text) {
833 const char *end = strchr (text, ',');
834 if (!end) end = text + strlen (text);
836 ADD_TEXT (pre);
837 ADD_LINK_TEXT (text, end - text);
839 text = *end ? end + 1 : end;
841 pre = _(", ");
843 ADD_TEXT ("\n");
844 break;
846 case GNM_FUNC_HELP_END:
847 FINISH_ARGS;
848 return;
849 case GNM_FUNC_HELP_EXTREF: {
850 GtkTextTag *link;
851 char *uri, *tagname;
852 const char *text;
854 FINISH_ARGS;
856 * We put in just one link and let the web page handle
857 * the rest. In particular, we do not even look at
858 * what the help->text is here.
860 if (seen_extref)
861 break;
863 uri = g_strdup_printf ("http://www.gnumeric.org/func-doc.shtml?%s", func->name);
865 tagname = g_strdup_printf ("EXTLINK-%s", func->name);
866 link = make_link
867 (description, target, tagname,
868 G_CALLBACK (cb_link_event), NULL);
870 g_object_set_data_full (G_OBJECT (link),
871 "uri", uri,
872 g_free);
874 ADD_TEXT (_("Further information: "));
876 text = _("online descriptions");
877 ADD_LINK_TEXT (text, strlen (text));
879 ADD_TEXT (".\n");
881 seen_extref = TRUE;
882 break;
884 case GNM_FUNC_HELP_EXCEL: {
885 const char *text = F2 (func, help->text);
886 FINISH_ARGS;
887 ADD_TEXT ("\n");
888 ADD_TEXT (_("Microsoft Excel: "));
889 ADD_TEXT_WITH_ARGS (text);
890 ADD_TEXT ("\n");
891 break;
893 case GNM_FUNC_HELP_ODF: {
894 const char *text = F2 (func, help->text);
895 FINISH_ARGS;
896 ADD_TEXT ("\n");
897 ADD_TEXT (_("ODF (OpenFormula): "));
898 ADD_TEXT_WITH_ARGS (text);
899 ADD_TEXT ("\n");
900 break;
902 default:
903 break;
908 #undef ADD_TEXT_WITH_ARGS
909 #undef ADD_TEXT
910 #undef ADD_LTEXT
911 #undef ADD_BOLD_TEXT
912 #undef ADD_LINK_TEXT
913 #undef FINISH_ARGS
915 typedef struct {
916 GnmFunc *fd;
917 FunctionSelectState *state;
918 GtkTreePath *path;
919 } dialog_function_select_find_func_t;
922 static gboolean
923 dialog_function_select_search_func (GtkTreeModel *model,
924 GtkTreePath *path,
925 GtkTreeIter *iter,
926 gpointer dt)
928 GnmFunc* fd;
929 dialog_function_select_find_func_t *data = dt;
931 gtk_tree_model_get (model, iter,
932 FUNCTION, &fd,
933 -1);
934 if (fd == data->fd) {
935 data->path = gtk_tree_path_copy (path);
936 return TRUE;
938 return FALSE;
941 static void
942 dialog_function_select_find_func (FunctionSelectState *state, char* name)
944 GnmFunc *fd;
946 if (name == NULL)
947 return;
949 fd = gnm_func_lookup (name, state->wb);
950 if (fd != NULL) {
951 dialog_function_select_find_func_t data = {fd, state, NULL};
952 GtkTreeSelection *selection = gtk_tree_view_get_selection
953 (state->treeview);
954 GtkTreePath *path;
956 gtk_tree_model_foreach (GTK_TREE_MODEL (state->model_functions),
957 dialog_function_select_search_func,
958 &data);
959 if (data.path != NULL) {
960 GtkTreeIter iter;
961 if (gtk_tree_model_get_iter
962 (GTK_TREE_MODEL (state->model_functions), &iter,
963 data.path))
964 gtk_list_store_set (state->model_functions,
965 &iter,
966 FUNCTION_VISIBLE, TRUE,
967 -1);
969 path = gtk_tree_model_filter_convert_child_path_to_path
970 (GTK_TREE_MODEL_FILTER (state->model_filter),
971 data.path);
973 gtk_tree_selection_select_path (selection,
974 path);
975 gtk_tree_view_scroll_to_cell (state->treeview, path,
976 NULL, FALSE, 0., 0.);
977 gtk_tree_path_free (path);
978 gtk_tree_path_free (data.path);
979 } else
980 g_warning ("Function %s was not found in its category", name);
982 } else
983 g_warning ("Function %s was not found", name);
986 typedef struct {
987 FunctionSelectState *state;
988 gchar * name;
989 } cb_dialog_function_select_idle_handler_t;
991 static gboolean
992 cb_dialog_function_select_idle_handler (gpointer dt)
994 cb_dialog_function_select_idle_handler_t *data = dt;
996 dialog_function_select_find_func (data->state, data->name);
998 g_free (data->name);
999 g_free (data);
1001 return FALSE;
1004 static void
1005 cb_description_clicked (GtkTextBuffer *textbuffer,
1006 GtkTextIter *location,
1007 GtkTextMark *mark,
1008 FunctionSelectState *state)
1010 const char * mark_name;
1011 GtkTextTag *link;
1012 GtkTextIter *start;
1013 GtkTextIter *end;
1014 cb_dialog_function_select_idle_handler_t *data;
1016 if ((mark == NULL) || ((mark_name = gtk_text_mark_get_name (mark)) == NULL)
1017 || (strcmp(mark_name, "selection_bound") != 0))
1018 return;
1020 link = gtk_text_tag_table_lookup
1021 (gtk_text_buffer_get_tag_table (textbuffer), "LINK");
1023 if ((link == NULL) || !gtk_text_iter_has_tag (location, link))
1024 return;
1026 start = gtk_text_iter_copy (location);
1027 end = gtk_text_iter_copy (location);
1029 if (!gtk_text_iter_begins_tag (start, link))
1030 gtk_text_iter_backward_to_tag_toggle (start, link);
1031 if (!gtk_text_iter_ends_tag (end, link))
1032 gtk_text_iter_forward_to_tag_toggle (end, link);
1034 data = g_new(cb_dialog_function_select_idle_handler_t, 1);
1036 data->name = gtk_text_buffer_get_text (textbuffer, start, end, FALSE);
1037 gtk_text_iter_free (start);
1038 gtk_text_iter_free (end);
1039 data->state = state;
1041 g_idle_add_full (G_PRIORITY_HIGH_IDLE, cb_dialog_function_select_idle_handler,
1042 data, NULL);
1045 static void
1046 cb_dialog_function_select_fun_selection_changed (GtkTreeSelection *selection,
1047 FunctionSelectState *state)
1049 GtkTreeIter iter;
1050 GtkTreeModel *model;
1051 GnmFunc const *func;
1052 GtkTextBuffer *description;
1053 GtkTextMark *mark;
1054 gboolean active = FALSE;
1056 description = gtk_text_view_get_buffer (state->description_view);
1058 mark = gtk_text_buffer_get_mark (description, "start-mark");
1059 gtk_text_view_scroll_to_mark (state->description_view, mark,
1060 0.1, TRUE, 0.0, 0.0);
1061 gtk_text_buffer_set_text (description, "", 0);
1063 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
1064 gtk_tree_model_get (model, &iter,
1065 FUNCTION, &func,
1066 -1);
1068 gnm_func_load_if_stub ((GnmFunc *)func);
1070 if (func->help == NULL)
1071 gtk_text_buffer_set_text (description, "?", -1);
1072 else
1073 describe_new_style (description,
1074 GTK_WIDGET (state->description_view),
1075 func, state->sheet);
1076 active = TRUE;
1078 gtk_widget_set_sensitive (state->ok_button, active);
1079 gtk_widget_set_sensitive (state->paste_button, active);
1083 /**********************************************************************/
1084 /* Setup Functions */
1085 /**********************************************************************/
1087 static const gchar *
1088 dialog_function_select_peek_description (GnmFunc *func)
1090 GnmFuncHelp const *help;
1092 gnm_func_load_if_stub (func);
1093 help = func->help;
1095 if (help == NULL)
1096 return "";
1098 for (; TRUE; help++) {
1099 switch (help->type) {
1100 case GNM_FUNC_HELP_ARG:
1101 case GNM_FUNC_HELP_NOTE:
1102 case GNM_FUNC_HELP_EXAMPLES:
1103 case GNM_FUNC_HELP_SEEALSO:
1104 case GNM_FUNC_HELP_EXTREF:
1105 case GNM_FUNC_HELP_EXCEL:
1106 case GNM_FUNC_HELP_ODF:
1107 case GNM_FUNC_HELP_DESCRIPTION:
1108 default:
1109 break;
1110 case GNM_FUNC_HELP_NAME: {
1111 const char *text = F2 (func, help->text);
1112 const char *colon = strchr (text, ':');
1113 return (colon ? colon + 1 : text);
1115 case GNM_FUNC_HELP_END:
1116 return "";
1122 static gchar *
1123 dialog_function_select_get_description (GnmFunc *func, PangoAttrList **pal)
1125 PangoAttribute *attr;
1126 char const *desc = dialog_function_select_peek_description (func);
1127 char const *here;
1128 GString* gstr = g_string_new (NULL);
1130 *pal = pango_attr_list_new ();
1132 if (desc != NULL) {
1133 while (*desc != '\0') {
1134 here = strstr (desc, "@{");
1135 if (here == NULL) {
1136 g_string_append (gstr, desc);
1137 break;
1139 g_string_append_len (gstr, desc, here - desc);
1140 attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
1141 attr->start_index = gstr->len;
1142 desc = here + 2;
1143 here = strchr (desc,'}');
1144 if (here == NULL) {
1145 g_string_append (gstr, desc);
1146 pango_attr_list_insert (*pal, attr);
1147 break;
1149 g_string_append_len (gstr, desc, here - desc);
1150 attr->end_index = gstr->len;
1151 pango_attr_list_insert (*pal, attr);
1152 desc = here + 1;
1156 return g_string_free (gstr, FALSE);
1161 static void
1162 dialog_function_select_load_tree (FunctionSelectState *state)
1164 GtkTreeIter iter;
1165 GnmFuncGroup const * cat;
1166 GSList *funcs = NULL, *ptr;
1167 GnmFunc *func;
1168 gint i = 0;
1169 PangoAttrList *pal;
1170 gchar *desc;
1172 gtk_list_store_clear (state->model_functions);
1174 while ((cat = gnm_func_group_get_nth (i++)) != NULL)
1175 funcs = g_slist_concat (funcs,
1176 g_slist_copy (cat->functions));
1178 funcs = g_slist_sort_with_data (funcs,
1179 dialog_function_select_by_name,
1180 state);
1182 for (ptr = funcs; ptr; ptr = ptr->next) {
1183 func = ptr->data;
1184 if (!(func->flags &
1185 (GNM_FUNC_INTERNAL | GNM_FUNC_IS_PLACEHOLDER))) {
1186 gtk_list_store_append (state->model_functions, &iter);
1187 gnm_func_ref (func);
1188 desc = dialog_function_select_get_description (func, &pal);
1189 gtk_list_store_set
1190 (state->model_functions, &iter,
1191 FUN_NAME, gnm_func_get_name (func, state->localized_function_names),
1192 FUNCTION, func,
1193 FUNCTION_DESC, desc,
1194 FUNCTION_PAL, pal,
1195 FUNCTION_CAT, func->fn_group,
1196 FUNCTION_VISIBLE, TRUE,
1197 FUNCTION_RECENT, FALSE,
1198 FUNCTION_USED, (func->usage_count > 1),
1199 -1);
1200 g_free (desc);
1201 pango_attr_list_unref (pal);
1206 g_slist_free (funcs);
1209 static void
1210 dialog_function_select_init (FunctionSelectState *state)
1212 GtkTreeViewColumn *column;
1213 GtkTreeSelection *selection;
1214 GtkTextIter where;
1215 GtkTextBuffer *description;
1216 GtkCellRenderer *cell;
1217 GtkWidget *cancel_button;
1218 GtkWidget *close_button;
1220 g_object_set_data (G_OBJECT (state->dialog), FUNCTION_SELECT_DIALOG_KEY,
1221 state);
1223 /* Set-up combo box */
1224 state->cb = GTK_COMBO_BOX
1225 (go_gtk_builder_get_widget (state->gui, "category-box"));
1226 state->model = gtk_list_store_new
1227 (NUM_CAT_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
1229 gtk_combo_box_set_model (state->cb, GTK_TREE_MODEL (state->model));
1230 g_object_unref (state->model);
1231 cell = gtk_cell_renderer_text_new ();
1232 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (state->cb), cell, TRUE);
1233 gtk_cell_layout_add_attribute
1234 (GTK_CELL_LAYOUT (state->cb), cell, "text", CAT_NAME);
1235 dialog_function_select_load_cb (state);
1236 gtk_combo_box_set_row_separator_func
1237 (state->cb, dialog_function_select_cat_row_separator,
1238 state, NULL);
1239 g_signal_connect (state->cb, "changed",
1240 G_CALLBACK (dialog_function_select_cat_changed),
1241 state);
1242 /* Finished set-up of combo box */
1244 /* Set-up treeview */
1246 state->model_functions = gtk_list_store_new
1247 (NUM_COLUMNS,
1248 /* FUN_NAME, */
1249 /* FUNCTION, */
1250 /* FUNCTION_DESC, */
1251 /* FUNCTION_PAL, */
1252 /* FUNCTION_CAT, */
1253 /* FUNCTION_VISIBLE, */
1254 /* FUNCTION_RECENT, */
1255 /* FUNCTION_USED, */
1256 G_TYPE_STRING, G_TYPE_POINTER,
1257 G_TYPE_STRING, PANGO_TYPE_ATTR_LIST,
1258 G_TYPE_POINTER, G_TYPE_BOOLEAN,
1259 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
1261 state->model_filter = gtk_tree_model_filter_new
1262 (GTK_TREE_MODEL (state->model_functions), NULL);
1263 g_object_unref (state->model_functions);
1264 gtk_tree_model_filter_set_visible_column
1265 (GTK_TREE_MODEL_FILTER (state->model_filter), FUNCTION_VISIBLE);
1267 state->treeview = GTK_TREE_VIEW
1268 (go_gtk_builder_get_widget (state->gui, "function-list"));
1269 gtk_tree_view_set_model (state->treeview,
1270 state->model_filter);
1271 g_object_unref (state->model_filter);
1273 selection = gtk_tree_view_get_selection (state->treeview);
1274 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1275 g_signal_connect (selection, "changed",
1276 G_CALLBACK
1277 (cb_dialog_function_select_fun_selection_changed),
1278 state);
1280 column = gtk_tree_view_column_new_with_attributes
1281 (_("Name"),
1282 gtk_cell_renderer_text_new (),
1283 "text", FUN_NAME, NULL);
1284 gtk_tree_view_append_column (state->treeview, column);
1285 column = gtk_tree_view_column_new_with_attributes
1286 (_("Description"),
1287 gtk_cell_renderer_text_new (),
1288 "text", FUNCTION_DESC,
1289 "attributes", FUNCTION_PAL, NULL);
1290 gtk_tree_view_append_column (state->treeview, column);
1292 gtk_tree_view_set_headers_visible (state->treeview, FALSE);
1293 /* Finished set-up of treeview */
1295 dialog_function_select_load_tree (state);
1296 dialog_function_load_recent_funcs (state);
1298 state->search_entry = go_gtk_builder_get_widget (state->gui,
1299 "search-entry");
1300 if (state->paste.prefix != NULL)
1301 gtk_entry_set_text (GTK_ENTRY (state->search_entry),
1302 state->paste.prefix);
1304 g_signal_connect (G_OBJECT (state->search_entry),
1305 "icon-press",
1306 G_CALLBACK
1307 (dialog_function_select_erase_search_entry),
1308 state);
1310 g_signal_connect (G_OBJECT (state->search_entry),
1311 "activate",
1312 G_CALLBACK (dialog_function_select_search),
1313 state);
1314 if (state->mode != HELP_MODE)
1315 g_signal_connect (G_OBJECT (state->treeview),
1316 "row-activated",
1317 G_CALLBACK (cb_dialog_function_row_activated),
1318 state);
1320 gtk_paned_set_position (GTK_PANED (go_gtk_builder_get_widget
1321 (state->gui, "vpaned1")), 300);
1323 state->description_view = GTK_TEXT_VIEW (go_gtk_builder_get_widget
1324 (state->gui, "description"));
1325 gtk_style_context_add_class
1326 (gtk_widget_get_style_context (GTK_WIDGET (state->description_view)),
1327 "function-help");
1328 description = gtk_text_view_get_buffer (state->description_view);
1329 gtk_text_buffer_get_start_iter (description, &where);
1330 gtk_text_buffer_create_mark (description, "start-mark", &where, TRUE);
1332 g_signal_connect_after (G_OBJECT (description),
1333 "mark-set",
1334 G_CALLBACK (cb_description_clicked), state);
1336 state->ok_button = go_gtk_builder_get_widget (state->gui, "ok_button");
1337 gtk_widget_set_sensitive (state->ok_button, FALSE);
1338 g_signal_connect (G_OBJECT (state->ok_button),
1339 "clicked",
1340 G_CALLBACK (cb_dialog_function_select_ok_clicked), state);
1341 state->paste_button = go_gtk_builder_get_widget (state->gui, "paste_button");
1342 gtk_widget_set_sensitive (state->paste_button, FALSE);
1343 g_signal_connect (G_OBJECT (state->paste_button),
1344 "clicked",
1345 G_CALLBACK (cb_dialog_function_select_paste_clicked), state);
1346 cancel_button = go_gtk_builder_get_widget (state->gui, "cancel_button");
1347 g_signal_connect (G_OBJECT (cancel_button), "clicked",
1348 G_CALLBACK (cb_dialog_function_select_cancel_clicked), state);
1349 close_button = go_gtk_builder_get_widget (state->gui, "close_button");
1350 g_signal_connect (G_OBJECT (close_button), "clicked",
1351 G_CALLBACK (cb_dialog_function_select_cancel_clicked), state);
1353 gnm_dialog_setup_destroy_handlers
1354 (GTK_DIALOG (state->dialog),
1355 state->wbcg,
1356 GNM_DIALOG_DESTROY_CURRENT_SHEET_REMOVED);
1358 gnm_init_help_button (
1359 go_gtk_builder_get_widget (state->gui, "help_button"),
1360 GNUMERIC_HELP_LINK_FUNCTION_SELECT);
1361 g_object_set_data_full
1362 (G_OBJECT (state->dialog),
1363 "state", state,
1364 (GDestroyNotify) cb_dialog_function_select_destroy);
1366 if (state->paste.prefix != NULL)
1367 dialog_function_select_search
1368 (GTK_ENTRY (state->search_entry), state);
1370 gtk_widget_set_visible (close_button, state->mode != GURU_MODE);
1371 gtk_widget_set_visible (go_gtk_builder_get_widget
1372 (state->gui, "help_button"),
1373 state->mode == GURU_MODE);
1374 gtk_widget_set_visible (cancel_button, state->mode == GURU_MODE);
1375 gtk_widget_set_visible (state->ok_button, state->mode == GURU_MODE);
1376 gtk_widget_set_visible (state->paste_button, state->mode == PASTE_MODE);
1377 gtk_widget_set_visible (go_gtk_builder_get_widget
1378 (state->gui, "title_label"),
1379 state->mode == GURU_MODE);
1380 gtk_combo_box_set_active (state->cb, state->mode == HELP_MODE ? 2 : 0);
1381 switch (state->mode) {
1382 case GURU_MODE:
1383 break;
1384 case HELP_MODE:
1385 gtk_window_set_title (GTK_WINDOW (state->dialog),
1386 _("Gnumeric Function Help Browser"));
1387 break;
1388 case PASTE_MODE:
1389 gtk_window_set_title (GTK_WINDOW (state->dialog),
1390 _("Paste Function Name dialog"));
1391 break;
1395 static void
1396 dialog_function_select_full (WBCGtk *wbcg, char const *guru_key,
1397 char const *key, DialogMode mode, gint from, gint to)
1399 FunctionSelectState* state;
1400 GtkBuilder *gui;
1402 g_return_if_fail (wbcg != NULL);
1404 if (gnm_dialog_raise_if_exists (wbcg, key))
1405 return;
1406 gui = gnm_gtk_builder_load ("function-select.ui", NULL, GO_CMD_CONTEXT (wbcg));
1407 if (gui == NULL)
1408 return;
1410 state = g_new (FunctionSelectState, 1);
1411 state->wbcg = wbcg;
1412 state->sheet = wb_control_cur_sheet (GNM_WBC (wbcg));
1413 state->localized_function_names = state->sheet->convs->localized_function_names;
1414 state->wb = state->sheet->workbook;
1415 state->gui = gui;
1416 state->dialog = go_gtk_builder_get_widget (state->gui, "selection_dialog");
1417 state->formula_guru_key = guru_key;
1418 state->recent_funcs = NULL;
1419 state->mode = mode;
1420 state->paste.from = from;
1421 state->paste.to = to;
1423 gnm_dialog_setup_destroy_handlers (GTK_DIALOG (state->dialog),
1424 state->wbcg,
1425 GNM_DIALOG_DESTROY_SHEET_REMOVED);
1427 if (mode == PASTE_MODE && state->paste.from >= 0) {
1428 GtkEditable *entry
1429 = GTK_EDITABLE (wbcg_get_entry (state->wbcg));
1430 state->paste.prefix = gtk_editable_get_chars
1431 (entry, state->paste.from,
1432 state->paste.to);
1433 } else
1434 state->paste.prefix = NULL;
1436 dialog_function_select_init (state);
1437 gnm_keyed_dialog (state->wbcg, GTK_WINDOW (state->dialog),
1438 key);
1440 gtk_widget_show (state->dialog);
1443 void
1444 dialog_function_select (WBCGtk *wbcg, char const *key)
1446 dialog_function_select_full (wbcg, key,
1447 FUNCTION_SELECT_KEY, GURU_MODE, -1, -1);
1450 void
1451 dialog_function_select_help (WBCGtk *wbcg)
1453 dialog_function_select_full (wbcg, NULL,
1454 FUNCTION_SELECT_HELP_KEY, HELP_MODE,
1455 -1, -1);
1458 void
1459 dialog_function_select_paste (WBCGtk *wbcg, gint from, gint to)
1461 dialog_function_select_full (wbcg, NULL,
1462 FUNCTION_SELECT_PASTE_KEY, PASTE_MODE,
1463 from, to);