Fixed some bad interaction between variable and data sheets.
[pspp-builds.git] / lib / gtksheet / gsheetmodel.c
1 /* GSheetModel --- an abstract model for the GSheet widget.
2  * Copyright (C) 2006 Free Software Foundation
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include <glib.h>
20 #include "gsheetmodel.h"
21 #include "gtkextra-marshal.h"
22
23 enum {
24   RANGE_CHANGED,
25   ROWS_INSERTED,
26   ROWS_DELETED,
27   COLUMNS_INSERTED,
28   COLUMNS_DELETED,
29   LAST_SIGNAL
30 };
31
32 static guint sheet_model_signals[LAST_SIGNAL] = { 0 };
33
34
35 static void      g_sheet_model_base_init   (gpointer           g_class);
36
37
38 inline GType
39 g_sheet_model_get_type (void)
40 {
41   static GType sheet_model_type = 0;
42
43   if (! sheet_model_type)
44     {
45       static const GTypeInfo sheet_model_info =
46       {
47         sizeof (GSheetModelIface), /* class_size */
48         g_sheet_model_base_init,   /* base_init */
49         NULL,           /* base_finalize */
50         NULL,
51         NULL,           /* class_finalize */
52         NULL,           /* class_data */
53         0,
54         0,              /* n_preallocs */
55         NULL
56       };
57
58       sheet_model_type =
59         g_type_register_static (G_TYPE_INTERFACE, "GSheetModel",
60                                 &sheet_model_info, 0);
61
62       g_type_interface_add_prerequisite (sheet_model_type, G_TYPE_OBJECT);
63     }
64
65   return sheet_model_type;
66 }
67
68 static void
69 g_sheet_model_base_init (gpointer g_class)
70 {
71   static gboolean initialized = FALSE;
72
73   if (! initialized)
74     {
75       sheet_model_signals[RANGE_CHANGED] =
76         g_signal_new ("range_changed",
77                       G_TYPE_SHEET_MODEL,
78                       G_SIGNAL_RUN_LAST,
79                       G_STRUCT_OFFSET (GSheetModelIface, range_changed),
80                       NULL, NULL,
81                       gtkextra_VOID__INT_INT_INT_INT,
82                       G_TYPE_NONE, 4,
83                       G_TYPE_INT,
84                       G_TYPE_INT,
85                       G_TYPE_INT,
86                       G_TYPE_INT);
87
88
89
90       sheet_model_signals[ROWS_INSERTED] =
91         g_signal_new ("rows_inserted",
92                       G_TYPE_SHEET_MODEL,
93                       G_SIGNAL_RUN_LAST,
94                       G_STRUCT_OFFSET (GSheetModelIface, rows_inserted),
95                       NULL, NULL,
96                       gtkextra_VOID__INT_INT,
97                       G_TYPE_NONE, 2,
98                       G_TYPE_INT,
99                       G_TYPE_INT);
100
101
102       sheet_model_signals[ROWS_DELETED] =
103         g_signal_new ("rows_deleted",
104                       G_TYPE_SHEET_MODEL,
105                       G_SIGNAL_RUN_LAST,
106                       G_STRUCT_OFFSET (GSheetModelIface, rows_deleted),
107                       NULL, NULL,
108                       gtkextra_VOID__INT_INT,
109                       G_TYPE_NONE, 2,
110                       G_TYPE_INT,
111                       G_TYPE_INT);
112
113       sheet_model_signals[COLUMNS_INSERTED] =
114         g_signal_new ("columns_inserted",
115                       G_TYPE_SHEET_MODEL,
116                       G_SIGNAL_RUN_LAST,
117                       G_STRUCT_OFFSET (GSheetModelIface, columns_inserted),
118                       NULL, NULL,
119                       gtkextra_VOID__INT_INT,
120                       G_TYPE_NONE, 2,
121                       G_TYPE_INT,
122                       G_TYPE_INT);
123
124
125       sheet_model_signals[COLUMNS_DELETED] =
126         g_signal_new ("columns_deleted",
127                       G_TYPE_SHEET_MODEL,
128                       G_SIGNAL_RUN_LAST,
129                       G_STRUCT_OFFSET (GSheetModelIface, columns_deleted),
130                       NULL, NULL,
131                       gtkextra_VOID__INT_INT,
132                       G_TYPE_NONE, 2,
133                       G_TYPE_INT,
134                       G_TYPE_INT);
135
136                     
137       initialized = TRUE;
138     }
139 }
140
141
142 /**
143  * g_sheet_model_free_strings
144  * @sheet_model: A #GSheetModel
145  * 
146  * Returns: True if strings obtained with get_string should be freed by the 
147  * sheet when no longer required.
148  **/
149 inline  gboolean 
150 g_sheet_model_free_strings (const GSheetModel *sheet_model)
151 {
152   g_return_val_if_fail (G_IS_SHEET_MODEL (sheet_model), FALSE);
153
154   return G_SHEET_MODEL_GET_IFACE (sheet_model)->free_strings;
155 }
156
157
158 /**
159  * g_sheet_model_get_string:
160  * @sheet_model: A #GSheetModel
161  * @row: The row of the cell to be retrieved.
162  * @column: The column of the cell to be retrieved.
163  * 
164  * Retrieves the datum at location ROW, COLUMN in the form of a string.
165  * Returns: The string representation of the datum, or NULL on error.
166  **/
167 inline gchar *
168 g_sheet_model_get_string (const GSheetModel *sheet_model, 
169                           gint row, gint column)
170 {
171   g_return_val_if_fail (G_IS_SHEET_MODEL (sheet_model), 0);
172
173   g_assert (G_SHEET_MODEL_GET_IFACE (sheet_model)->get_string);
174   
175   return (G_SHEET_MODEL_GET_IFACE (sheet_model)->get_string) (sheet_model, row, column);
176 }
177
178 /**
179  * g_sheet_model_set_string
180  * @sheet_model: A #GSheetModel
181  * @text: The text describing the datum to be set.
182  * @row: The row of the cell to be cleared.
183  * @column: The column of the cell to be cleared.
184  * 
185  * Sets the datum at a location from a string.
186  * Returns: TRUE if the datum was changed, FALSE otherwise.
187  **/
188 gboolean
189 g_sheet_model_set_string      (GSheetModel *sheet_model, 
190                                  const gchar *text, 
191                                  gint row, gint column)
192 {
193   g_return_val_if_fail (G_IS_SHEET_MODEL (sheet_model), FALSE);
194
195   g_assert (G_SHEET_MODEL_GET_IFACE (sheet_model)->set_string);
196
197   return G_SHEET_MODEL_GET_IFACE (sheet_model)->set_string (sheet_model, 
198                                                             text, row, column);
199 }
200
201
202
203 /**
204  * g_sheet_model_datum_clear:
205  * @sheet_model: A #GSheetModel
206  * @row: The row of the cell to be cleared.
207  * @column: The column of the cell to be cleared.
208  * 
209  * Called when the datum at a location is to be cleared.
210  * Returns: TRUE if the datum was cleared, FALSE otherwise.
211  **/
212 gboolean
213 g_sheet_model_datum_clear    (GSheetModel *sheet_model, 
214                                 gint row, gint column)
215 {
216   g_return_val_if_fail (G_IS_SHEET_MODEL (sheet_model), FALSE);
217
218   g_assert (G_SHEET_MODEL_GET_IFACE (sheet_model)->clear_datum);
219
220   return G_SHEET_MODEL_GET_IFACE (sheet_model)->clear_datum (sheet_model, 
221                                                                 row, column);
222 }
223
224
225 /**
226  * g_sheet_model_range_changed:
227  * @sheet_model: A #GSheetModel
228  * @range: The #GSheetRange range of cells which have changed.
229  * 
230  * Emits the "range_changed" signal on @sheet_model.
231  **/
232 void
233 g_sheet_model_range_changed (GSheetModel *sheet_model,
234                                gint row0, gint col0,
235                                gint rowi, gint coli)
236 {
237   g_return_if_fail (G_IS_SHEET_MODEL (sheet_model));
238
239   g_signal_emit (sheet_model, sheet_model_signals[RANGE_CHANGED], 0, 
240                  row0, col0, rowi, coli);
241 }
242
243
244
245
246 /**
247  * g_sheet_model_rows_inserted:
248  * @sheet_model: A #GSheetModel
249  * @row: The row before which the new rows should be inserted.
250  * @n_rows: The number of rows to insert.
251  * 
252  * Emits the "rows_inserted" signal on @sheet_model.
253  **/
254 void
255 g_sheet_model_rows_inserted (GSheetModel *sheet_model,
256                                gint row, gint n_rows)
257 {
258   g_return_if_fail (G_IS_SHEET_MODEL (sheet_model));
259
260   g_signal_emit (sheet_model, sheet_model_signals[ROWS_INSERTED], 0, 
261                  row, n_rows);
262 }
263
264
265 /**
266  * g_sheet_model_columns_inserted:
267  * @sheet_model: A #GSheetModel
268  * @column: The column before which the new columns should be inserted.
269  * @n_columns: The number of columns to insert.
270  * 
271  * Emits the "columns_inserted" signal on @sheet_model.
272  **/
273 void
274 g_sheet_model_columns_inserted (GSheetModel *sheet_model,
275                                gint column, gint n_columns)
276 {
277   g_return_if_fail (G_IS_SHEET_MODEL (sheet_model));
278
279   g_signal_emit (sheet_model, sheet_model_signals[COLUMNS_INSERTED], 0, 
280                  column, n_columns);
281 }
282
283
284
285
286 /**
287  * g_sheet_model_rows_deleted:
288  * @sheet_model: A #GSheetModel
289  * @row: The first row to be deleted.
290  * @n_rows: The number of rows to delete.
291  * 
292  * Emits the "rows_deleted" signal on @sheet_model.
293  **/
294 void
295 g_sheet_model_rows_deleted (GSheetModel *sheet_model,
296                                gint row, gint n_rows)
297 {
298   g_return_if_fail (G_IS_SHEET_MODEL (sheet_model));
299
300   g_signal_emit (sheet_model, sheet_model_signals[ROWS_DELETED], 0, 
301                  row, n_rows);
302 }
303
304
305
306 /**
307  * g_sheet_model_columns_deleted:
308  * @sheet_model: A #GSheetModel
309  * @column: The first column to be deleted.
310  * @n_columns: The number of columns to delete.
311  * 
312  * Emits the "columns_deleted" signal on @sheet_model.
313  **/
314 void
315 g_sheet_model_columns_deleted (GSheetModel *sheet_model,
316                                gint column, gint n_columns)
317 {
318   g_return_if_fail (G_IS_SHEET_MODEL (sheet_model));
319
320   g_signal_emit (sheet_model, sheet_model_signals[COLUMNS_DELETED], 0, 
321                  column, n_columns);
322 }
323
324
325
326
327
328 /**
329  * g_sheet_model_is_editable:
330  * @sheet_model: A #GSheetModel
331  * @row: The row 
332  * @column: The column
333  * 
334  * Returns: TRUE if the cell is editable, FALSE otherwise
335  **/
336 inline gboolean 
337 g_sheet_model_is_editable (const GSheetModel *model, 
338                              gint row, gint column)
339 {
340   g_return_val_if_fail (G_IS_SHEET_MODEL (model), TRUE);
341
342   if ( ! G_SHEET_MODEL_GET_IFACE (model)->is_editable )
343     return TRUE;
344
345   return G_SHEET_MODEL_GET_IFACE (model)->is_editable (model, 
346                                                           row, column);
347 }
348
349 /**
350  * g_sheet_model_is_visible:
351  * @sheet_model: A #GSheetModel
352  * @row: The row 
353  * @column: The column
354  * 
355  * Returns: TRUE if the cell is visible, FALSE otherwise
356  **/
357 inline gboolean 
358 g_sheet_model_is_visible (const GSheetModel *model, 
359                           gint row, gint column)
360 {
361   g_return_val_if_fail (G_IS_SHEET_MODEL (model), TRUE);
362
363   if ( ! G_SHEET_MODEL_GET_IFACE (model)->is_visible )
364     return TRUE;
365
366   return G_SHEET_MODEL_GET_IFACE (model)->is_visible (model, 
367                                                         row, column);
368 }
369
370
371 /**
372  * g_sheet_model_get_foreground:
373  * @sheet_model: A #GSheetModel
374  * @row: The row 
375  * @column: The column
376  *
377  * Returns the foreground colour of the cell at @row, @column
378  * Returns: the foreground colour, or NULL on error.
379  **/
380 inline const GdkColor *
381 g_sheet_model_get_foreground (const GSheetModel *model, 
382                                 gint row, gint column)
383 {
384   g_return_val_if_fail (G_IS_SHEET_MODEL (model), NULL);
385
386   if ( ! G_SHEET_MODEL_GET_IFACE (model)->get_foreground )
387     return NULL;
388
389   return G_SHEET_MODEL_GET_IFACE (model)->get_foreground (model, 
390                                                             row, column);
391 }
392
393 /**
394  * g_sheet_model_get_background:
395  * @sheet_model: A #GSheetModel
396  * @row: The row 
397  * @column: The column
398  *
399  * Returns the background colour of the cell at @row, @column
400  * Returns: the background colour, or NULL on error.
401  **/
402 inline const GdkColor *
403 g_sheet_model_get_background (const GSheetModel *model, 
404                                 gint row, gint column)
405 {
406   g_return_val_if_fail (G_IS_SHEET_MODEL (model), NULL);
407
408   if ( ! G_SHEET_MODEL_GET_IFACE (model)->get_background )
409     return NULL;
410
411   return G_SHEET_MODEL_GET_IFACE (model)->get_background (model, 
412                                                             row, column);
413 }
414
415 /**
416  * g_sheet_model_get_justification:
417  * @sheet_model: A #GSheetModel
418  * @row: The row 
419  * @column: The column
420  *
421  * Returns the justification of the cell at @row, @column
422  * Returns: the justification, or NULL on error.
423  **/
424 inline const GtkJustification *
425 g_sheet_model_get_justification (const GSheetModel *model, 
426                                    gint row, gint column)
427 {
428   g_return_val_if_fail (G_IS_SHEET_MODEL (model), NULL);
429
430   if ( ! G_SHEET_MODEL_GET_IFACE (model)->get_justification)
431     return NULL;
432
433   return G_SHEET_MODEL_GET_IFACE (model)->get_justification (model, 
434                                                                row, column);
435 }
436
437 /**
438  * g_sheet_model_get_font_desc:
439  * @sheet_model: A #GSheetModel
440  * @row: The row 
441  * @column: The column
442  *
443  * Returns the font description of the cell at @row, @column
444  * Returns: the font description, or NULL on error.
445  **/
446 inline const PangoFontDescription *
447 g_sheet_model_get_font_desc(const GSheetModel *model,
448                               gint row, gint column)
449 {
450   g_return_val_if_fail (G_IS_SHEET_MODEL (model), NULL);
451   if ( ! G_SHEET_MODEL_GET_IFACE (model)->get_font_desc)
452     return NULL;
453
454   return G_SHEET_MODEL_GET_IFACE (model)->get_font_desc (model, 
455                                                            row, column);
456 }
457
458 /**
459  * g_sheet_model_get_cell_border:
460  * @sheet_model: A #GSheetModel
461  * @row: The row 
462  * @column: The column
463  *
464  * Returns the cell border of the cell at @row, @column
465  * Returns: the cell border, or NULL on error.
466  **/
467 inline const GtkSheetCellBorder * 
468 g_sheet_model_get_cell_border (const GSheetModel *model, 
469                                  gint row, gint column)
470 {
471   g_return_val_if_fail (G_IS_SHEET_MODEL (model), NULL);
472   if ( ! G_SHEET_MODEL_GET_IFACE (model)->get_cell_border)
473     return NULL;
474
475   return G_SHEET_MODEL_GET_IFACE (model)->get_cell_border (model, 
476                                                            row, column);
477 }
478
479
480
481 /**
482  * g_sheet_model_get_column_count:
483  * @model: A #GSheetModel
484  *
485  * Returns the total number of columns represented by the model
486  **/
487 inline gint 
488 g_sheet_model_get_column_count(const GSheetModel *model)
489 {
490   g_return_val_if_fail (G_IS_SHEET_MODEL (model), -1);
491
492   return G_SHEET_MODEL_GET_IFACE (model)->get_column_count (model);
493 }
494
495 /**
496  * g_sheet_model_get_row_count:
497  * @model: A #GSheetModel
498  *
499  * Returns the total number of rows represented by the model
500  **/
501 inline gint 
502 g_sheet_model_get_row_count(const GSheetModel *model)
503 {
504   g_return_val_if_fail (G_IS_SHEET_MODEL (model), -1);
505
506
507   return G_SHEET_MODEL_GET_IFACE (model)->get_row_count (model);
508 }