1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * dialog-function-wizard.c: The formula guru
6 * Jody Goldberg <jody@gnome.org>
7 * Andreas J. Guelzow <aguelzow@taliesin.ca>
9 * Copyright (C) 2000 Jody Goldberg (jody@gnome.org)
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of the
14 * License, or (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, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
26 #include <gnumeric-config.h>
27 #include <glib/gi18n-lib.h>
32 #include <parse-util.h>
36 #include <sheet-view.h>
38 #include <workbook-control.h>
41 #include <expr-impl.h>
42 #include <expr-name.h>
44 #include <gnm-format.h>
45 #include <goffice/goffice.h>
46 #include <widgets/gnumeric-expr-entry.h>
47 #include <widgets/gnumeric-cell-renderer-expr-entry.h>
53 #define FORMULA_GURU_KEY "formula-guru-dialog"
54 #define FORMULA_GURU_KEY_DIALOG "formula-guru-dialog"
56 #define MIN_VAR_ARGS_DISPLAYED 2
57 #define AV_FORMULA_SIZE 100
67 GtkWidget
*selector_button
;
68 GtkWidget
*clear_button
;
69 GtkWidget
*zoom_button
;
70 GtkWidget
*array_button
;
71 GtkWidget
*main_button_area
;
72 GtkWidget
*quote_button
;
73 GtkTreePath
* active_path
;
79 GtkTreeView
*treeview
;
80 GtkWidget
*tooltip_widget
;
81 GtkWidget
*tooltip_label
;
85 gint old_height_request
;
86 gint old_width_request
;
88 GnumericCellRendererExprEntry
*cellrenderer
;
89 GtkTreeViewColumn
*column
;
90 GtkCellEditable
*editable
;
105 static void dialog_formula_guru_update_parent (GtkTreeIter
*child
, FormulaGuruState
*state
,
107 gint sel_start
, gint sel_length
);
110 dialog_formula_guru_write (GString
*text
, FormulaGuruState
*state
, gint sel_start
,
115 entry
= wbcg_get_entry (state
->wbcg
);
117 sel_start
+= g_utf8_strlen (state
->prefix
, -1);
118 g_string_prepend (text
, state
->prefix
);
121 g_string_append (text
, state
->suffix
);
122 gtk_entry_set_text (entry
, text
->str
);
123 gtk_editable_select_region (GTK_EDITABLE (entry
), sel_start
, sel_start
+ sel_length
);
127 dialog_formula_guru_delete_children (GtkTreeIter
*parent
, FormulaGuruState
*state
)
131 while (gtk_tree_model_iter_children (GTK_TREE_MODEL(state
->model
),
133 gtk_tree_store_remove (state
->model
, &iter
);
137 dialog_formula_guru_update_this_parent (GtkTreeIter
*parent
, FormulaGuruState
*state
,
138 GtkTreePath
*origin
, gint sel_start
, gint sel_length
)
140 GString
*text
= g_string_sized_new (AV_FORMULA_SIZE
);
144 gboolean not_first
= FALSE
;
145 int arg_min
, arg_num
= 0;
146 gboolean find_origin
= TRUE
;
148 gtk_tree_model_get (GTK_TREE_MODEL(state
->model
), parent
,
149 IS_NON_FUN
, &is_non_fun
,
154 g_return_if_fail (!is_non_fun
);
155 g_return_if_fail (fd
!= NULL
);
157 g_string_append (text
, gnm_func_get_name (fd
, sheet_get_conventions (state
->pos
->sheet
)->localized_function_names
));
158 g_string_append (text
, "(");
160 if (gtk_tree_model_iter_children (GTK_TREE_MODEL(state
->model
), &iter
, parent
)) {
163 gtk_tree_model_get (GTK_TREE_MODEL(state
->model
), &iter
,
164 FUN_ARG_ENTRY
, &argument
,
166 if ((argument
== NULL
|| g_utf8_strlen (argument
, -1) == 0) && arg_num
> arg_min
) {
172 g_string_append_c (text
, go_locale_get_arg_sep ());
175 if (find_origin
&& origin
!= NULL
) {
176 GtkTreePath
*b
= gtk_tree_model_get_path
177 (GTK_TREE_MODEL (state
->model
), &iter
);
178 if (0 == gtk_tree_path_compare (origin
, b
)) {
179 sel_start
+= g_utf8_strlen (text
->str
, text
->len
);
180 gtk_tree_path_free (origin
);
181 origin
= gtk_tree_model_get_path
182 (GTK_TREE_MODEL (state
->model
), parent
);
185 gtk_tree_path_free (b
);
187 if (argument
&& strlen (argument
) > 0) {
188 GnmExprTop
const *texpr
= gnm_expr_parse_str
189 (argument
, state
->pos
,
190 GNM_EXPR_PARSE_DEFAULT
,
191 sheet_get_conventions (state
->pos
->sheet
),
194 g_string_append_c (text
, '"');
195 g_string_append (text
, argument
);
196 g_string_append_c (text
, '"');
198 if ((GNM_EXPR_GET_OPER (texpr
->expr
) == GNM_EXPR_OP_NAME
)
199 && expr_name_is_placeholder (texpr
->expr
->name
.name
)
200 && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state
->quote_button
))) {
201 g_string_append_c (text
, '"');
202 g_string_append (text
, argument
);
203 g_string_append_c (text
, '"');
205 g_string_append (text
, argument
);
206 gnm_expr_top_unref (texpr
);
213 } while (gtk_tree_model_iter_next (GTK_TREE_MODEL(state
->model
), &iter
));
216 g_string_append_c (text
, ')');
218 gtk_tree_store_set (state
->model
, parent
,
219 FUN_ARG_ENTRY
, text
->str
,
221 if (origin
== NULL
) {
223 sel_length
= g_utf8_strlen (text
->str
, text
->len
);
224 origin
= gtk_tree_model_get_path (GTK_TREE_MODEL(state
->model
), parent
);
227 if (0 == gtk_tree_store_iter_depth (state
->model
, parent
))
228 dialog_formula_guru_write (text
, state
, sel_start
, sel_length
);
230 g_string_free (text
, TRUE
);
232 dialog_formula_guru_update_parent (parent
, state
, origin
, sel_start
, sel_length
);
236 dialog_formula_guru_update_parent (GtkTreeIter
*child
, FormulaGuruState
*state
,
237 GtkTreePath
*origin
, gint sel_start
, gint sel_length
)
241 if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (state
->model
), &iter
,
243 dialog_formula_guru_update_this_parent (&iter
, state
, origin
, sel_start
,
246 gtk_tree_path_free (origin
);
250 dialog_formula_guru_update_this_child (GtkTreeIter
*child
, FormulaGuruState
*state
,
251 GtkTreePath
*origin
, gint sel_start
, gint sel_length
)
256 if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (state
->model
), &iter
,
258 if (origin
== NULL
) {
260 gtk_tree_model_get (GTK_TREE_MODEL(state
->model
), child
,
261 FUN_ARG_ENTRY
, &text
,
263 sel_length
= g_utf8_strlen (text
, -1);
265 origin
= gtk_tree_model_get_path (GTK_TREE_MODEL(state
->model
), child
);
267 dialog_formula_guru_update_this_parent (&iter
, state
, origin
, sel_start
,
274 dialog_formula_guru_adjust_children (GtkTreeIter
*parent
, GnmFunc
const *fd
,
275 FormulaGuruState
*state
)
279 gint min_arg
, max_arg
, args
= 0, i
;
284 gtk_tree_model_get (GTK_TREE_MODEL(state
->model
), parent
,
285 IS_NON_FUN
, &is_non_fun
,
289 while (gtk_tree_model_iter_children (GTK_TREE_MODEL(state
->model
),
291 gtk_tree_store_remove (state
->model
, &iter
);
295 g_return_if_fail (fd
!= NULL
);
297 gtk_tree_model_get (GTK_TREE_MODEL(state
->model
), parent
,
301 if (max_arg
== G_MAXINT
) {
302 args
= MAX (MIN_VAR_ARGS_DISPLAYED
+ min_arg
,
303 gtk_tree_model_iter_n_children (GTK_TREE_MODEL(state
->model
),
308 while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL(state
->model
),
309 &iter
, parent
, args
))
310 gtk_tree_store_remove (state
->model
, &iter
);
311 for (i
= 0; i
< args
; i
++) {
312 if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL(state
->model
),
314 gtk_tree_store_append (state
->model
, &iter
, parent
);
315 gtk_tree_store_set (state
->model
, &iter
,
323 arg_name
= gnm_func_get_arg_name (fd
, i
);
324 if (i
>= min_arg
&& arg_name
!= NULL
) {
325 char *mod_name
= g_strdup_printf (_("[%s]"), arg_name
);
330 gtk_tree_store_set (state
->model
, &iter
,
332 ARG_TOOLTIP
, gnm_func_get_arg_description (fd
, i
),
333 ARG_TYPE
, gnm_func_get_arg_type_string (fd
, i
),
338 dialog_formula_guru_update_this_parent (parent
, state
, NULL
, 0, 0);
343 dialog_formula_guru_adjust_varargs (GtkTreeIter
*iter
, FormulaGuruState
*state
)
345 GtkTreeIter new_iter
, parent
;
346 char *arg_name
, *arg_type
;
350 if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (state
->model
), &new_iter
) &&
351 gtk_tree_model_iter_parent (GTK_TREE_MODEL (state
->model
), &parent
, iter
)) {
352 gtk_tree_model_get (GTK_TREE_MODEL (state
->model
), &parent
,
355 if (max_arg
== G_MAXINT
) {
356 gtk_tree_model_get (GTK_TREE_MODEL (state
->model
), iter
,
360 gtk_tree_store_insert_after (state
->model
, &new_iter
, &parent
, iter
);
361 gtk_tree_store_set (state
->model
, &new_iter
,
379 dialog_formula_guru_load_fd (GtkTreePath
*path
, GnmFunc
*fd
,
380 FormulaGuruState
*state
)
383 gint min_arg
, max_arg
;
384 GtkTreePath
*new_path
;
386 gnm_func_load_if_stub (fd
);
389 gtk_tree_store_clear (state
->model
);
390 gtk_tree_store_append (state
->model
, &iter
, NULL
);
391 } else if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (state
->model
), &iter
, path
)) {
392 GtkTreePath
*new_path
= gtk_tree_path_copy (path
);
393 if (gtk_tree_path_prev (new_path
) &&
394 gtk_tree_model_get_iter (GTK_TREE_MODEL (state
->model
),
396 dialog_formula_guru_adjust_varargs (&iter
, state
);
397 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (state
->model
),
399 gtk_tree_store_clear (state
->model
);
400 gtk_tree_path_free (new_path
);
404 gtk_tree_store_clear (state
->model
);
405 gtk_tree_path_free (new_path
);
408 gtk_tree_path_free (new_path
);
411 gnm_func_count_args (fd
, &min_arg
, &max_arg
);
413 gtk_tree_store_set (state
->model
, &iter
,
420 dialog_formula_guru_adjust_children (&iter
, fd
, state
);
421 dialog_formula_guru_adjust_varargs (&iter
, state
);
423 new_path
= gtk_tree_model_get_path (GTK_TREE_MODEL (state
->model
),
425 gtk_tree_view_expand_row (state
->treeview
, new_path
, FALSE
);
426 gtk_tree_path_free (new_path
);
432 dialog_formula_guru_load_string (GtkTreePath
* path
,
433 char const *argument
, FormulaGuruState
*state
)
436 gboolean okay
= TRUE
;
438 g_return_if_fail (path
!= NULL
);
440 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (state
->model
),
442 GtkTreePath
*new_path
= gtk_tree_path_copy (path
);
444 if (gtk_tree_path_prev (new_path
) &&
445 gtk_tree_model_get_iter (GTK_TREE_MODEL (state
->model
),
447 dialog_formula_guru_adjust_varargs (&iter
, state
);
448 okay
= gtk_tree_model_get_iter (GTK_TREE_MODEL (state
->model
),
452 gtk_tree_path_free (new_path
);
455 g_return_if_fail (okay
);
457 dialog_formula_guru_delete_children (&iter
, state
);
458 gtk_tree_store_set (state
->model
, &iter
,
459 FUN_ARG_ENTRY
, argument
? argument
: "",
466 dialog_formula_guru_update_parent (&iter
, state
, gtk_tree_model_get_path
467 (GTK_TREE_MODEL (state
->model
), &iter
),
468 0, argument
? g_utf8_strlen (argument
, -1) : 0);
472 dialog_formula_guru_load_expr (GtkTreePath
const *parent_path
, gint child_num
,
473 GnmExpr
const *expr
, FormulaGuruState
*state
)
477 if (parent_path
== NULL
)
478 path
= gtk_tree_path_new_first ();
480 /* gtk_tree_path_copy should have a const argument */
481 path
= gtk_tree_path_copy ((GtkTreePath
*) parent_path
);
482 gtk_tree_path_append_index (path
, child_num
);
485 switch (GNM_EXPR_GET_OPER (expr
)) {
486 case GNM_EXPR_OP_FUNCALL
: {
490 max_arg
= dialog_formula_guru_load_fd (path
, expr
->func
.func
, state
);
491 if (max_arg
> expr
->func
.argc
)
492 max_arg
= expr
->func
.argc
;
493 for (i
= 0; i
< max_arg
; i
++)
494 dialog_formula_guru_load_expr (path
, i
,
497 gtk_tree_path_append_index (path
, MAX (0, i
- 1));
498 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (state
->model
),
500 dialog_formula_guru_adjust_varargs (&iter
, state
);
505 case GNM_EXPR_OP_ANY_BINARY
:
506 case GNM_EXPR_OP_UNARY_NEG
:
508 char *text
= gnm_expr_as_string (expr
, state
->pos
,
509 sheet_get_conventions (state
->pos
->sheet
));
510 dialog_formula_guru_load_string (path
, text
, state
);
516 gtk_tree_path_free (path
);
520 cb_dialog_formula_guru_destroy (FormulaGuruState
*state
)
522 wbcg_edit_finish (state
->wbcg
, WBC_EDIT_REJECT
, NULL
);
524 if (state
->model
!= NULL
)
525 g_object_unref (state
->model
);
526 g_free (state
->prefix
);
527 g_free (state
->suffix
);
530 g_object_unref (state
->editable
);
531 if (state
->gui
!= NULL
)
532 g_object_unref (state
->gui
);
533 gnm_expr_entry_enable_tips (wbcg_get_entry_logical (state
->wbcg
));
534 if (state
->tooltip_widget
) {
535 g_object_unref (state
->tooltip_widget
);
536 g_object_unref (state
->tooltip_label
);
543 cb_dialog_formula_guru_cancel_clicked (FormulaGuruState
*state
)
545 wbcg_edit_finish (state
->wbcg
, WBC_EDIT_REJECT
, NULL
);
549 cb_dialog_formula_guru_zoom_toggled (GtkWidget
*button
, FormulaGuruState
*state
)
551 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (state
->treeview
);
556 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button
))) {
557 gtk_widget_hide (state
->main_button_area
);
558 gtk_widget_hide (state
->clear_button
);
559 gtk_widget_hide (state
->selector_button
);
560 gtk_tree_view_set_headers_visible (state
->treeview
, FALSE
);
561 gtk_widget_get_size_request (state
->dialog
,
562 &state
->old_width_request
,
563 &state
->old_height_request
);
564 gtk_window_get_size (GTK_WINDOW (state
->dialog
),
567 gtk_widget_set_size_request (state
->dialog
,state
->old_width_request
,100);
569 /* FIXME: the ideal `shrunk size' should probably not be hardcoded.*/
570 gtk_window_resize (GTK_WINDOW (state
->dialog
),state
->old_width_request
,100);
571 gtk_window_set_resizable (GTK_WINDOW (state
->dialog
), FALSE
);
573 gtk_widget_show (state
->main_button_area
);
574 gtk_widget_show (state
->clear_button
);
575 gtk_widget_show (state
->selector_button
);
576 gtk_tree_view_set_headers_visible (state
->treeview
, TRUE
);
577 gtk_window_set_resizable (GTK_WINDOW (state
->dialog
), TRUE
);
578 gtk_widget_set_size_request (state
->dialog
,
579 state
->old_width_request
,
580 state
->old_height_request
);
581 gtk_window_resize (GTK_WINDOW (state
->dialog
), state
->old_width
,
584 /* FIXME: this should keep the selection in sight, unfortunately it does not for */
585 /* the size reduction case. */
586 if (gtk_tree_selection_get_selected (selection
, NULL
, &iter
)) {
587 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (state
->model
), &iter
);
588 gtk_tree_view_scroll_to_cell (state
->treeview
, path
, NULL
,
590 gtk_tree_path_free (path
);
597 * cb_dialog_formula_guru_selector_clicked:
603 cb_dialog_formula_guru_selector_clicked (G_GNUC_UNUSED GtkWidget
*button
,
604 FormulaGuruState
*state
)
606 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (state
->treeview
);
610 g_return_if_fail (state
->active_path
== NULL
);
612 if (gtk_tree_selection_get_selected (selection
, &model
, &iter
)) {
613 state
->active_path
= gtk_tree_model_get_path (model
, &iter
);
614 gtk_widget_hide (state
->dialog
);
615 dialog_function_select (state
->wbcg
, FORMULA_GURU_KEY
);
617 g_warning ("We should never be here!?");
623 * cb_dialog_formula_guru_clear_clicked:
629 cb_dialog_formula_guru_clear_clicked (G_GNUC_UNUSED GtkWidget
*button
,
630 FormulaGuruState
*state
)
632 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (state
->treeview
);
636 g_return_if_fail (state
->active_path
== NULL
);
638 if (gtk_tree_selection_get_selected (selection
, &model
, &parent
)) {
639 gtk_tree_store_set (state
->model
, &parent
,
646 dialog_formula_guru_delete_children (&parent
, state
);
647 dialog_formula_guru_update_parent (&parent
, state
, gtk_tree_model_get_path
648 (GTK_TREE_MODEL (state
->model
), &parent
), 0, 0);
650 g_warning ("We should never be here!?");
655 dialog_formula_guru_is_array (FormulaGuruState
*state
)
657 return gtk_toggle_button_get_active
658 (GTK_TOGGLE_BUTTON (state
->array_button
));
662 * cb_dialog_formula_guru_ok_clicked:
666 * Close (destroy) the dialog
669 cb_dialog_formula_guru_ok_clicked (G_GNUC_UNUSED GtkWidget
*button
,
670 FormulaGuruState
*state
)
672 if (state
->cellrenderer
->entry
)
673 gnumeric_cell_renderer_expr_entry_editing_done (
674 GTK_CELL_EDITABLE (state
->cellrenderer
->entry
),
675 state
->cellrenderer
);
676 wbcg_edit_finish (state
->wbcg
,
677 dialog_formula_guru_is_array (state
)
678 ? WBC_EDIT_ACCEPT_ARRAY
679 : WBC_EDIT_ACCEPT
, NULL
);
683 cb_dialog_formula_guru_selection_changed (GtkTreeSelection
*the_selection
,
684 FormulaGuruState
*state
)
689 if (!gtk_tree_selection_get_selected (the_selection
, &model
, &iter
)) {
690 gtk_widget_set_sensitive (state
->clear_button
, FALSE
);
691 gtk_widget_set_sensitive (state
->selector_button
, FALSE
);
695 gtk_widget_set_sensitive (state
->clear_button
,
696 0 != gtk_tree_store_iter_depth (state
->model
,
698 gtk_widget_set_sensitive (state
->selector_button
, TRUE
);
699 dialog_formula_guru_update_this_child (&iter
, state
,
703 /* We shouldn't need that if it weren't for a GTK+ bug*/
705 cb_dialog_formula_guru_row_collapsed (G_GNUC_UNUSED GtkTreeView
*treeview
,
706 G_GNUC_UNUSED GtkTreeIter
*iter
,
707 G_GNUC_UNUSED GtkTreePath
*path
,
708 FormulaGuruState
*state
)
710 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (state
->treeview
);
712 cb_dialog_formula_guru_selection_changed (selection
, state
);
717 cb_dialog_formula_guru_edited (G_GNUC_UNUSED GtkCellRendererText
*cell
,
720 FormulaGuruState
*state
)
724 gboolean have_iter
= FALSE
;
726 path
= gtk_tree_path_new_from_string (path_string
);
728 have_iter
= gtk_tree_model_get_iter (GTK_TREE_MODEL (state
->model
),
730 gtk_tree_path_free (path
);
733 gtk_tree_store_set (state
->model
, &iter
, FUN_ARG_ENTRY
, new_text
, -1);
735 if (g_utf8_strlen (new_text
, -1) > 0)
736 dialog_formula_guru_adjust_varargs (&iter
, state
);
739 dialog_formula_guru_update_parent (&iter
, state
, gtk_tree_model_get_path
740 (GTK_TREE_MODEL (state
->model
), &iter
),
741 0, g_utf8_strlen (new_text
, -1));
745 cb_dialog_formula_guru_editing_started (G_GNUC_UNUSED GtkCellRenderer
*cell
,
746 GtkCellEditable
*editable
,
747 G_GNUC_UNUSED
const gchar
*path
,
748 FormulaGuruState
*state
)
750 g_object_ref (editable
);
752 g_object_unref (state
->editable
);
753 state
->editable
= editable
;
757 start_editing_cb (GtkTreeView
*tree_view
,
758 GdkEventButton
*event
,
759 FormulaGuruState
*state
)
764 if (event
->window
!= gtk_tree_view_get_bin_window (tree_view
))
766 if (state
->treeview
!= tree_view
)
769 if (gtk_tree_view_get_path_at_pos (tree_view
,
774 gtk_tree_model_get_iter (GTK_TREE_MODEL (state
->model
),
779 gtk_tree_model_get (GTK_TREE_MODEL (state
->model
), &iter
,
780 IS_NON_FUN
, &is_non_fun
,
784 gtk_tree_path_free (path
);
789 gtk_cell_editable_editing_done (state
->editable
);
791 gtk_widget_grab_focus (GTK_WIDGET (state
->treeview
));
792 gtk_tree_view_set_cursor (state
->treeview
,
797 gtk_tree_path_free (path
);
805 cb_dialog_formula_guru_query_tooltip (G_GNUC_UNUSED GtkWidget
*widget
,
808 gboolean keyboard_mode
,
812 FormulaGuruState
*state
= user_data
;
818 if (gtk_tree_view_get_tooltip_context
819 (state
->treeview
, &x_
, &y_
, keyboard_mode
, NULL
, &path
, &iter
)) {
820 char *markup
, *arg_desc
;
821 GtkWidget
*parent
, *window
;
823 gtk_tree_model_get (GTK_TREE_MODEL (state
->model
), &iter
,
824 ARG_TOOLTIP
, &arg_desc
, -1);
825 if (arg_desc
== NULL
|| arg_desc
[0]=='\0')
827 if (!state
->tooltip_widget
) {
828 state
->tooltip_label
= gtk_label_new ("");
829 state
->tooltip_widget
830 = gtk_widget_get_toplevel (state
->tooltip_label
);
831 gtk_widget_show_all (state
->tooltip_widget
);
832 g_object_ref (state
->tooltip_widget
);
833 g_object_ref (state
->tooltip_label
);
835 gtk_tooltip_set_custom (tooltip
, state
->tooltip_widget
);
836 window
= gtk_widget_get_toplevel (state
->tooltip_widget
);
837 /* Applying to window */
838 gtk_widget_set_app_paintable (window
, FALSE
);
840 parent
= gtk_widget_get_parent (state
->tooltip_widget
);
841 if (parent
!= NULL
&& GTK_IS_BOX (parent
)) {
842 gtk_box_set_spacing (GTK_BOX (parent
),0);
843 parent
= gtk_widget_get_parent (parent
);
844 if (parent
!= NULL
&& GTK_IS_ALIGNMENT (parent
))
845 gtk_alignment_set_padding
846 (GTK_ALIGNMENT (parent
),
850 markup
= gnm_func_convert_markup_to_pango
852 state
->tooltip_label
);
853 gtk_label_set_markup (GTK_LABEL (state
->tooltip_label
), markup
);
856 gtk_tree_view_set_tooltip_row (state
->treeview
,
858 gtk_tree_path_free (path
);
865 dialog_formula_guru_init (FormulaGuruState
*state
)
868 GtkTreeViewColumn
*column
;
869 GtkTreeSelection
*selection
;
870 GtkCellRenderer
*renderer
;
872 g_object_set_data (G_OBJECT (state
->dialog
), FORMULA_GURU_KEY_DIALOG
,
875 state
->tooltip_widget
= NULL
;
877 /* Set-up treeview */
878 scrolled
= go_gtk_builder_get_widget (state
->gui
, "scrolled");
879 state
->model
= gtk_tree_store_new (NUM_COLUMNS
, G_TYPE_STRING
, G_TYPE_BOOLEAN
,
880 G_TYPE_STRING
, G_TYPE_STRING
,
881 G_TYPE_INT
, G_TYPE_INT
, G_TYPE_POINTER
,
883 state
->treeview
= GTK_TREE_VIEW (
884 gtk_tree_view_new_with_model (GTK_TREE_MODEL (state
->model
)));
885 g_signal_connect (state
->treeview
,
887 G_CALLBACK (cb_dialog_formula_guru_row_collapsed
), state
);
888 selection
= gtk_tree_view_get_selection (state
->treeview
);
889 gtk_tree_selection_set_mode (selection
, GTK_SELECTION_BROWSE
);
890 g_signal_connect (selection
,
892 G_CALLBACK (cb_dialog_formula_guru_selection_changed
), state
);
894 column
= gtk_tree_view_column_new_with_attributes (_("Name"),
895 gnumeric_cell_renderer_text_new (),
896 "text", ARG_NAME
, NULL
);
897 gtk_tree_view_append_column (state
->treeview
, column
);
898 column
= gtk_tree_view_column_new_with_attributes (_("Type"),
899 gnumeric_cell_renderer_text_new (),
900 "text", ARG_TYPE
, NULL
);
901 gtk_tree_view_append_column (state
->treeview
, column
);
902 renderer
= gnumeric_cell_renderer_expr_entry_new (state
->wbcg
);
903 state
->cellrenderer
= GNM_CELL_RENDERER_EXPR_ENTRY (renderer
);
904 g_signal_connect (G_OBJECT (renderer
), "edited",
905 G_CALLBACK (cb_dialog_formula_guru_edited
), state
);
906 state
->editable
= NULL
;
907 g_signal_connect (G_OBJECT (renderer
), "editing-started",
908 G_CALLBACK (cb_dialog_formula_guru_editing_started
), state
);
909 column
= gtk_tree_view_column_new_with_attributes (_("Function/Argument"),
911 "text", FUN_ARG_ENTRY
,
912 "editable", IS_NON_FUN
,
914 state
->column
= column
;
915 gtk_tree_view_append_column (state
->treeview
, column
);
917 gtk_widget_set_has_tooltip (GTK_WIDGET (state
->treeview
), TRUE
);
918 g_signal_connect (G_OBJECT (state
->treeview
), "query-tooltip",
919 G_CALLBACK (cb_dialog_formula_guru_query_tooltip
), state
);
921 gtk_tree_view_set_headers_visible (state
->treeview
, TRUE
);
922 gtk_tree_view_set_enable_tree_lines (state
->treeview
, TRUE
);
923 gtk_container_add (GTK_CONTAINER (scrolled
), GTK_WIDGET (state
->treeview
));
925 g_signal_connect (state
->treeview
,
926 "button_press_event",
927 G_CALLBACK (start_editing_cb
), state
);
928 /* Finished set-up of treeview */
930 state
->quote_button
= go_gtk_builder_get_widget (state
->gui
,
932 state
->array_button
= go_gtk_builder_get_widget (state
->gui
,
934 gtk_widget_set_sensitive (state
->array_button
, TRUE
);
936 state
->ok_button
= go_gtk_builder_get_widget (state
->gui
, "ok_button");
937 gtk_widget_set_sensitive (state
->ok_button
, TRUE
);
938 g_signal_connect (G_OBJECT (state
->ok_button
),
940 G_CALLBACK (cb_dialog_formula_guru_ok_clicked
), state
);
942 state
->selector_button
= go_gtk_builder_get_widget (state
->gui
, "select_func");
943 gtk_widget_set_sensitive (state
->selector_button
, FALSE
);
944 g_signal_connect (G_OBJECT (state
->selector_button
),
946 G_CALLBACK (cb_dialog_formula_guru_selector_clicked
), state
);
948 state
->clear_button
= go_gtk_builder_get_widget (state
->gui
, "trash");
949 gtk_widget_set_sensitive (state
->clear_button
, FALSE
);
950 g_signal_connect (G_OBJECT (state
->clear_button
),
952 G_CALLBACK (cb_dialog_formula_guru_clear_clicked
), state
);
954 state
->zoom_button
= go_gtk_builder_get_widget (state
->gui
, "zoom");
955 gtk_widget_set_sensitive (state
->zoom_button
, TRUE
);
956 g_signal_connect (G_OBJECT (state
->zoom_button
),
958 G_CALLBACK (cb_dialog_formula_guru_zoom_toggled
), state
);
960 state
->main_button_area
= go_gtk_builder_get_widget (state
->gui
, "dialog-action_area2");
962 g_signal_connect_swapped (G_OBJECT (go_gtk_builder_get_widget (state
->gui
, "cancel_button")),
964 G_CALLBACK (cb_dialog_formula_guru_cancel_clicked
), state
);
966 gnm_init_help_button (
967 go_gtk_builder_get_widget (state
->gui
, "help_button"),
968 GNUMERIC_HELP_LINK_FORMULA_GURU
);
970 wbc_gtk_attach_guru (state
->wbcg
, state
->dialog
);
971 g_object_set_data_full (G_OBJECT (state
->dialog
),
972 "state", state
, (GDestroyNotify
) cb_dialog_formula_guru_destroy
);
978 dialog_formula_guru_show (FormulaGuruState
*state
)
982 if ((!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (state
->model
), &iter
)) ||
983 gtk_tree_model_iter_n_children (GTK_TREE_MODEL(state
->model
), &iter
) == 0)
984 wbcg_edit_finish (state
->wbcg
, WBC_EDIT_ACCEPT
, NULL
);
986 gtk_widget_show_all (state
->dialog
);
990 * dialog_formula_guru
991 * @wbcg: The workbook to use as a parent window.
993 * Pop up a function selector then a formula guru.
996 dialog_formula_guru (WBCGtk
*wbcg
, GnmFunc
*fd
)
1002 FormulaGuruState
*state
;
1003 GnmExpr
const *expr
= NULL
;
1005 g_return_if_fail (wbcg
!= NULL
);
1007 dialog
= gnm_dialog_raise_if_exists (wbcg
, FORMULA_GURU_KEY
);
1010 /* We already exist */
1011 state
= g_object_get_data (G_OBJECT (dialog
),
1012 FORMULA_GURU_KEY_DIALOG
);
1014 if (state
->active_path
) {
1015 dialog_formula_guru_load_fd (state
->active_path
, fd
, state
);
1016 gtk_tree_path_free (state
->active_path
);
1017 state
->active_path
= NULL
;
1019 dialog_formula_guru_load_fd (NULL
, fd
, state
);
1020 dialog_formula_guru_show (state
);
1022 if (state
->active_path
) {
1023 gtk_tree_path_free (state
->active_path
);
1024 state
->active_path
= NULL
;
1027 if (0 == gtk_tree_model_iter_n_children (GTK_TREE_MODEL(state
->model
),
1029 gtk_widget_destroy (state
->dialog
);
1031 dialog_formula_guru_show (state
);
1036 /* Get the dialog and check for errors */
1037 gui
= gnm_gtk_builder_load ("res:ui/formula-guru.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
1041 state
= g_new (FormulaGuruState
, 1);
1043 state
->wb
= wb_control_get_workbook (GNM_WBC (wbcg
));
1045 state
->active_path
= NULL
;
1046 state
->pos
= g_new (GnmParsePos
, 1);
1048 gnm_expr_entry_disable_tips (wbcg_get_entry_logical (wbcg
));
1050 sv
= wb_control_cur_sheet_view (GNM_WBC (wbcg
));
1051 cell
= sheet_cell_get (sv_sheet (sv
), sv
->edit_pos
.col
, sv
->edit_pos
.row
);
1053 parse_pos_init_cell (state
->pos
, cell
);
1054 if (gnm_cell_has_expr (cell
))
1055 expr
= gnm_expr_top_first_funcall (cell
->base
.texpr
);
1057 parse_pos_init_editpos (state
->pos
, sv
);
1061 wbcg_edit_start (wbcg
, TRUE
, TRUE
);
1062 state
->prefix
= g_strdup ("=");
1063 state
->suffix
= NULL
;
1065 char const *sub_str
;
1066 char const *full_str
= gtk_entry_get_text (wbcg_get_entry (wbcg
));
1069 func_str
= gnm_expr_as_string (expr
,
1071 sheet_get_conventions (sv_sheet (sv
)));
1073 wbcg_edit_start (wbcg
, FALSE
, TRUE
);
1074 fd
= gnm_expr_get_func_def (expr
);
1076 sub_str
= strstr (full_str
, func_str
);
1078 g_return_if_fail (sub_str
!= NULL
);
1080 state
->prefix
= g_strndup (full_str
, sub_str
- full_str
);
1081 state
->suffix
= g_strdup (sub_str
+ strlen (func_str
));
1085 state
->dialog
= go_gtk_builder_get_widget (state
->gui
, "formula_guru");
1086 gnm_dialog_setup_destroy_handlers (GTK_DIALOG (state
->dialog
),
1088 GNM_DIALOG_DESTROY_SHEET_REMOVED
);
1091 if (dialog_formula_guru_init (state
)) {
1092 go_gtk_notice_dialog (wbcg_toplevel (wbcg
), GTK_MESSAGE_ERROR
,
1093 _("Could not create the formula guru."));
1098 gnm_keyed_dialog (state
->wbcg
, GTK_WINDOW (state
->dialog
),
1101 gtk_widget_show_all (gtk_dialog_get_content_area (GTK_DIALOG (state
->dialog
)));
1102 gtk_widget_realize (state
->dialog
);
1105 dialog_function_select (wbcg
, FORMULA_GURU_KEY
);
1110 dialog_formula_guru_load_fd (NULL
, fd
, state
);
1113 gtk_tree_store_append (state
->model
, &iter
, NULL
);
1114 dialog_formula_guru_load_expr (NULL
, 0, expr
, state
);
1117 gtk_widget_show_all (state
->dialog
);