1.12.42
[gnumeric.git] / src / tools / data-shuffling.c
blob5173fd824fae33bf75f6f5f3afd72ee525d72491
2 /*
3 * data-shuffling.c:
5 * Author:
6 * Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi>
8 * (C) Copyright 2003 by Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <https://www.gnu.org/licenses/>.
24 #include <gnumeric-config.h>
25 #include <glib/gi18n-lib.h>
26 #include <gnumeric.h>
28 #include <sheet.h>
29 #include <sheet-filter.h>
30 #include <cell.h>
31 #include <ranges.h>
32 #include <value.h>
33 #include <command-context.h>
34 #include <goffice/goffice.h>
36 #include <gnm-random.h>
37 #include <tools/data-shuffling.h>
38 #include <expr.h>
41 typedef struct {
42 GnmCellPos a;
43 GnmCellPos b;
44 } swap_t;
46 static void
47 swap_values (data_shuffling_t *ds,
48 int col_a, int row_a, int col_b, int row_b)
50 swap_t *s = g_new (swap_t, 1);
52 s->a.col = col_a;
53 s->a.row = row_a;
54 s->b.col = col_b;
55 s->b.row = row_b;
57 ds->changes = g_slist_prepend (ds->changes, s);
61 static void
62 shuffle_cols (data_shuffling_t *ds)
64 int i;
66 for (i = ds->a_col; i <= ds->b_col; i++) {
67 int rnd_col = (int) (ds->cols * random_01 () + ds->a_col);
69 if (i != rnd_col)
70 swap_values (ds, i, 0, rnd_col, 0);
74 static void
75 shuffle_rows (data_shuffling_t *ds)
77 int i;
79 for (i = ds->a_row; i <= ds->b_row; i++) {
80 int rnd_row = (int) (ds->rows * random_01 () + ds->a_row);
82 if (i != rnd_row)
83 swap_values (ds, 0, i, 0, rnd_row);
87 static void
88 shuffle_area (data_shuffling_t *ds)
90 int i, j;
91 int rnd_col;
92 int rnd_row;
94 for (i = ds->a_col; i <= ds->b_col; i++) {
95 rnd_col = (int) (ds->cols * random_01 () + ds->a_col);
97 for (j = ds->a_row; j <= ds->b_row; j++) {
98 rnd_row = (int) (ds->rows * random_01 () + ds->a_row);
100 swap_values (ds, i, j, rnd_col, rnd_row);
105 static void
106 init_shuffling_tool (data_shuffling_t *st, Sheet *sheet, GnmValue *range,
107 data_analysis_output_t *dao)
109 st->a_col = range->v_range.cell.a.col;
110 st->a_row = range->v_range.cell.a.row;
111 st->b_col = range->v_range.cell.b.col;
112 st->b_row = range->v_range.cell.b.row;
113 st->cols = st->b_col - st->a_col + 1;
114 st->rows = st->b_row - st->a_row + 1;
115 st->dao = dao;
116 st->sheet = sheet;
117 st->changes = NULL;
120 static void
121 do_swap_cells (data_shuffling_t *st, swap_t *sw)
123 GnmExprRelocateInfo reverse;
125 reverse.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE;
126 reverse.target_sheet = st->sheet;
127 reverse.origin_sheet = st->sheet;
128 st->tmp_area.end.col = st->tmp_area.start.col;
129 st->tmp_area.end.row = st->tmp_area.start.row;
131 /* Move A to a tmp_area. */
132 range_init (&reverse.origin, sw->a.col, sw->a.row, sw->a.col,
133 sw->a.row);
134 reverse.col_offset = st->tmp_area.start.col - sw->a.col;
135 reverse.row_offset = st->tmp_area.start.row - sw->a.row;
136 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
138 /* Move B to A. */
139 range_init (&reverse.origin, sw->b.col, sw->b.row, sw->b.col,
140 sw->b.row);
141 reverse.col_offset = sw->a.col - sw->b.col;
142 reverse.row_offset = sw->a.row - sw->b.row;
143 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
145 /* Move tmp_area to B. */
146 range_init (&reverse.origin, st->tmp_area.start.col,
147 st->tmp_area.start.row,
148 st->tmp_area.end.col, st->tmp_area.end.row);
149 reverse.col_offset = sw->b.col - st->tmp_area.start.col;
150 reverse.row_offset = sw->b.row - st->tmp_area.start.row;
151 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
154 static void
155 do_swap_cols (data_shuffling_t *st, swap_t *sw)
157 GnmExprRelocateInfo reverse;
159 reverse.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE;
160 reverse.target_sheet = st->sheet;
161 reverse.origin_sheet = st->sheet;
162 st->tmp_area.end.col = st->tmp_area.start.col;
163 st->tmp_area.end.row = st->tmp_area.start.row + st->rows - 1;
165 /* Move A to a tmp_area. */
166 range_init (&reverse.origin, sw->a.col, st->a_row, sw->a.col,
167 st->b_row);
168 reverse.col_offset = st->tmp_area.start.col - sw->a.col;
169 reverse.row_offset = st->tmp_area.start.row - st->a_row;
170 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
172 /* Move B to A. */
173 range_init (&reverse.origin, sw->b.col, st->a_row, sw->b.col,
174 st->b_row);
175 reverse.col_offset = sw->a.col - sw->b.col;
176 reverse.row_offset = 0;
177 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
179 /* Move tmp_area to B. */
180 range_init (&reverse.origin, st->tmp_area.start.col,
181 st->tmp_area.start.row,
182 st->tmp_area.end.col, st->tmp_area.end.row);
183 reverse.col_offset = sw->b.col - st->tmp_area.start.col;
184 reverse.row_offset = st->a_row - st->tmp_area.start.row;
185 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
188 static void
189 do_swap_rows (data_shuffling_t *st, swap_t *sw)
191 GnmExprRelocateInfo reverse;
193 reverse.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE;
194 reverse.target_sheet = st->sheet;
195 reverse.origin_sheet = st->sheet;
196 st->tmp_area.end.col = st->tmp_area.start.col + st->cols - 1;
197 st->tmp_area.end.row = st->tmp_area.start.row;
199 /* Move A to a tmp_area. */
200 range_init (&reverse.origin, st->a_col, sw->a.row, st->b_col,
201 sw->a.row);
202 reverse.col_offset = st->tmp_area.start.col - st->a_col;
203 reverse.row_offset = st->tmp_area.start.row - sw->a.row;
204 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
206 /* Move B to A. */
207 range_init (&reverse.origin, st->a_col, sw->b.row, st->b_col,
208 sw->b.row);
209 reverse.col_offset = 0;
210 reverse.row_offset = sw->a.row - sw->b.row;
211 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
213 /* Move tmp_area to B. */
214 range_init (&reverse.origin, st->tmp_area.start.col,
215 st->tmp_area.start.row,
216 st->tmp_area.end.col, st->tmp_area.end.row);
217 reverse.col_offset = st->a_col - st->tmp_area.start.col;
218 reverse.row_offset = sw->b.row - st->tmp_area.start.row;
219 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
222 static void
223 run_shuffling_tool (data_shuffling_t *st)
225 GSList *cur;
226 GnmCell *cell;
227 int i, j;
229 if (st->type == SHUFFLE_COLS) {
230 /* Find empty space. */
231 for (i = gnm_sheet_get_last_col (st->sheet); i >= 0; i--)
232 for (j = gnm_sheet_get_last_row (st->sheet); j >= 0; j--) {
233 cell = sheet_cell_get (st->sheet, i, j);
234 if (cell != NULL)
235 break;
236 else if (gnm_sheet_get_max_rows (st->sheet) - j >= st->rows)
237 goto cols_out;
239 cols_out:
240 if (i < 0)
241 return;
242 range_init (&st->tmp_area, i, j, i, j + st->rows - 1);
243 for (cur = st->changes; cur; cur = cur->next)
244 do_swap_cols (st, (swap_t *) cur->data);
245 } else if (st->type == SHUFFLE_ROWS) {
246 /* Find empty space. */
247 for (i = gnm_sheet_get_last_row (st->sheet); i >= 0; i--)
248 for (j = gnm_sheet_get_last_col (st->sheet); j >= 0; j--) {
249 cell = sheet_cell_get (st->sheet, j, i);
250 if (cell != NULL)
251 break;
252 else if (gnm_sheet_get_max_cols (st->sheet) - j >= st->cols)
253 goto rows_out;
255 rows_out:
256 if (i < 0)
257 return;
258 range_init (&st->tmp_area, j, i, j + st->cols - 1, i);
259 for (cur = st->changes; cur; cur = cur->next)
260 do_swap_rows (st, (swap_t *) cur->data);
261 } else {
262 /* SHUFFLE_AREA */
263 /* Find empty space. */
264 for (i = gnm_sheet_get_last_col (st->sheet); i >= 0; i--)
265 for (j = gnm_sheet_get_last_row (st->sheet); j >= 0; j--) {
266 cell = sheet_cell_get (st->sheet, i, j);
267 if (cell == NULL)
268 goto area_out;
270 area_out:
271 if (i < 0)
272 return;
273 range_init (&st->tmp_area, i, j, i, j);
274 for (cur = st->changes; cur; cur = cur->next)
275 do_swap_cells (st, (swap_t *) cur->data);
280 * data_shuffling: (skip)
282 data_shuffling_t *
283 data_shuffling (WorkbookControl *wbc,
284 data_analysis_output_t *dao,
285 Sheet *sheet,
286 GnmValue *input_range,
287 int shuffling_type)
289 data_shuffling_t *st = g_new (data_shuffling_t, 1);
291 dao_prepare_output (wbc, dao, _("Shuffled"));
293 init_shuffling_tool (st, sheet, input_range, dao);
294 st->type = shuffling_type;
295 st->wbc = wbc;
297 if (shuffling_type == SHUFFLE_COLS)
298 shuffle_cols (st);
299 else if (shuffling_type == SHUFFLE_ROWS)
300 shuffle_rows (st);
301 else /* SHUFFLE_AREA */
302 shuffle_area (st);
304 return st;
307 void
308 data_shuffling_redo (data_shuffling_t *st)
310 run_shuffling_tool (st);
311 dao_autofit_columns (st->dao);
312 sheet_redraw_all (st->sheet, TRUE);
314 /* Reverse the list for undo. */
315 st->changes = g_slist_reverse (st->changes);
318 void
319 data_shuffling_free (data_shuffling_t *st)
321 dao_free (st->dao);
322 g_slist_free_full (st->changes, g_free);