1
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
5
* Copyright (C) 2008-2009 Jody Goldberg (jody@gnome.org)
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of version 2 of the GNU General Public
9
* License as published by the Free Software Foundation.
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
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"
30
#include <gsf/gsf-impl-utils.h>
31
#include <glib/gi18n-lib.h>
34
#include <glib-object.h>
36
struct _GnmSheetSlicer {
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;
47
gboolean headers_col, headers_row, stripes_col, stripes_row, last_col, last_row;
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 IS_GNM_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))
63
PROP_FIRST_HEADER_ROW,
67
PROP_SHOW_HEADERS_COL,
68
PROP_SHOW_HEADERS_ROW,
69
PROP_SHOW_STRIPES_COL,
70
PROP_SHOW_STRIPES_ROW,
77
static GObjectClass *parent_klass;
79
gnm_sheet_slicer_init (GnmSheetSlicer *gss)
82
gss->first_header_row = gss->first_data_row = gss->first_data_col = gss->row_page_count = gss->col_page_count = 0;
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);
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;
119
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
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;
144
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
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,
202
gnm_sheet_slicer_set_sheet (GnmSheetSlicer *gss, Sheet *sheet)
204
g_return_if_fail (IS_SHEET (sheet));
205
g_return_if_fail (IS_GNM_SHEET_SLICER (gss));
206
g_return_if_fail (NULL == gss->sheet);
210
sheet->slicers = g_slist_prepend (sheet->slicers, gss);
214
gnm_sheet_slicer_clear_sheet (GnmSheetSlicer *gss)
216
g_return_if_fail (IS_GNM_SHEET_SLICER (gss));
217
g_return_if_fail (NULL != gss->sheet);
219
gss->sheet->slicers = g_slist_remove (gss->sheet->slicers, gss);
221
g_object_unref (gss);
225
gnm_sheet_slicer_get_range (GnmSheetSlicer const *gss)
227
g_return_val_if_fail (IS_GNM_SHEET_SLICER (gss), NULL);
232
gnm_sheet_slicer_set_range (GnmSheetSlicer *gss, GnmRange const *r)
234
g_return_if_fail (IS_GNM_SHEET_SLICER (gss));
239
* gnm_sheet_slicer_overlaps_range :
240
* @filter : #GnmFilter
243
* Returns: %TRUE if @filter overlaps @r.
246
gnm_sheet_slicer_overlaps_range (GnmSheetSlicer const *gss, GnmRange const *r)
248
g_return_val_if_fail (IS_GNM_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.
263
gnm_sheet_slicer_field_header_at_pos (GnmSheetSlicer const *gss,
264
GnmCellPos const *pos)
269
g_return_val_if_fail (IS_GNM_SHEET_SLICER (gss), NULL);
271
/* 0) TODO page fields */
272
if (pos->col < gss->range.start.col || pos->row < gss->range.start.row)
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 */
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 :
305
* Returns: %NULL or the #GnmSheetSlicer in @sheet that overlaps with @pos.
308
gnm_sheet_slicers_at_pos (Sheet const *sheet, GnmCellPos const *pos)
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))
325
gss_append_field_indicies (GnmSheetSlicer const *gss, GODataSlicerFieldType type,
328
GArray *tmp = gss->base.fields [type];
329
unsigned int i, n = tmp->len;
330
for (i = 0 ; i < n; i++)
331
g_array_append_val (field_order, g_array_index (tmp, int, i));
335
* gnm_sheet_slicer_regenerate:
336
* @gss : #GnmSheetSlicer
339
* See what we need to do then think about when portions belong in the GODataSlicer base.
343
gnm_sheet_slicer_regenerate (GnmSheetSlicer *gss)
345
GArray *permutation, *field_order;
348
g_return_if_fail (IS_GNM_SHEET_SLICER (gss));
349
g_return_if_fail (IS_SHEET (gss->sheet));
351
field_order = g_array_sized_new (FALSE, FALSE, sizeof (unsigned int), gss->base.all_fields->len);
352
gss_append_field_indicies (gss, GDS_FIELD_TYPE_ROW, field_order);
353
gss_append_field_indicies (gss, GDS_FIELD_TYPE_COL, field_order);
355
n = go_data_cache_num_items (gss->base.cache);
356
permutation = g_array_sized_new (FALSE, FALSE, sizeof (int), n);
357
for (i = 0 ; i < n ; i++)
358
g_array_append_val (permutation, i);
360
/* TODO : apply page filters */
361
go_data_cache_permute (gss->base.cache, field_order, permutation);
362
go_data_cache_dump (gss->base.cache, field_order, permutation);
364
g_array_free (field_order, TRUE);
365
g_array_free (permutation, TRUE);
369
gnm_sheet_slicer_get_layout (GnmSheetSlicer const *gss)
371
g_return_val_if_fail (IS_GNM_SHEET_SLICER (gss), GSS_Layout_XL_outline);
376
gnm_sheet_slicer_set_layout (GnmSheetSlicer *gss, GnmSheetSlicerLayout l)
378
g_return_if_fail (IS_GNM_SHEET_SLICER (gss));
383
gnm_sheet_slicer_layout_get_type ()
385
static GType etype = 0;
387
static GEnumValue const values[] = {
388
{ GSS_Layout_XL_outline, (char *)"GSS_Layout_XL_outline", (char *)"xl-outline" },
389
{ GSS_Layout_XL_compact, (char *)"GSS_Layout_XL_compact", (char *)"xl-compact" },
390
{ GSS_Layout_XL_tabular, (char *)"GSS_Layout_XL_tabular", (char *)"xl-tabular" },
393
etype = g_enum_register_static ("GnmSheetSlicerLayout", values);