1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
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>
30 #include <sheet-filter.h>
34 #include <command-context.h>
35 #include <goffice/goffice.h>
37 #include "gnm-random.h"
38 #include "tools/data-shuffling.h"
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);
58 ds
->changes
= g_slist_prepend (ds
->changes
, s
);
63 shuffle_cols (data_shuffling_t
*ds
)
67 for (i
= ds
->a_col
; i
<= ds
->b_col
; i
++) {
68 int rnd_col
= (int) (ds
->cols
* random_01 () + ds
->a_col
);
71 swap_values (ds
, i
, 0, rnd_col
, 0);
76 shuffle_rows (data_shuffling_t
*ds
)
80 for (i
= ds
->a_row
; i
<= ds
->b_row
; i
++) {
81 int rnd_row
= (int) (ds
->rows
* random_01 () + ds
->a_row
);
84 swap_values (ds
, 0, i
, 0, rnd_row
);
89 shuffle_area (data_shuffling_t
*ds
)
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
);
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;
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
,
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
));
140 range_init (&reverse
.origin
, sw
->b
.col
, sw
->b
.row
, sw
->b
.col
,
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
));
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
,
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
));
174 range_init (&reverse
.origin
, sw
->b
.col
, st
->a_row
, sw
->b
.col
,
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
));
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
,
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
));
208 range_init (&reverse
.origin
, st
->a_col
, sw
->b
.row
, st
->b_col
,
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
));
224 run_shuffling_tool (data_shuffling_t
*st
)
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
);
237 else if (gnm_sheet_get_max_rows (st
->sheet
) - j
>= st
->rows
)
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
);
253 else if (gnm_sheet_get_max_cols (st
->sheet
) - j
>= st
->cols
)
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
);
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
);
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)
284 data_shuffling (WorkbookControl
*wbc
,
285 data_analysis_output_t
*dao
,
287 GnmValue
*input_range
,
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
;
298 if (shuffling_type
== SHUFFLE_COLS
)
300 else if (shuffling_type
== SHUFFLE_ROWS
)
302 else /* SHUFFLE_AREA */
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
);
320 data_shuffling_free (data_shuffling_t
*st
)
323 g_slist_free_full (st
->changes
, g_free
);