Compilation: fix up tools includes.
[gnumeric.git] / src / tools / data-shuffling.c
blob924a81ba562552941a619ade9a05c4c7aa4ba106
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 "tools/data-shuffling.h"
39 #include "expr.h"
42 typedef struct {
43 GnmCellPos a;
44 GnmCellPos b;
45 } swap_t;
47 static void
48 swap_values (data_shuffling_t *ds,
49 int col_a, int row_a, int col_b, int row_b)
51 swap_t *s = g_new (swap_t, 1);
53 s->a.col = col_a;
54 s->a.row = row_a;
55 s->b.col = col_b;
56 s->b.row = row_b;
58 ds->changes = g_slist_prepend (ds->changes, s);
62 static void
63 shuffle_cols (data_shuffling_t *ds)
65 int i;
67 for (i = ds->a_col; i <= ds->b_col; i++) {
68 int rnd_col = (int) (ds->cols * random_01 () + ds->a_col);
70 if (i != rnd_col)
71 swap_values (ds, i, 0, rnd_col, 0);
75 static void
76 shuffle_rows (data_shuffling_t *ds)
78 int i;
80 for (i = ds->a_row; i <= ds->b_row; i++) {
81 int rnd_row = (int) (ds->rows * random_01 () + ds->a_row);
83 if (i != rnd_row)
84 swap_values (ds, 0, i, 0, rnd_row);
88 static void
89 shuffle_area (data_shuffling_t *ds)
91 int i, j;
92 int rnd_col;
93 int rnd_row;
95 for (i = ds->a_col; i <= ds->b_col; i++) {
96 rnd_col = (int) (ds->cols * random_01 () + ds->a_col);
98 for (j = ds->a_row; j <= ds->b_row; j++) {
99 rnd_row = (int) (ds->rows * random_01 () + ds->a_row);
101 swap_values (ds, i, j, rnd_col, rnd_row);
106 static void
107 init_shuffling_tool (data_shuffling_t *st, Sheet *sheet, GnmValue *range,
108 data_analysis_output_t *dao)
110 st->a_col = range->v_range.cell.a.col;
111 st->a_row = range->v_range.cell.a.row;
112 st->b_col = range->v_range.cell.b.col;
113 st->b_row = range->v_range.cell.b.row;
114 st->cols = st->b_col - st->a_col + 1;
115 st->rows = st->b_row - st->a_row + 1;
116 st->dao = dao;
117 st->sheet = sheet;
118 st->changes = NULL;
121 static void
122 do_swap_cells (data_shuffling_t *st, swap_t *sw)
124 GnmExprRelocateInfo reverse;
126 reverse.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE;
127 reverse.target_sheet = st->sheet;
128 reverse.origin_sheet = st->sheet;
129 st->tmp_area.end.col = st->tmp_area.start.col;
130 st->tmp_area.end.row = st->tmp_area.start.row;
132 /* Move A to a tmp_area. */
133 range_init (&reverse.origin, sw->a.col, sw->a.row, sw->a.col,
134 sw->a.row);
135 reverse.col_offset = st->tmp_area.start.col - sw->a.col;
136 reverse.row_offset = st->tmp_area.start.row - sw->a.row;
137 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
139 /* Move B to A. */
140 range_init (&reverse.origin, sw->b.col, sw->b.row, sw->b.col,
141 sw->b.row);
142 reverse.col_offset = sw->a.col - sw->b.col;
143 reverse.row_offset = sw->a.row - sw->b.row;
144 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
146 /* Move tmp_area to B. */
147 range_init (&reverse.origin, st->tmp_area.start.col,
148 st->tmp_area.start.row,
149 st->tmp_area.end.col, st->tmp_area.end.row);
150 reverse.col_offset = sw->b.col - st->tmp_area.start.col;
151 reverse.row_offset = sw->b.row - st->tmp_area.start.row;
152 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
155 static void
156 do_swap_cols (data_shuffling_t *st, swap_t *sw)
158 GnmExprRelocateInfo reverse;
160 reverse.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE;
161 reverse.target_sheet = st->sheet;
162 reverse.origin_sheet = st->sheet;
163 st->tmp_area.end.col = st->tmp_area.start.col;
164 st->tmp_area.end.row = st->tmp_area.start.row + st->rows - 1;
166 /* Move A to a tmp_area. */
167 range_init (&reverse.origin, sw->a.col, st->a_row, sw->a.col,
168 st->b_row);
169 reverse.col_offset = st->tmp_area.start.col - sw->a.col;
170 reverse.row_offset = st->tmp_area.start.row - st->a_row;
171 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
173 /* Move B to A. */
174 range_init (&reverse.origin, sw->b.col, st->a_row, sw->b.col,
175 st->b_row);
176 reverse.col_offset = sw->a.col - sw->b.col;
177 reverse.row_offset = 0;
178 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
180 /* Move tmp_area to B. */
181 range_init (&reverse.origin, st->tmp_area.start.col,
182 st->tmp_area.start.row,
183 st->tmp_area.end.col, st->tmp_area.end.row);
184 reverse.col_offset = sw->b.col - st->tmp_area.start.col;
185 reverse.row_offset = st->a_row - st->tmp_area.start.row;
186 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
189 static void
190 do_swap_rows (data_shuffling_t *st, swap_t *sw)
192 GnmExprRelocateInfo reverse;
194 reverse.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE;
195 reverse.target_sheet = st->sheet;
196 reverse.origin_sheet = st->sheet;
197 st->tmp_area.end.col = st->tmp_area.start.col + st->cols - 1;
198 st->tmp_area.end.row = st->tmp_area.start.row;
200 /* Move A to a tmp_area. */
201 range_init (&reverse.origin, st->a_col, sw->a.row, st->b_col,
202 sw->a.row);
203 reverse.col_offset = st->tmp_area.start.col - st->a_col;
204 reverse.row_offset = st->tmp_area.start.row - sw->a.row;
205 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
207 /* Move B to A. */
208 range_init (&reverse.origin, st->a_col, sw->b.row, st->b_col,
209 sw->b.row);
210 reverse.col_offset = 0;
211 reverse.row_offset = sw->a.row - sw->b.row;
212 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
214 /* Move tmp_area to B. */
215 range_init (&reverse.origin, st->tmp_area.start.col,
216 st->tmp_area.start.row,
217 st->tmp_area.end.col, st->tmp_area.end.row);
218 reverse.col_offset = st->a_col - st->tmp_area.start.col;
219 reverse.row_offset = sw->b.row - st->tmp_area.start.row;
220 sheet_move_range (&reverse, NULL, GO_CMD_CONTEXT (st->wbc));
223 static void
224 run_shuffling_tool (data_shuffling_t *st)
226 GSList *cur;
227 GnmCell *cell;
228 int i, j;
230 if (st->type == SHUFFLE_COLS) {
231 /* Find empty space. */
232 for (i = gnm_sheet_get_last_col (st->sheet); i >= 0; i--)
233 for (j = gnm_sheet_get_last_row (st->sheet); j >= 0; j--) {
234 cell = sheet_cell_get (st->sheet, i, j);
235 if (cell != NULL)
236 break;
237 else if (gnm_sheet_get_max_rows (st->sheet) - j >= st->rows)
238 goto cols_out;
240 cols_out:
241 if (i < 0)
242 return;
243 range_init (&st->tmp_area, i, j, i, j + st->rows - 1);
244 for (cur = st->changes; cur; cur = cur->next)
245 do_swap_cols (st, (swap_t *) cur->data);
246 } else if (st->type == SHUFFLE_ROWS) {
247 /* Find empty space. */
248 for (i = gnm_sheet_get_last_row (st->sheet); i >= 0; i--)
249 for (j = gnm_sheet_get_last_col (st->sheet); j >= 0; j--) {
250 cell = sheet_cell_get (st->sheet, j, i);
251 if (cell != NULL)
252 break;
253 else if (gnm_sheet_get_max_cols (st->sheet) - j >= st->cols)
254 goto rows_out;
256 rows_out:
257 if (i < 0)
258 return;
259 range_init (&st->tmp_area, j, i, j + st->cols - 1, i);
260 for (cur = st->changes; cur; cur = cur->next)
261 do_swap_rows (st, (swap_t *) cur->data);
262 } else {
263 /* SHUFFLE_AREA */
264 /* Find empty space. */
265 for (i = gnm_sheet_get_last_col (st->sheet); i >= 0; i--)
266 for (j = gnm_sheet_get_last_row (st->sheet); j >= 0; j--) {
267 cell = sheet_cell_get (st->sheet, i, j);
268 if (cell == NULL)
269 goto area_out;
271 area_out:
272 if (i < 0)
273 return;
274 range_init (&st->tmp_area, i, j, i, j);
275 for (cur = st->changes; cur; cur = cur->next)
276 do_swap_cells (st, (swap_t *) cur->data);
281 * data_shuffling: (skip)
283 data_shuffling_t *
284 data_shuffling (WorkbookControl *wbc,
285 data_analysis_output_t *dao,
286 Sheet *sheet,
287 GnmValue *input_range,
288 int shuffling_type)
290 data_shuffling_t *st = g_new (data_shuffling_t, 1);
292 dao_prepare_output (wbc, dao, _("Shuffled"));
294 init_shuffling_tool (st, sheet, input_range, dao);
295 st->type = shuffling_type;
296 st->wbc = wbc;
298 if (shuffling_type == SHUFFLE_COLS)
299 shuffle_cols (st);
300 else if (shuffling_type == SHUFFLE_ROWS)
301 shuffle_rows (st);
302 else /* SHUFFLE_AREA */
303 shuffle_area (st);
305 return st;
308 void
309 data_shuffling_redo (data_shuffling_t *st)
311 run_shuffling_tool (st);
312 dao_autofit_columns (st->dao);
313 sheet_redraw_all (st->sheet, TRUE);
315 /* Reverse the list for undo. */
316 st->changes = g_slist_reverse (st->changes);
319 void
320 data_shuffling_free (data_shuffling_t *st)
322 dao_free (st->dao);
323 g_slist_free_full (st->changes, g_free);