1 /*
2 * dialog-sheet-resize.c: Dialog to resize current or all sheets.
3 *
4 * Author:
5 * Morten Welinder <terra@gnome.org>
6 *
7 * (C) Copyright 2009 Morten Welinder <terra@gnome.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <https://www.gnu.org/licenses/>.
21 */
22
23 #include <gnumeric-config.h>
24 #include <glib/gi18n-lib.h>
25 #include <gnumeric.h>
26 #include <dialogs/dialogs.h>
27 #include <dialogs/help.h>
28
29 #include <gui-util.h>
30 #include <wbc-gtk.h>
31 #include <workbook-view.h>
32 #include <workbook.h>
33 #include <sheet.h>
34 #include <commands.h>
35
36 #define RESIZE_DIALOG_KEY "sheet-resize-dialog"
37
38 typedef struct {
39 WBCGtk *wbcg;
40 Sheet *sheet;
41 GtkWidget *dialog;
42 GtkWidget *columns_scale, *rows_scale;
43 GtkWidget *columns_label, *rows_label;
44 GtkWidget *ok_button, *cancel_button;
45 GtkWidget *all_sheets_button;
46 } ResizeState;
47
48 static void
get_sizes(ResizeState * state,int * cols,int * rows)49 get_sizes (ResizeState *state, int *cols, int *rows)
50 {
51 GtkAdjustment *adj;
52
53 adj = gtk_range_get_adjustment (GTK_RANGE (state->columns_scale));
54 *cols = 1 << (int)gtk_adjustment_get_value (adj);
55
56 adj = gtk_range_get_adjustment (GTK_RANGE (state->rows_scale));
57 *rows = 1 << (int)gtk_adjustment_get_value (adj);
58 }
59
60 static void
set_count(GtkWidget * l,int count)61 set_count (GtkWidget *l, int count)
62 {
63 char *text;
64
65 if (count >= (1 << 20))
66 text = g_strdup_printf ("%dM", count >> 20);
67 else
68 text = g_strdup_printf ("%d", count);
69 gtk_label_set_text (GTK_LABEL (l), text);
70 g_free (text);
71 }
72
73 static void
cb_scale_changed(ResizeState * state)74 cb_scale_changed (ResizeState *state)
75 {
76 int cols, rows;
77 get_sizes (state, &cols, &rows);
78 set_count (state->columns_label, cols);
79 set_count (state->rows_label, rows);
80 gtk_widget_set_sensitive (state->ok_button,
81 gnm_sheet_valid_size (cols, rows));
82 }
83
84 static int
mylog2(int N)85 mylog2 (int N)
86 {
87 int l2 = 0;
88 while (N > 1)
89 N >>= 1, l2++;
90 return l2;
91 }
92
93 static void
init_scale(GtkWidget * scale,int N,int lo,int hi)94 init_scale (GtkWidget *scale, int N, int lo, int hi)
95 {
96 GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (scale));
97 g_object_set (G_OBJECT (adj),
98 "lower", (double)mylog2 (lo),
99 "upper", (double)mylog2 (hi) + 1.,
100 NULL);
101 gtk_adjustment_set_value (adj, mylog2 (N));
102 }
103
104 static void
cb_ok_clicked(ResizeState * state)105 cb_ok_clicked (ResizeState *state)
106 {
107 GSList *changed_sheets = NULL;
108 WorkbookControl *wbc;
109 Workbook *wb;
110 gboolean all_sheets;
111 int cols, rows;
112
113 get_sizes (state, &cols, &rows);
114 all_sheets = gtk_toggle_button_get_active
115 (GTK_TOGGLE_BUTTON (state->all_sheets_button));
116
117 wbc = GNM_WBC (state->wbcg);
118 wb = wb_control_get_workbook (wbc);
119
120 if (all_sheets) {
121 GPtrArray *sheets = workbook_sheets (wb);
122 unsigned ui;
123
124 for (ui = 0; ui < sheets->len; ui++) {
125 Sheet *this_sheet = g_ptr_array_index (sheets, ui);
126
127 if (this_sheet == state->sheet)
128 continue;
129
130 if (cols == gnm_sheet_get_max_cols (this_sheet) &&
131 rows == gnm_sheet_get_max_rows (this_sheet))
132 continue;
133
134 changed_sheets = g_slist_prepend (changed_sheets, this_sheet);
135 }
136 g_ptr_array_unref (sheets);
137 }
138
139 if (changed_sheets ||
140 cols != gnm_sheet_get_max_cols (state->sheet) ||
141 rows != gnm_sheet_get_max_rows (state->sheet)) {
142 /* We also append the sheet if it isn't changed in size */
143 /* to ensure that the focus stays on the current sheet. */
144 changed_sheets = g_slist_prepend (changed_sheets, state->sheet);
145 }
146
147
148
149 if (changed_sheets)
150 cmd_resize_sheets (wbc, changed_sheets,
151 cols, rows);
152
153 gtk_widget_destroy (state->dialog);
154 }
155
156 void
dialog_sheet_resize(WBCGtk * wbcg)157 dialog_sheet_resize (WBCGtk *wbcg)
158 {
159 GtkBuilder *gui;
160 ResizeState *state;
161 int slider_width;
162
163 if (gnm_dialog_raise_if_exists (wbcg, RESIZE_DIALOG_KEY))
164 return;
165 gui = gnm_gtk_builder_load ("res:ui/sheet-resize.ui", NULL, GO_CMD_CONTEXT (wbcg));
166 if (gui == NULL)
167 return;
168
169 state = g_new (ResizeState, 1);
170 state->wbcg = wbcg;
171 state->dialog = go_gtk_builder_get_widget (gui, "Resize");
172 state->sheet = wbcg_cur_sheet (wbcg);
173 g_return_if_fail (state->dialog != NULL);
174
175 slider_width = mylog2 (MAX (GNM_MAX_ROWS / GNM_MIN_ROWS,
176 GNM_MAX_COLS / GNM_MIN_COLS)) *
177 gnm_widget_measure_string (GTK_WIDGET (wbcg_toplevel (wbcg)),
178 "00");
179
180 state->columns_scale = go_gtk_builder_get_widget (gui, "columns_scale");
181 gtk_widget_set_size_request (state->columns_scale, slider_width, -1);
182 state->columns_label = go_gtk_builder_get_widget (gui, "columns_label");
183 state->rows_scale = go_gtk_builder_get_widget (gui, "rows_scale");
184 gtk_widget_set_size_request (state->rows_scale, slider_width, -1);
185 state->rows_label = go_gtk_builder_get_widget (gui, "rows_label");
186 state->all_sheets_button = go_gtk_builder_get_widget (gui, "all_sheets_button");
187 state->ok_button = go_gtk_builder_get_widget (gui, "ok_button");
188 state->cancel_button = go_gtk_builder_get_widget (gui, "cancel_button");
189
190 g_signal_connect_swapped (G_OBJECT (state->columns_scale),
191 "value-changed", G_CALLBACK (cb_scale_changed),
192 state);
193 init_scale (state->columns_scale,
194 gnm_sheet_get_max_cols (state->sheet),
195 GNM_MIN_COLS, GNM_MAX_COLS);
196
197 g_signal_connect_swapped (G_OBJECT (state->rows_scale),
198 "value-changed", G_CALLBACK (cb_scale_changed),
199 state);
200 init_scale (state->rows_scale,
201 gnm_sheet_get_max_rows (state->sheet),
202 GNM_MIN_ROWS, GNM_MAX_ROWS);
203
204 cb_scale_changed (state);
205
206 g_signal_connect_swapped (G_OBJECT (state->cancel_button),
207 "clicked", G_CALLBACK (gtk_widget_destroy),
208 state->dialog);
209
210 g_signal_connect_swapped (G_OBJECT (state->ok_button),
211 "clicked", G_CALLBACK (cb_ok_clicked),
212 state);
213
214 gnm_dialog_setup_destroy_handlers (GTK_DIALOG (state->dialog), wbcg,
215 GNM_DIALOG_DESTROY_SHEET_REMOVED);
216
217 gnm_keyed_dialog (wbcg, GTK_WINDOW (state->dialog),
218 RESIZE_DIALOG_KEY);
219
220 g_object_set_data_full (G_OBJECT (state->dialog),
221 "state", state,
222 (GDestroyNotify) g_free);
223 g_object_unref (gui);
224
225 gtk_widget_show (state->dialog);
226 }
227