GUI: Dead kittens.
[gnumeric.git] / src / tools / data-shuffling.c
blob113c9e2315075e83fb600b38c1575e5a37506e0c
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /*
4 * data-shuffling.c:
6 * Author:
7 * Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi>
9 * (C) Copyright 2003 by Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi>
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>
29 #include <sheet.h>
30 #include <sheet-filter.h>
31 #include <cell.h>
32 #include <ranges.h>
33 #include <value.h>
34 #include <command-context.h>
35 #include <goffice/goffice.h>
37 #include "gnm-random.h"
38 #include "data-shuffling.h"
39 #include "dao.h"
40 #include "expr.h"
43 typedef struct {
44 GnmCellPos a;
45 GnmCellPos b;
46 } swap_t;
48 static void
49 swap_values (data_shuffling_t *ds,
50 int col_a, int row_a, int col_b, int row_b)
52 swap_t *s = g_new (swap_t, 1);
54 s->a.col = col_a;
55 s->a.row = row_a;
56 s->b.col = col_b;
57 s->b.row = row_b;
59 ds->changes = g_slist_prepend (ds->changes, s);
63 static void
64 shuffle_cols (data_shuffling_t *ds)
66 int i;
68 for (i = ds->a_col; i <= ds->b_col; i++) {
69 int rnd_col = (int) (ds->cols * random_01 () + ds->a_col);
71 if (i != rnd_col)
72 swap_values (ds, i, 0, rnd_col, 0);
76 static void
77 shuffle_rows (data_shuffling_t *ds)
79 int i;
81 for (i = ds->a_row; i <= ds->b_row; i++) {
82 int rnd_row = (int) (ds->rows * random_01 () + ds->a_row);
84 if (i != rnd_row)
85 swap_values (ds, 0, i, 0, rnd_row);
89 static void
90 shuffle_area (data_shuffling_t *ds)
92 int i, j;
93 int rnd_col;
94 int rnd_row;
96 for (i = ds->a_col; i <= ds->b_col; i++) {
97 rnd_col = (int) (ds->cols * random_01 () + ds->a_col);
99 for (j = ds->a_row; j <= ds->b_row; j++) {
100 rnd_row = (int) (ds->rows * random_01 () + ds->a_row);
102 swap_values (ds, i, j, rnd_col, rnd_row);
107 static void
108 init_shuffling_tool (data_shuffling_t *st, Sheet *sheet, GnmValue *range,
109 data_analysis_output_t *dao)
111 st->a_col = range->v_range.cell.a.col;
112 st->a_row = range->v_range.cell.a.row;
113 st->b_col = range->v_range.cell.b.col;
114 st->b_row = range->v_range.cell.b.row;
115 st->cols = st->b_col - st->a_col + 1;
116 st->rows = st->b_row - st->a_row + 1;
117 st->dao = dao;
118 st->sheet = sheet;
119 st->changes = NULL;
122 static void
123 do_swap_cells (data_shuffling_t *st, swap_t *sw)
125 GnmExprRelocateInfo reverse;
127 reverse.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE;
128 reverse.target_sheet = st->sheet;
129 reverse.origin_sheet = st->sheet;
130 st->tmp_area.end.col = st->tmp_area.start.col;
131 st->tmp_area.end.row = st->tmp_area.start.row;
133 /* Move A to a tmp_area. */
134 range_init (&reverse.origin, sw->a.col, sw->a.row, sw->a.col,
135 sw->a.row);
136 reverse.col_offset = st->tmp_area.start.col - sw->a.col;
137 reverse.row_offset = st->tmp_area.start.row - sw->a.row;
138 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
140 /* Move B to A. */
141 range_init (&reverse.origin, sw->b.col, sw->b.row, sw->b.col,
142 sw->b.row);
143 reverse.col_offset = sw->a.col - sw->b.col;
144 reverse.row_offset = sw->a.row - sw->b.row;
145 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
147 /* Move tmp_area to B. */
148 range_init (&reverse.origin, st->tmp_area.start.col,
149 st->tmp_area.start.row,
150 st->tmp_area.end.col, st->tmp_area.end.row);
151 reverse.col_offset = sw->b.col - st->tmp_area.start.col;
152 reverse.row_offset = sw->b.row - st->tmp_area.start.row;
153 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
156 static void
157 do_swap_cols (data_shuffling_t *st, swap_t *sw)
159 GnmExprRelocateInfo reverse;
161 reverse.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE;
162 reverse.target_sheet = st->sheet;
163 reverse.origin_sheet = st->sheet;
164 st->tmp_area.end.col = st->tmp_area.start.col;
165 st->tmp_area.end.row = st->tmp_area.start.row + st->rows - 1;
167 /* Move A to a tmp_area. */
168 range_init (&reverse.origin, sw->a.col, st->a_row, sw->a.col,
169 st->b_row);
170 reverse.col_offset = st->tmp_area.start.col - sw->a.col;
171 reverse.row_offset = st->tmp_area.start.row - st->a_row;
172 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
174 /* Move B to A. */
175 range_init (&reverse.origin, sw->b.col, st->a_row, sw->b.col,
176 st->b_row);
177 reverse.col_offset = sw->a.col - sw->b.col;
178 reverse.row_offset = 0;
179 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
181 /* Move tmp_area to B. */
182 range_init (&reverse.origin, st->tmp_area.start.col,
183 st->tmp_area.start.row,
184 st->tmp_area.end.col, st->tmp_area.end.row);
185 reverse.col_offset = sw->b.col - st->tmp_area.start.col;
186 reverse.row_offset = st->a_row - st->tmp_area.start.row;
187 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
190 static void
191 do_swap_rows (data_shuffling_t *st, swap_t *sw)
193 GnmExprRelocateInfo reverse;
195 reverse.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE;
196 reverse.target_sheet = st->sheet;
197 reverse.origin_sheet = st->sheet;
198 st->tmp_area.end.col = st->tmp_area.start.col + st->cols - 1;
199 st->tmp_area.end.row = st->tmp_area.start.row;
201 /* Move A to a tmp_area. */
202 range_init (&reverse.origin, st->a_col, sw->a.row, st->b_col,
203 sw->a.row);
204 reverse.col_offset = st->tmp_area.start.col - st->a_col;
205 reverse.row_offset = st->tmp_area.start.row - sw->a.row;
206 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
208 /* Move B to A. */
209 range_init (&reverse.origin, st->a_col, sw->b.row, st->b_col,
210 sw->b.row);
211 reverse.col_offset = 0;
212 reverse.row_offset = sw->a.row - sw->b.row;
213 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
215 /* Move tmp_area to B. */
216 range_init (&reverse.origin, st->tmp_area.start.col,
217 st->tmp_area.start.row,
218 st->tmp_area.end.col, st->tmp_area.end.row);
219 reverse.col_offset = st->a_col - st->tmp_area.start.col;
220 reverse.row_offset = sw->b.row - st->tmp_area.start.row;
221 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
224 static void
225 run_shuffling_tool (data_shuffling_t *st)
227 GSList *cur;
228 GnmCell *cell;
229 int i, j;
231 if (st->type == SHUFFLE_COLS) {
232 /* Find empty space. */
233 for (i = gnm_sheet_get_last_col (st->sheet); i >= 0; i--)
234 for (j = gnm_sheet_get_last_row (st->sheet); j >= 0; j--) {
235 cell = sheet_cell_get (st->sheet, i, j);
236 if (cell != NULL)
237 break;
238 else if (gnm_sheet_get_max_rows (st->sheet) - j >= st->rows)
239 goto cols_out;
241 cols_out:
242 if (i < 0)
243 return;
244 range_init (&st->tmp_area, i, j, i, j + st->rows - 1);
245 for (cur = st->changes; cur; cur = cur->next)
246 do_swap_cols (st, (swap_t *) cur->data);
247 } else if (st->type == SHUFFLE_ROWS) {
248 /* Find empty space. */
249 for (i = gnm_sheet_get_last_row (st->sheet); i >= 0; i--)
250 for (j = gnm_sheet_get_last_col (st->sheet); j >= 0; j--) {
251 cell = sheet_cell_get (st->sheet, j, i);
252 if (cell != NULL)
253 break;
254 else if (gnm_sheet_get_max_cols (st->sheet) - j >= st->cols)
255 goto rows_out;
257 rows_out:
258 if (i < 0)
259 return;
260 range_init (&st->tmp_area, j, i, j + st->cols - 1, i);
261 for (cur = st->changes; cur; cur = cur->next)
262 do_swap_rows (st, (swap_t *) cur->data);
263 } else {
264 /* SHUFFLE_AREA */
265 /* Find empty space. */
266 for (i = gnm_sheet_get_last_col (st->sheet); i >= 0; i--)
267 for (j = gnm_sheet_get_last_row (st->sheet); j >= 0; j--) {
268 cell = sheet_cell_get (st->sheet, i, j);
269 if (cell == NULL)
270 goto area_out;
272 area_out:
273 if (i < 0)
274 return;
275 range_init (&st->tmp_area, i, j, i, j);
276 for (cur = st->changes; cur; cur = cur->next)
277 do_swap_cells (st, (swap_t *) cur->data);
281 data_shuffling_t *
282 data_shuffling (WorkbookControl *wbc,
283 data_analysis_output_t *dao,
284 Sheet *sheet,
285 GnmValue *input_range,
286 int shuffling_type)
288 data_shuffling_t *st = g_new (data_shuffling_t, 1);
290 dao_prepare_output (wbc, dao, _("Shuffled"));
292 init_shuffling_tool (st, sheet, input_range, dao);
293 st->type = shuffling_type;
294 st->wbc = wbc;
296 if (shuffling_type == SHUFFLE_COLS)
297 shuffle_cols (st);
298 else if (shuffling_type == SHUFFLE_ROWS)
299 shuffle_rows (st);
300 else /* SHUFFLE_AREA */
301 shuffle_area (st);
303 return st;
306 void
307 data_shuffling_redo (data_shuffling_t *st)
309 run_shuffling_tool (st);
310 dao_autofit_columns (st->dao);
311 sheet_redraw_all (st->sheet, TRUE);
313 /* Reverse the list for undo. */
314 st->changes = g_slist_reverse (st->changes);
317 void
318 data_shuffling_free (data_shuffling_t *st)
320 dao_free (st->dao);
321 g_slist_free_full (st->changes, g_free);