1.12.42
[gnumeric.git] / src / dialogs / dialog-tabulate.c
blob3c72bcc150332ba4dd0ec171d9bf44a8d39e1a22
1 /*
2 * dialog-tabulate.c:
3 * Dialog for making tables of function dependcies.
5 * Author:
6 * COPYRIGHT (C) Morten Welinder (terra@gnome.org)
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) version 3.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
21 * USA
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>
30 #include <gui-util.h>
31 #include <widgets/gnm-expr-entry.h>
32 #include <tools/tabulate.h>
33 #include <wbc-gtk.h>
34 #include <ranges.h>
35 #include <value.h>
36 #include <sheet.h>
37 #include <mstyle.h>
38 #include <workbook.h>
39 #include <mathfunc.h>
40 #include <cell.h>
41 #include <commands.h>
42 #include <gnm-format.h>
43 #include <number-match.h>
44 #include <mstyle.h>
45 #include <style-border.h>
46 #include <sheet-style.h>
47 #include <style-color.h>
49 #include <string.h>
51 #define TABULATE_KEY "tabulate-dialog"
53 /* ------------------------------------------------------------------------- */
55 enum {
56 COL_CELL = 0,
57 COL_MIN,
58 COL_MAX,
59 COL_STEP
62 typedef struct {
63 WBCGtk *wbcg;
64 Sheet *sheet;
66 GtkBuilder *gui;
67 GtkDialog *dialog;
69 GtkGrid *grid;
70 GnmExprEntry *resultrangetext;
71 } DialogState;
73 static const char * const mode_group[] = {
74 "mode_visual",
75 "mode_coordinate",
76 NULL
79 /* ------------------------------------------------------------------------- */
81 static void
82 non_model_dialog (WBCGtk *wbcg,
83 GtkDialog *dialog,
84 const char *key)
86 gnm_keyed_dialog (wbcg, GTK_WINDOW (dialog), key);
88 gtk_widget_show (GTK_WIDGET (dialog));
91 static GnmCell *
92 single_cell (Sheet *sheet, GnmExprEntry *gee)
94 int col, row;
95 gboolean issingle;
96 GnmValue *v = gnm_expr_entry_parse_as_value (gee, sheet);
98 if (!v) return NULL;
100 col = v->v_range.cell.a.col;
101 row = v->v_range.cell.a.row;
102 issingle = (col == v->v_range.cell.b.col && row == v->v_range.cell.b.row);
104 value_release (v);
106 if (issingle)
107 return sheet_cell_fetch (sheet, col, row);
108 else
109 return NULL;
112 static int
113 get_grid_float_entry (GtkGrid *g, int y, int x, GnmCell *cell, gnm_float *number,
114 GtkEntry **wp, gboolean with_default, gnm_float default_float)
116 GOFormat const *format;
117 GtkWidget *w = gtk_grid_get_child_at (g, x, y + 1);
119 g_return_val_if_fail (GTK_IS_ENTRY (w), 3);
121 *wp = GTK_ENTRY (w);
122 format = gnm_style_get_format (gnm_cell_get_style (cell));
124 return (with_default?
125 entry_to_float_with_format_default (*wp, number, TRUE, format,
126 default_float):
127 entry_to_float_with_format (*wp, number, TRUE, format));
130 static void
131 cb_dialog_destroy (DialogState *dd)
133 g_object_unref (dd->gui);
134 memset (dd, 0, sizeof (*dd));
135 g_free (dd);
138 static void
139 cancel_clicked (G_GNUC_UNUSED GtkWidget *widget, DialogState *dd)
141 GtkDialog *dialog = dd->dialog;
142 gtk_widget_destroy (GTK_WIDGET (dialog));
145 static void
146 tabulate_ok_clicked (G_GNUC_UNUSED GtkWidget *widget, DialogState *dd)
148 GtkDialog *dialog = dd->dialog;
149 GnmCell *resultcell;
150 int dims = 0;
151 int row;
152 gboolean with_coordinates;
153 GnmTabulateInfo *data;
154 /* we might get the 4 below from the positon of some of the widgets inside the grid */
155 int nrows = 4;
156 GnmCell **cells;
157 gnm_float *minima, *maxima, *steps;
159 cells = g_new (GnmCell *, nrows);
160 minima = g_new (gnm_float, nrows);
161 maxima = g_new (gnm_float, nrows);
162 steps = g_new (gnm_float, nrows);
164 for (row = 1; row < nrows; row++) {
165 GtkEntry *e_w;
166 GnmExprEntry *w = GNM_EXPR_ENTRY (gtk_grid_get_child_at (dd->grid, COL_CELL, row + 1));
168 if (!w || gnm_expr_entry_is_blank (w))
169 continue;
171 cells[dims] = single_cell (dd->sheet, w);
172 if (!cells[dims]) {
173 go_gtk_notice_dialog (GTK_WINDOW (dd->dialog),
174 GTK_MESSAGE_ERROR,
175 _("You should introduce a single valid cell as dependency cell"));
176 gnm_expr_entry_grab_focus (GNM_EXPR_ENTRY (w), TRUE);
177 goto error;
179 if (gnm_cell_has_expr (cells[dims])) {
180 go_gtk_notice_dialog (GTK_WINDOW (dd->dialog),
181 GTK_MESSAGE_ERROR,
182 _("The dependency cells should not contain an expression"));
183 gnm_expr_entry_grab_focus (GNM_EXPR_ENTRY (w), TRUE);
184 goto error;
187 if (get_grid_float_entry (dd->grid, row, COL_MIN, cells[dims],
188 &(minima[dims]), &e_w, FALSE, 0.0)) {
189 go_gtk_notice_dialog (GTK_WINDOW (dd->dialog),
190 GTK_MESSAGE_ERROR,
191 _("You should introduce a valid number as minimum"));
192 focus_on_entry (e_w);
193 goto error;
196 if (get_grid_float_entry (dd->grid, row, COL_MAX, cells[dims],
197 &(maxima[dims]), &e_w, FALSE, 0.0)) {
198 go_gtk_notice_dialog (GTK_WINDOW (dd->dialog),
199 GTK_MESSAGE_ERROR,
200 _("You should introduce a valid number as maximum"));
201 focus_on_entry (e_w);
202 goto error;
205 if (maxima[dims] < minima[dims]) {
206 go_gtk_notice_dialog (GTK_WINDOW (dd->dialog),
207 GTK_MESSAGE_ERROR,
208 _("The maximum value should be bigger than the minimum"));
209 focus_on_entry (e_w);
210 goto error;
213 if (get_grid_float_entry (dd->grid, row, COL_STEP, cells[dims],
214 &(steps[dims]), &e_w, TRUE, 1.0)) {
215 go_gtk_notice_dialog (GTK_WINDOW (dd->dialog),
216 GTK_MESSAGE_ERROR,
217 _("You should introduce a valid number as step size"));
218 focus_on_entry (e_w);
219 goto error;
222 if (steps[dims] <= 0) {
223 go_gtk_notice_dialog (GTK_WINDOW (dd->dialog),
224 GTK_MESSAGE_ERROR,
225 _("The step size should be positive"));
226 focus_on_entry (e_w);
227 goto error;
230 dims++;
233 if (dims == 0) {
234 go_gtk_notice_dialog (GTK_WINDOW (dd->dialog),
235 GTK_MESSAGE_ERROR,
236 _("You should introduce one or more dependency cells"));
237 goto error;
241 resultcell = single_cell (dd->sheet, dd->resultrangetext);
243 if (!resultcell) {
244 go_gtk_notice_dialog (GTK_WINDOW (dd->dialog),
245 GTK_MESSAGE_ERROR,
246 _("You should introduce a single valid cell as result cell"));
247 gnm_expr_entry_grab_focus (dd->resultrangetext, TRUE);
248 goto error;
251 if (!gnm_cell_has_expr (resultcell)) {
252 go_gtk_notice_dialog (GTK_WINDOW (dd->dialog),
253 GTK_MESSAGE_ERROR,
254 _("The target cell should contain an expression"));
255 gnm_expr_entry_grab_focus (dd->resultrangetext, TRUE);
256 goto error;
261 int i = gnm_gui_group_value (dd->gui, mode_group);
262 with_coordinates = (i == -1) ? TRUE : (gboolean)i;
265 data = g_new (GnmTabulateInfo, 1);
266 data->target = resultcell;
267 data->dims = dims;
268 data->cells = cells;
269 data->minima = minima;
270 data->maxima = maxima;
271 data->steps = steps;
272 data->with_coordinates = with_coordinates;
274 if (!cmd_tabulate (GNM_WBC (dd->wbcg), data)) {
275 gtk_widget_destroy (GTK_WIDGET (dialog));
276 return;
279 g_free (data);
280 error:
281 g_free (minima);
282 g_free (maxima);
283 g_free (steps);
284 g_free (cells);
287 void
288 dialog_tabulate (WBCGtk *wbcg, Sheet *sheet)
290 GtkBuilder *gui;
291 GtkDialog *dialog;
292 DialogState *dd;
293 int i;
295 g_return_if_fail (wbcg != NULL);
297 /* Only one guru per workbook. */
298 if (wbc_gtk_get_guru (wbcg))
299 return;
301 if (gnm_dialog_raise_if_exists (wbcg, TABULATE_KEY))
302 return;
303 gui = gnm_gtk_builder_load ("res:ui/tabulate.ui", NULL, GO_CMD_CONTEXT (wbcg));
304 if (gui == NULL)
305 return;
307 dialog = GTK_DIALOG (go_gtk_builder_get_widget (gui, "tabulate_dialog"));
309 dd = g_new (DialogState, 1);
310 dd->wbcg = wbcg;
311 dd->gui = gui;
312 dd->dialog = dialog;
313 dd->sheet = sheet;
315 dd->grid = GTK_GRID (go_gtk_builder_get_widget (gui, "main-grid"));
316 /* we might get the 4 below from the positon of some of the widgets inside the grid */
317 for (i = 1; i < 4; i++) {
318 GnmExprEntry *ge = gnm_expr_entry_new (wbcg, TRUE);
319 gnm_expr_entry_set_flags (ge,
320 GNM_EE_SINGLE_RANGE | GNM_EE_SHEET_OPTIONAL,
321 GNM_EE_MASK);
323 gtk_grid_attach (dd->grid, GTK_WIDGET (ge), COL_CELL, i + 1, 1, 1);
324 gtk_widget_set_margin_left (GTK_WIDGET (ge), 18);
325 gtk_widget_show (GTK_WIDGET (ge));
328 dd->resultrangetext = gnm_expr_entry_new (wbcg, TRUE);
329 gnm_expr_entry_set_flags (dd->resultrangetext,
330 GNM_EE_SINGLE_RANGE | GNM_EE_SHEET_OPTIONAL,
331 GNM_EE_MASK);
332 gtk_grid_attach (dd->grid, GTK_WIDGET (dd->resultrangetext), 0, 6, 4, 1);
333 gtk_widget_set_margin_left (GTK_WIDGET (dd->resultrangetext), 18);
334 gtk_widget_show (GTK_WIDGET (dd->resultrangetext));
336 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui, "ok_button")),
337 "clicked",
338 G_CALLBACK (tabulate_ok_clicked), dd);
340 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (gui, "cancel_button")),
341 "clicked",
342 G_CALLBACK (cancel_clicked), dd);
343 /* FIXME: Add correct helpfile address */
344 gnm_init_help_button (
345 go_gtk_builder_get_widget (gui, "help_button"),
346 GNUMERIC_HELP_LINK_TABULATE);
347 g_object_set_data_full (G_OBJECT (dialog),
348 "state", dd, (GDestroyNotify) cb_dialog_destroy);
350 gnm_dialog_setup_destroy_handlers (dialog, wbcg,
351 GNM_DIALOG_DESTROY_SHEET_REMOVED);
353 gtk_widget_show_all (gtk_dialog_get_content_area (dialog));
354 wbc_gtk_attach_guru (wbcg, GTK_WIDGET (dialog));
356 non_model_dialog (wbcg, dialog, TABULATE_KEY);