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 "data-shuffling.h"
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);
59 ds
->changes
= g_slist_prepend (ds
->changes
, s
);
64 shuffle_cols (data_shuffling_t
*ds
)
68 for (i
= ds
->a_col
; i
<= ds
->b_col
; i
++) {
69 int rnd_col
= (int) (ds
->cols
* random_01 () + ds
->a_col
);
72 swap_values (ds
, i
, 0, rnd_col
, 0);
77 shuffle_rows (data_shuffling_t
*ds
)
81 for (i
= ds
->a_row
; i
<= ds
->b_row
; i
++) {
82 int rnd_row
= (int) (ds
->rows
* random_01 () + ds
->a_row
);
85 swap_values (ds
, 0, i
, 0, rnd_row
);
90 shuffle_area (data_shuffling_t
*ds
)
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
);
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;
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
,
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
));
141 range_init (&reverse
.origin
, sw
->b
.col
, sw
->b
.row
, sw
->b
.col
,
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
));
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
,
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
));
175 range_init (&reverse
.origin
, sw
->b
.col
, st
->a_row
, sw
->b
.col
,
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
));
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
,
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
));
209 range_init (&reverse
.origin
, st
->a_col
, sw
->b
.row
, st
->b_col
,
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
));
225 run_shuffling_tool (data_shuffling_t
*st
)
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
);
238 else if (gnm_sheet_get_max_rows (st
->sheet
) - j
>= st
->rows
)
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
);
254 else if (gnm_sheet_get_max_cols (st
->sheet
) - j
>= st
->cols
)
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
);
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
);
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
);
282 data_shuffling (WorkbookControl
*wbc
,
283 data_analysis_output_t
*dao
,
285 GnmValue
*input_range
,
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
;
296 if (shuffling_type
== SHUFFLE_COLS
)
298 else if (shuffling_type
== SHUFFLE_ROWS
)
300 else /* SHUFFLE_AREA */
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
);
318 data_shuffling_free (data_shuffling_t
*st
)
321 g_slist_free_full (st
->changes
, g_free
);