GUI: Move .ui files from goffice resources to glib resources
[gnumeric.git] / src / dialogs / dialog-consolidate.c
blobd636834831f7375471951637d44187e3da5d87fc
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * dialog-consolidate.c : implementation of the consolidation dialog.
5 * Copyright (C) Almer S. Tigelaar <almer@gnome.org>
6 * Copyright (C) Andreas J. Guelzow <aguelzow@taliesin.ca>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
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, see <https://www.gnu.org/licenses/>.
22 #include <gnumeric-config.h>
23 #include <glib/gi18n-lib.h>
24 #include <gnumeric.h>
25 #include "dialogs.h"
26 #include "help.h"
27 #include "tool-dialogs.h"
29 #include <commands.h>
30 #include <consolidate.h>
31 #include <func.h>
32 #include <gui-util.h>
33 #include <ranges.h>
34 #include <value.h>
35 #include <sheet-view.h>
36 #include <selection.h>
37 #include <widgets/gnumeric-expr-entry.h>
38 #include <widgets/gnumeric-cell-renderer-expr-entry.h>
39 #include <widgets/gnm-dao.h>
40 #include <wbc-gtk.h>
41 #include <dao-gui-utils.h>
42 #include <tools/dao.h>
43 #include <gtk/gtk.h>
45 #include <string.h>
48 #define CONSOLIDATE_KEY "consolidate-dialog"
50 enum {
51 SOURCE_COLUMN,
52 PIXMAP_COLUMN,
53 IS_EDITABLE_COLUMN,
54 NUM_COLUMNS
57 typedef struct {
58 GenericToolState base;
60 GtkComboBox *function;
62 GtkTreeView *source_view;
63 GtkTreeModel *source_areas;
64 GnumericCellRendererExprEntry *cellrenderer;
65 GdkPixbuf *pixmap;
67 GtkButton *clear;
68 GtkButton *delete;
70 GtkCheckButton *labels_row;
71 GtkCheckButton *labels_col;
72 GtkCheckButton *labels_copy;
74 int areas_index; /* Select index in sources clist */
75 char *construct_error; /* If set an error occurred in construct_consolidate */
76 } ConsolidateState;
78 static void dialog_set_button_sensitivity (G_GNUC_UNUSED GtkWidget *dummy,
79 ConsolidateState *state);
81 /**
82 * adjust_source_areas
84 * ensures that we have exactly 2 empty rows
87 **/
88 static void
89 adjust_source_areas (ConsolidateState *state)
91 int i = 0;
92 int cnt_empty = 2;
93 GtkTreeIter iter;
95 if (gtk_tree_model_get_iter_first
96 (state->source_areas, &iter)) {
97 do {
98 char *source;
100 gtk_tree_model_get (state->source_areas,
101 &iter,
102 SOURCE_COLUMN, &source,
103 -1);
104 if (strlen(source) == 0)
105 cnt_empty--;
106 g_free (source);
107 } while (gtk_tree_model_iter_next
108 (state->source_areas,&iter));
111 for (i = 0; i < cnt_empty; i++) {
112 gtk_list_store_append (GTK_LIST_STORE(state->source_areas),
113 &iter);
114 gtk_list_store_set (GTK_LIST_STORE(state->source_areas),
115 &iter,
116 IS_EDITABLE_COLUMN, TRUE,
117 SOURCE_COLUMN, "",
118 PIXMAP_COLUMN, state->pixmap,
119 -1);
121 dialog_set_button_sensitivity (NULL, state);
125 * construct_consolidate:
127 * Builts a new Consolidate structure from the
128 * state of all the widgets in the dialog, this can
129 * be used to actually "execute" a consolidation
131 static GnmConsolidate *
132 construct_consolidate (ConsolidateState *state, data_analysis_output_t *dao)
134 GnmConsolidate *cs = gnm_consolidate_new ();
135 GnmConsolidateMode mode = 0;
136 char const *func;
137 GnmValue *range_value;
138 GtkTreeIter iter;
139 gboolean has_iter;
141 switch (gtk_combo_box_get_active (state->function)) {
142 case 0 : func = "SUM"; break;
143 case 1 : func = "MIN"; break;
144 case 2 : func = "MAX"; break;
145 case 3 : func = "AVERAGE"; break;
146 case 4 : func = "COUNT"; break;
147 case 5 : func = "PRODUCT"; break;
148 case 6 : func = "STDEV"; break;
149 case 7 : func = "STDEVP"; break;
150 case 8 : func = "VAR"; break;
151 case 9 : func = "VARP"; break;
152 default :
153 func = NULL;
154 g_warning ("Unknown function index!");
157 gnm_consolidate_set_function (cs, gnm_func_lookup (func, NULL));
159 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->labels_row)))
160 mode |= CONSOLIDATE_COL_LABELS;
161 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->labels_col)))
162 mode |= CONSOLIDATE_ROW_LABELS;
164 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->labels_copy)))
165 mode |= CONSOLIDATE_COPY_LABELS;
166 if (!dao_put_formulas (dao))
167 mode |= CONSOLIDATE_PUT_VALUES;
169 gnm_consolidate_set_mode (cs, mode);
171 g_return_val_if_fail (gtk_tree_model_iter_n_children
172 (state->source_areas,
173 NULL)> 2, NULL);
175 has_iter = gtk_tree_model_get_iter_first (state->source_areas,
176 &iter);
177 g_return_val_if_fail (has_iter, NULL);
178 do {
179 char *source;
181 gtk_tree_model_get (state->source_areas,
182 &iter,
183 SOURCE_COLUMN, &source,
184 -1);
185 if (strlen(source) != 0) {
186 range_value = value_new_cellrange_str (state->base.sheet, source);
188 if (range_value == NULL) {
189 state->construct_error = g_strdup_printf (
190 _("Specification %s "
191 "does not define a region"),
192 source);
193 g_free (source);
194 gnm_consolidate_free (cs, FALSE);
195 return NULL;
197 if (!gnm_consolidate_add_source (cs, range_value)) {
198 state->construct_error = g_strdup_printf (
199 _("Source region %s overlaps "
200 "with the destination region"),
201 source);
202 g_free (source);
203 gnm_consolidate_free (cs, FALSE);
204 return NULL;
207 g_free (source);
208 } while (gtk_tree_model_iter_next
209 (state->source_areas,&iter));
211 return cs;
214 /***************************************************************************************/
217 * dialog_set_button_sensitivity:
218 * @dummy:
219 * @state:
222 static void
223 dialog_set_button_sensitivity (G_GNUC_UNUSED GtkWidget *dummy,
224 ConsolidateState *state)
226 gboolean ready;
228 ready = gnm_dao_is_ready (GNM_DAO (state->base.gdao))
229 && (gtk_tree_model_iter_n_children
230 (state->source_areas, NULL)> 2);
231 gtk_widget_set_sensitive (GTK_WIDGET (state->base.ok_button), ready);
232 return;
235 static void
236 cb_selection_changed (G_GNUC_UNUSED GtkTreeSelection *ignored,
237 ConsolidateState *state)
239 GtkTreeIter iter;
240 GtkTreeSelection *selection = gtk_tree_view_get_selection (state->source_view);
242 gtk_widget_set_sensitive (GTK_WIDGET(state->delete),
243 gtk_tree_selection_get_selected (selection, NULL, &iter));
247 static void
248 cb_source_edited (G_GNUC_UNUSED GtkCellRendererText *cell,
249 gchar *path_string,
250 gchar *new_text,
251 ConsolidateState *state)
253 GtkTreeIter iter;
254 GtkTreePath *path;
256 path = gtk_tree_path_new_from_string (path_string);
258 if (gtk_tree_model_get_iter (state->source_areas, &iter, path))
259 gtk_list_store_set (GTK_LIST_STORE(state->source_areas),
260 &iter, SOURCE_COLUMN, new_text, -1);
261 else
262 g_warning ("Did not get a valid iterator");
264 gtk_tree_path_free (path);
265 adjust_source_areas (state);
268 static void
269 cb_dialog_destroy (ConsolidateState *state)
271 if (state->pixmap != NULL)
272 g_object_unref (state->pixmap);
273 if (state->construct_error != NULL) {
274 g_warning ("The construct error was not freed, this should not happen!");
275 g_free (state->construct_error);
279 static void
280 cb_consolidate_ok_clicked (GtkWidget *button, ConsolidateState *state)
282 GnmConsolidate *cs;
283 data_analysis_output_t *dao;
285 if (state->cellrenderer->entry)
286 gnumeric_cell_renderer_expr_entry_editing_done (
287 GTK_CELL_EDITABLE (state->cellrenderer->entry),
288 state->cellrenderer);
290 if (state->base.warning_dialog != NULL)
291 gtk_widget_destroy (state->base.warning_dialog);
293 dao = parse_output ((GenericToolState *)state, NULL);
294 cs = construct_consolidate (state, dao);
297 * If something went wrong consolidate_construct
298 * return NULL and sets the state->construct_error to
299 * a suitable error message
301 if (cs == NULL) {
302 go_gtk_notice_nonmodal_dialog (GTK_WINDOW (state->base.dialog),
303 &state->base.warning_dialog,
304 GTK_MESSAGE_ERROR,
305 "%s", state->construct_error);
306 g_free (state->construct_error);
307 g_free (dao);
308 state->construct_error = NULL;
310 return;
313 if (gnm_consolidate_check_destination (cs, dao)) {
314 if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg),
315 state->base.sheet,
316 dao, cs, gnm_tool_consolidate_engine,
317 FALSE) &&
318 (button == state->base.ok_button))
319 gtk_widget_destroy (state->base.dialog);
320 } else {
321 go_gtk_notice_nonmodal_dialog (GTK_WINDOW (state->base.dialog),
322 &state->base.warning_dialog,
323 GTK_MESSAGE_ERROR,
324 _("The output range overlaps "
325 "with the input ranges."));
326 g_free (dao);
327 gnm_consolidate_free (cs, FALSE);
331 static void
332 cb_source_changed (G_GNUC_UNUSED GtkEntry *ignored,
333 ConsolidateState *state)
335 g_return_if_fail (state != NULL);
339 static void
340 cb_clear_clicked (G_GNUC_UNUSED GtkButton *button,
341 ConsolidateState *state)
343 g_return_if_fail (state != NULL);
345 if (state->cellrenderer->entry)
346 gnumeric_cell_renderer_expr_entry_editing_done (
347 GTK_CELL_EDITABLE (state->cellrenderer->entry),
348 state->cellrenderer);
350 gtk_list_store_clear (GTK_LIST_STORE(state->source_areas));
351 adjust_source_areas (state);
353 dialog_set_button_sensitivity (NULL, state);
356 static void
357 cb_delete_clicked (G_GNUC_UNUSED GtkButton *button,
358 ConsolidateState *state)
360 GtkTreeIter sel_iter;
361 GtkTreeSelection *selection =
362 gtk_tree_view_get_selection (state->source_view);
364 if (state->cellrenderer->entry)
365 gnumeric_cell_renderer_expr_entry_editing_done (
366 GTK_CELL_EDITABLE (state->cellrenderer->entry),
367 state->cellrenderer);
368 if (!gtk_tree_selection_get_selected (selection, NULL, &sel_iter))
369 return;
370 gtk_list_store_remove (GTK_LIST_STORE(state->source_areas),
371 &sel_iter);
372 adjust_source_areas (state);
374 dialog_set_button_sensitivity (NULL, state);
377 static void
378 cb_labels_toggled (G_GNUC_UNUSED GtkCheckButton *button,
379 ConsolidateState *state)
381 gboolean copy_labels =
382 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->labels_row)) ||
383 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->labels_col));
385 gtk_widget_set_sensitive (GTK_WIDGET (state->labels_copy), copy_labels);
386 if (!copy_labels)
387 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->labels_copy), FALSE);
390 /***************************************************************************************/
392 static void
393 connect_signal_labels_toggled (ConsolidateState *state, GtkCheckButton *button)
395 g_signal_connect (G_OBJECT (button),
396 "toggled",
397 G_CALLBACK (cb_labels_toggled), state);
400 static void
401 setup_widgets (ConsolidateState *state, GtkBuilder *gui)
403 GtkTreeViewColumn *column;
404 GtkTreeSelection *selection;
405 GtkCellRenderer *renderer;
407 state->function = go_gtk_builder_combo_box_init_text (gui, "function");
408 gtk_combo_box_set_active (state->function, 0);
410 /* Begin: Source Areas View*/
411 state->source_view = GTK_TREE_VIEW (go_gtk_builder_get_widget
412 (gui,
413 "source_treeview"));
414 state->source_areas = GTK_TREE_MODEL(gtk_list_store_new
415 (NUM_COLUMNS,
416 G_TYPE_STRING,
417 GDK_TYPE_PIXBUF,
418 G_TYPE_INT));
419 gtk_tree_view_set_model (state->source_view,
420 state->source_areas);
421 g_object_unref (state->source_areas);
423 selection = gtk_tree_view_get_selection
424 (state->source_view );
425 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
427 renderer = gnumeric_cell_renderer_expr_entry_new (state->base.wbcg);
428 state->cellrenderer =
429 GNM_CELL_RENDERER_EXPR_ENTRY (renderer);
430 column = gtk_tree_view_column_new_with_attributes
431 ("", renderer,
432 "text", SOURCE_COLUMN,
433 "editable", IS_EDITABLE_COLUMN,
434 NULL);
435 g_signal_connect (G_OBJECT (renderer), "edited",
436 G_CALLBACK (cb_source_edited), state);
437 gtk_tree_view_column_set_expand (column, TRUE);
438 gtk_tree_view_append_column (state->source_view, column);
439 column = gtk_tree_view_column_new_with_attributes
440 ("", gtk_cell_renderer_pixbuf_new (),
441 "pixbuf", PIXMAP_COLUMN, NULL);
442 gtk_tree_view_append_column (state->source_view, column);
443 /* End: Source Areas View*/
445 state->clear = GTK_BUTTON (go_gtk_builder_get_widget (gui, "clear"));
446 state->delete = GTK_BUTTON (go_gtk_builder_get_widget (gui, "delete"));
448 state->labels_row = GTK_CHECK_BUTTON (go_gtk_builder_get_widget (gui, "labels_row"));
449 state->labels_col = GTK_CHECK_BUTTON (go_gtk_builder_get_widget (gui, "labels_col"));
450 state->labels_copy = GTK_CHECK_BUTTON (go_gtk_builder_get_widget (gui, "labels_copy"));
452 cb_selection_changed (NULL, state);
453 g_signal_connect (selection,
454 "changed",
455 G_CALLBACK (cb_selection_changed), state);
456 g_signal_connect (G_OBJECT (state->clear),
457 "clicked",
458 G_CALLBACK (cb_clear_clicked), state);
459 g_signal_connect (G_OBJECT (state->delete),
460 "clicked",
461 G_CALLBACK (cb_delete_clicked), state);
463 connect_signal_labels_toggled (state, state->labels_row);
464 connect_signal_labels_toggled (state, state->labels_col);
465 connect_signal_labels_toggled (state, state->labels_copy);
469 static gboolean
470 add_source_area (SheetView *sv, GnmRange const *r, gpointer closure)
472 ConsolidateState *state = closure;
473 char *range_name;
474 GtkTreeIter iter;
476 if (range_is_singleton (r))
477 return TRUE;
479 range_name = global_range_name (sv_sheet (sv), r);
481 gtk_list_store_prepend (GTK_LIST_STORE(state->source_areas),
482 &iter);
483 gtk_list_store_set (GTK_LIST_STORE(state->source_areas),
484 &iter,
485 IS_EDITABLE_COLUMN, TRUE,
486 SOURCE_COLUMN, range_name,
487 PIXMAP_COLUMN, state->pixmap,
488 -1);
489 g_free (range_name);
491 return TRUE;
495 * dialog_consolidate_tool_init:
496 * @state:
498 * Create the dialog (guru).
501 static void
502 dialog_consolidate_tool_init (ConsolidateState *state)
504 state->areas_index = -1;
506 setup_widgets (state, state->base.gui);
507 state->pixmap = go_gtk_widget_render_icon_pixbuf
508 (GTK_WIDGET (state->base.dialog),
509 "gnumeric-exprentry",
510 GTK_ICON_SIZE_LARGE_TOOLBAR);
512 /* Dynamic initialization */
513 cb_source_changed (NULL, state);
514 cb_labels_toggled (state->labels_row, state);
517 * When there are non-singleton selections add them all to the
518 * source range list for convenience
520 sv_selection_foreach (state->base.sv, &add_source_area, state);
522 adjust_source_areas (state);
523 dialog_set_button_sensitivity (NULL, state);
524 state->base.state_destroy = (state_destroy_t)cb_dialog_destroy;
527 void
528 dialog_consolidate (WBCGtk *wbcg)
530 ConsolidateState *state;
531 SheetView *sv;
532 Sheet *sheet;
534 g_return_if_fail (wbcg != NULL);
535 sv = wb_control_cur_sheet_view (GNM_WBC (wbcg));
536 sheet = sv_sheet (sv);
538 /* Only pop up one copy per workbook */
539 if (gnm_dialog_raise_if_exists (wbcg, CONSOLIDATE_KEY)) {
540 return;
543 /* Primary static initialization */
544 state = g_new0 (ConsolidateState, 1);
546 if (dialog_tool_init ((GenericToolState *)state, wbcg, sheet,
547 GNUMERIC_HELP_LINK_CONSOLIDATE,
548 "res:ui/consolidate.ui", "Consolidate",
549 _("Could not create the Consolidate dialog."),
550 CONSOLIDATE_KEY,
551 G_CALLBACK (cb_consolidate_ok_clicked),
552 NULL,
553 G_CALLBACK (dialog_set_button_sensitivity),
555 return;
557 gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
558 dialog_consolidate_tool_init (state);
559 gtk_widget_show (GTK_WIDGET (state->base.dialog));