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>
29 #include <sheet-filter.h>
33 #include <command-context.h>
34 #include <goffice/goffice.h>
36 #include <gnm-random.h>
37 #include <tools/data-shuffling.h>
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);
57 ds
->changes
= g_slist_prepend (ds
->changes
, s
);
62 shuffle_cols (data_shuffling_t
*ds
)
66 for (i
= ds
->a_col
; i
<= ds
->b_col
; i
++) {
67 int rnd_col
= (int) (ds
->cols
* random_01 () + ds
->a_col
);
70 swap_values (ds
, i
, 0, rnd_col
, 0);
75 shuffle_rows (data_shuffling_t
*ds
)
79 for (i
= ds
->a_row
; i
<= ds
->b_row
; i
++) {
80 int rnd_row
= (int) (ds
->rows
* random_01 () + ds
->a_row
);
83 swap_values (ds
, 0, i
, 0, rnd_row
);
88 shuffle_area (data_shuffling_t
*ds
)
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
);
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;
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
,
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
));
139 range_init (&reverse
.origin
, sw
->b
.col
, sw
->b
.row
, sw
->b
.col
,
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
));
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
,
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
));
173 range_init (&reverse
.origin
, sw
->b
.col
, st
->a_row
, sw
->b
.col
,
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
));
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
,
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
));
207 range_init (&reverse
.origin
, st
->a_col
, sw
->b
.row
, st
->b_col
,
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
));
223 run_shuffling_tool (data_shuffling_t
*st
)
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
);
236 else if (gnm_sheet_get_max_rows (st
->sheet
) - j
>= st
->rows
)
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
);
252 else if (gnm_sheet_get_max_cols (st
->sheet
) - j
>= st
->cols
)
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
);
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
);
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)
283 data_shuffling (WorkbookControl
*wbc
,
284 data_analysis_output_t
*dao
,
286 GnmValue
*input_range
,
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
;
297 if (shuffling_type
== SHUFFLE_COLS
)
299 else if (shuffling_type
== SHUFFLE_ROWS
)
301 else /* SHUFFLE_AREA */
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
);
319 data_shuffling_free (data_shuffling_t
*st
)
322 g_slist_free_full (st
->changes
, g_free
);