Update Spanish translation
[gnumeric.git] / src / gnm-sheet-slicer.c
blob04838109600008e6cdadb2d7851dec1984698891
1 /*
2 * gnm-sheet-slicer.c:
4 * Copyright (C) 2008-2009 Jody Goldberg (jody@gnome.org)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) version 3.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19 * USA
22 #include <gnumeric-config.h>
23 #include <gnm-sheet-slicer.h>
24 #include <go-data-slicer-impl.h>
25 #include <go-data-slicer-field-impl.h>
26 #include <go-data-cache.h>
27 #include <sheet.h>
28 #include <ranges.h>
30 #include <gsf/gsf-impl-utils.h>
31 #include <glib/gi18n-lib.h>
32 #include <string.h>
34 #include <glib-object.h>
36 struct _GnmSheetSlicer {
37 GODataSlicer base;
39 Sheet *sheet;
40 GnmRange range;
42 /* Offsets from the top-left (in LTR) pos range */
43 unsigned int first_header_row, first_data_row, first_data_col;
44 unsigned int row_page_count, col_page_count;
46 struct {
47 gboolean headers_col, headers_row, stripes_col, stripes_row, last_col, last_row;
48 } show;
50 GnmSheetSlicerLayout layout;
52 typedef GODataSlicerClass GnmSheetSlicerClass;
54 #define GNM_SHEET_SLICER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GNM_SHEET_SLICER_TYPE, GnmSheetSlicerClass))
55 #define GNM_IS_SHEET_SLICER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GNM_SHEET_SLICER_TYPE))
56 #define GNM_SHEET_SLICER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GNM_SHEET_SLICER_TYPE, GnmSheetSlicerClass))
58 enum {
59 PROP_0,
60 PROP_SHEET,
61 PROP_RANGE,
63 PROP_FIRST_HEADER_ROW,
64 PROP_FIRST_DATA_COL,
65 PROP_FIRST_DATA_ROW,
67 PROP_SHOW_HEADERS_COL,
68 PROP_SHOW_HEADERS_ROW,
69 PROP_SHOW_STRIPES_COL,
70 PROP_SHOW_STRIPES_ROW,
71 PROP_SHOW_LAST_COL,
72 PROP_SHOW_LAST_ROW,
74 PROP_LAYOUT
77 static GObjectClass *parent_klass;
78 static void
79 gnm_sheet_slicer_init (GnmSheetSlicer *gss)
81 gss->sheet = NULL;
82 gss->first_header_row = gss->first_data_row = gss->first_data_col = gss->row_page_count = gss->col_page_count = 0;
85 static void
86 gnm_sheet_slicer_finalize (GObject *obj)
88 GnmSheetSlicer *gss = (GnmSheetSlicer *)obj;
90 if (NULL != gss->sheet) {
91 g_warning ("finalizing a slicer that is still attached to a sheet");
94 (parent_klass->finalize) (obj);
97 static void
98 gnm_sheet_slicer_set_property (GObject *obj, guint property_id,
99 GValue const *value, GParamSpec *pspec)
101 GnmSheetSlicer *gss = (GnmSheetSlicer *)obj;
103 switch (property_id) {
104 case PROP_SHEET : gnm_sheet_slicer_set_sheet (gss, g_value_get_object (value)); break;
105 case PROP_RANGE : gnm_sheet_slicer_set_range (gss, g_value_get_boxed (value)); break;
106 case PROP_FIRST_HEADER_ROW : gss->first_header_row = g_value_get_uint (value); break;
107 case PROP_FIRST_DATA_COL : gss->first_data_col = g_value_get_uint (value); break;
108 case PROP_FIRST_DATA_ROW : gss->first_data_row = g_value_get_uint (value); break;
110 case PROP_SHOW_HEADERS_COL : gss->show.headers_col = g_value_get_boolean (value); break;
111 case PROP_SHOW_HEADERS_ROW : gss->show.headers_row = g_value_get_boolean (value); break;
112 case PROP_SHOW_STRIPES_COL : gss->show.stripes_col = g_value_get_boolean (value); break;
113 case PROP_SHOW_STRIPES_ROW : gss->show.stripes_row = g_value_get_boolean (value); break;
114 case PROP_SHOW_LAST_COL : gss->show.last_col = g_value_get_boolean (value); break;
115 case PROP_SHOW_LAST_ROW : gss->show.last_row = g_value_get_boolean (value); break;
117 case PROP_LAYOUT: gnm_sheet_slicer_set_layout (gss, g_value_get_enum (value)); break;
118 default:
119 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
123 static void
124 gnm_sheet_slicer_get_property (GObject *obj, guint property_id,
125 GValue *value, GParamSpec *pspec)
127 GnmSheetSlicer const *gss = (GnmSheetSlicer const *)obj;
128 switch (property_id) {
129 case PROP_SHEET : g_value_set_object (value, gss->sheet); break;
130 case PROP_RANGE : g_value_set_boxed (value, &gss->range); break;
131 case PROP_FIRST_HEADER_ROW : g_value_set_uint (value, gss->first_header_row ); break;
132 case PROP_FIRST_DATA_COL : g_value_set_uint (value, gss->first_data_col); break;
133 case PROP_FIRST_DATA_ROW : g_value_set_uint (value, gss->first_data_row); break;
135 case PROP_SHOW_HEADERS_COL : g_value_set_boolean (value, gss->show.headers_col); break;
136 case PROP_SHOW_HEADERS_ROW : g_value_set_boolean (value, gss->show.headers_row); break;
137 case PROP_SHOW_STRIPES_COL : g_value_set_boolean (value, gss->show.stripes_col); break;
138 case PROP_SHOW_STRIPES_ROW : g_value_set_boolean (value, gss->show.stripes_row); break;
139 case PROP_SHOW_LAST_COL : g_value_set_boolean (value, gss->show.last_col); break;
140 case PROP_SHOW_LAST_ROW : g_value_set_boolean (value, gss->show.last_row); break;
142 case PROP_LAYOUT : g_value_set_enum (value, gss->layout); break;
143 default:
144 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
148 static void
149 gnm_sheet_slicer_class_init (GnmSheetSlicerClass *klass)
151 GObjectClass *gobject_class = (GObjectClass *)klass;
152 gobject_class->set_property = gnm_sheet_slicer_set_property;
153 gobject_class->get_property = gnm_sheet_slicer_get_property;
154 gobject_class->finalize = gnm_sheet_slicer_finalize;
156 g_object_class_install_property (gobject_class, PROP_SHEET,
157 g_param_spec_object ("sheet", NULL, NULL, GNM_SHEET_TYPE,
158 GSF_PARAM_STATIC | G_PARAM_READWRITE));
159 g_object_class_install_property (gobject_class, PROP_RANGE,
160 g_param_spec_boxed ("range", NULL, NULL, gnm_range_get_type (),
161 GSF_PARAM_STATIC | G_PARAM_READWRITE));
162 g_object_class_install_property (gobject_class, PROP_FIRST_HEADER_ROW,
163 g_param_spec_uint ("first-header-row", NULL, NULL, 0, GNM_MAX_ROWS, 0,
164 GSF_PARAM_STATIC | G_PARAM_READWRITE));
165 g_object_class_install_property (gobject_class, PROP_FIRST_DATA_COL,
166 g_param_spec_uint ("first-data-col", NULL, NULL, 0, GNM_MAX_COLS, 0,
167 GSF_PARAM_STATIC | G_PARAM_READWRITE));
168 g_object_class_install_property (gobject_class, PROP_FIRST_DATA_ROW,
169 g_param_spec_uint ("first-data-row", NULL, NULL, 0, GNM_MAX_ROWS, 0,
170 GSF_PARAM_STATIC | G_PARAM_READWRITE));
172 g_object_class_install_property (gobject_class, PROP_SHOW_HEADERS_COL,
173 g_param_spec_boolean ("show-headers-col", NULL, NULL, TRUE,
174 GSF_PARAM_STATIC | G_PARAM_READWRITE));
175 g_object_class_install_property (gobject_class, PROP_SHOW_HEADERS_ROW,
176 g_param_spec_boolean ("show-headers-row", NULL, NULL, TRUE,
177 GSF_PARAM_STATIC | G_PARAM_READWRITE));
178 g_object_class_install_property (gobject_class, PROP_SHOW_STRIPES_COL,
179 g_param_spec_boolean ("show-stripes-col", NULL, NULL, TRUE,
180 GSF_PARAM_STATIC | G_PARAM_READWRITE));
181 g_object_class_install_property (gobject_class, PROP_SHOW_STRIPES_ROW,
182 g_param_spec_boolean ("show-stripes-row", NULL, NULL, TRUE,
183 GSF_PARAM_STATIC | G_PARAM_READWRITE));
184 g_object_class_install_property (gobject_class, PROP_SHOW_LAST_COL,
185 g_param_spec_boolean ("show-last-col", NULL, NULL, TRUE,
186 GSF_PARAM_STATIC | G_PARAM_READWRITE));
187 g_object_class_install_property (gobject_class, PROP_SHOW_LAST_ROW,
188 g_param_spec_boolean ("show-last-row", NULL, NULL, TRUE,
189 GSF_PARAM_STATIC | G_PARAM_READWRITE));
191 g_object_class_install_property (gobject_class, PROP_LAYOUT,
192 g_param_spec_enum ("layout", NULL, NULL, gnm_sheet_slicer_layout_get_type (), GSS_LAYOUT_XL_OUTLINE,
193 GSF_PARAM_STATIC | G_PARAM_READWRITE));
194 parent_klass = g_type_class_peek_parent (klass);
197 GSF_CLASS (GnmSheetSlicer, gnm_sheet_slicer,
198 gnm_sheet_slicer_class_init, gnm_sheet_slicer_init,
199 GO_DATA_SLICER_TYPE)
201 void
202 gnm_sheet_slicer_set_sheet (GnmSheetSlicer *gss, Sheet *sheet)
204 g_return_if_fail (IS_SHEET (sheet));
205 g_return_if_fail (GNM_IS_SHEET_SLICER (gss));
206 g_return_if_fail (NULL == gss->sheet);
208 g_object_ref (gss);
209 gss->sheet = sheet;
210 sheet->slicers = g_slist_prepend (sheet->slicers, gss);
213 void
214 gnm_sheet_slicer_clear_sheet (GnmSheetSlicer *gss)
216 g_return_if_fail (GNM_IS_SHEET_SLICER (gss));
217 g_return_if_fail (NULL != gss->sheet);
219 gss->sheet->slicers = g_slist_remove (gss->sheet->slicers, gss);
220 gss->sheet = NULL;
221 g_object_unref (gss);
224 GnmRange const *
225 gnm_sheet_slicer_get_range (GnmSheetSlicer const *gss)
227 g_return_val_if_fail (GNM_IS_SHEET_SLICER (gss), NULL);
228 return &gss->range;
231 void
232 gnm_sheet_slicer_set_range (GnmSheetSlicer *gss, GnmRange const *r)
234 g_return_if_fail (GNM_IS_SHEET_SLICER (gss));
235 gss->range = *r;
239 * gnm_sheet_slicer_overlaps_range:
240 * @gss: #GnmSheetSlicer
241 * @r: #GnmRange
243 * Returns: %TRUE if @gss overlaps @r.
245 gboolean
246 gnm_sheet_slicer_overlaps_range (GnmSheetSlicer const *gss, GnmRange const *r)
248 g_return_val_if_fail (GNM_IS_SHEET_SLICER (gss), FALSE);
249 return range_overlap (&gss->range, r);
253 * gnm_sheet_slicer_field_header_at_pos:
254 * @gss: #GnmSheetSlicer const
255 * @pos: #GnmCellPos const
257 * Checks to see if @pos (in absolute position, not relative to @gss' corner)
258 * corresponds to a field header. [Does not add a reference]
260 * Returns a #GODataSlicerField or %NULL.
262 GODataSlicerField *
263 gnm_sheet_slicer_field_header_at_pos (GnmSheetSlicer const *gss,
264 GnmCellPos const *pos)
266 int res = -1;
267 unsigned int c, r;
269 g_return_val_if_fail (GNM_IS_SHEET_SLICER (gss), NULL);
271 /* 0) TODO page fields */
272 if (pos->col < gss->range.start.col || pos->row < gss->range.start.row)
273 return NULL;
275 c = pos->col - gss->range.start.col;
276 r = pos->row - gss->range.start.row;
278 /* TODO other layouts */
280 /* col headers along the top starting at first_data_col */
281 if (r == 0 &&
282 c >= gss->first_data_col) {
283 c -= gss->first_data_col;
284 if (c < gss->base.fields[GDS_FIELD_TYPE_COL]->len)
285 res = g_array_index (gss->base.fields[GDS_FIELD_TYPE_COL], int, c);
288 /* row headers just about data starting at 0th col */
289 } else if (r >= (gss->first_data_row - 1) && /* -1 for the headers */
290 c < gss->first_data_col) {
291 if (c < gss->base.fields[GDS_FIELD_TYPE_ROW]->len)
292 res = g_array_index (gss->base.fields[GDS_FIELD_TYPE_ROW], int, c);
295 return (res >= 0) ? go_data_slicer_get_field (&gss->base, res) : NULL;
298 /************************************************************/
301 * gnm_sheet_slicers_at_pos:
302 * @sheet: #Sheet
303 * @pos: #GnmCellPos
305 * Returns: (transfer none): %NULL or the #GnmSheetSlicer in @sheet that overlaps with @pos.
307 GnmSheetSlicer *
308 gnm_sheet_slicers_at_pos (Sheet const *sheet, GnmCellPos const *pos)
310 GSList *ptr;
311 GnmRange r;
313 g_return_val_if_fail (IS_SHEET (sheet), NULL);
314 g_return_val_if_fail (NULL != pos, NULL);
316 range_init_cellpos (&r, pos);
317 for (ptr = sheet->slicers; ptr != NULL ; ptr = ptr->next)
318 if (gnm_sheet_slicer_overlaps_range (ptr->data, &r))
319 return ptr->data;
321 return NULL;
324 #if 0
325 static void
326 gss_append_field_indicies (GnmSheetSlicer const *gss, GODataSlicerFieldType type,
327 GArray *field_order)
329 GArray *tmp = gss->base.fields [type];
330 unsigned int i, n = tmp->len;
331 for (i = 0 ; i < n; i++)
332 g_array_append_val (field_order, g_array_index (tmp, int, i));
335 static void
336 gnm_sheet_slicer_test_sort (GnmSheetSlicer *gss)
338 /* quick test to sort the cache based on the row/col */
339 GArray *permutation, *field_order;
340 unsigned int i, n;
342 field_order = g_array_sized_new (FALSE, FALSE, sizeof (unsigned int), gss->base.all_fields->len);
343 gss_append_field_indicies (gss, GDS_FIELD_TYPE_ROW, field_order);
344 gss_append_field_indicies (gss, GDS_FIELD_TYPE_COL, field_order);
346 n = go_data_cache_num_items (gss->base.cache);
347 permutation = g_array_sized_new (FALSE, FALSE, sizeof (int), n);
348 for (i = 0 ; i < n ; i++)
349 g_array_append_val (permutation, i);
350 go_data_cache_permute (gss->base.cache, field_order, permutation);
351 go_data_cache_dump (gss->base.cache, field_order, permutation);
353 g_array_free (field_order, TRUE);
354 g_array_free (permutation, TRUE);
356 #endif
359 * gnm_sheet_slicer_regenerate:
360 * @gss: #GnmSheetSlicer
362 * Do some work!
363 * See what we need to do then think about when portions belong in the GODataSlicer base.
366 void
367 gnm_sheet_slicer_regenerate (GnmSheetSlicer *gss)
369 #if 0
370 GArray *permutation, *rows;
371 unsigned int i, n;
373 g_return_if_fail (GNM_IS_SHEET_SLICER (gss));
374 g_return_if_fail (IS_SHEET (gss->sheet));
375 g_return_if_fail (NULL != gss->base.cache);
377 field_order = g_array_sized_new (FALSE, FALSE, sizeof (unsigned int), gss->base.all_fields->len);
378 gss_append_field_indicies (gss, GDS_FIELD_TYPE_ROW, field_order);
379 gss_append_field_indicies (gss, GDS_FIELD_TYPE_COL, field_order);
381 n = go_data_cache_num_items (gss->base.cache);
382 #endif
385 GnmSheetSlicerLayout
386 gnm_sheet_slicer_get_layout (GnmSheetSlicer const *gss)
388 g_return_val_if_fail (GNM_IS_SHEET_SLICER (gss), GSS_LAYOUT_XL_OUTLINE);
389 return gss->layout;
392 void
393 gnm_sheet_slicer_set_layout (GnmSheetSlicer *gss, GnmSheetSlicerLayout l)
395 g_return_if_fail (GNM_IS_SHEET_SLICER (gss));
396 gss->layout = l;
399 GType
400 gnm_sheet_slicer_layout_get_type (void)
402 static GType etype = 0;
403 if (etype == 0) {
404 static GEnumValue const values[] = {
405 { GSS_LAYOUT_XL_OUTLINE, "GSS_LAYOUT_XL_OUTLINE", "xl-outline" },
406 { GSS_LAYOUT_XL_COMPACT, "GSS_LAYOUT_XL_COMPACT", "xl-compact" },
407 { GSS_LAYOUT_XL_TABULAR, "GSS_LAYOUT_XL_TABULAR", "xl-tabular" },
408 { 0, NULL, NULL }
410 etype = g_enum_register_static ("GnmSheetSlicerLayout", values);
412 return etype;