23aca590dccef5680ffcf741b22263f6b3a4438a
[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 <config.h>
20
21 #include <glib.h>
22 #include "gsheetmodel.h"
23 #include <gtksheet/psppire-marshal.h>
24
25 enum {
26   RANGE_CHANGED,
27   ROWS_INSERTED,
28   ROWS_DELETED,
29   COLUMNS_INSERTED,
30   COLUMNS_DELETED,
31   LAST_SIGNAL
32 };
33
34 static guint sheet_model_signals[LAST_SIGNAL] = { 0 };
35
36
37 static void      g_sheet_model_base_init   (gpointer           g_class);
38
39
40 GType
41 g_sheet_model_get_type (void)
42 {
43   static GType sheet_model_type = 0;
44
45   if (! sheet_model_type)
46     {
47       static const GTypeInfo sheet_model_info =
48       {
49         sizeof (GSheetModelIface), /* class_size */
50         g_sheet_model_base_init,   /* base_init */
51         NULL,           /* base_finalize */
52         NULL,
53         NULL,           /* class_finalize */
54         NULL,           /* class_data */
55         0,
56         0,              /* n_preallocs */
57         NULL
58       };
59
60       sheet_model_type =
61         g_type_register_static (G_TYPE_INTERFACE, "GSheetModel",
62                                 &sheet_model_info, 0);
63
64       g_type_interface_add_prerequisite (sheet_model_type, G_TYPE_OBJECT);
65     }
66
67   return sheet_model_type;
68 }
69
70 static void
71 g_sheet_model_base_init (gpointer g_class)
72 {
73   static gboolean initialized = FALSE;
74
75   if (! initialized)
76     {
77       sheet_model_signals[RANGE_CHANGED] =
78         g_signal_new ("range_changed",
79                       G_TYPE_SHEET_MODEL,
80                       G_SIGNAL_RUN_LAST,
81                       G_STRUCT_OFFSET (GSheetModelIface, range_changed),
82                       NULL, NULL,
83                       psppire_marshal_VOID__INT_INT_INT_INT,
84                       G_TYPE_NONE, 4,
85                       G_TYPE_INT,
86                       G_TYPE_INT,
87                       G_TYPE_INT,
88                       G_TYPE_INT);
89
90
91
92       sheet_model_signals[ROWS_INSERTED] =
93         g_signal_new ("rows_inserted",
94                       G_TYPE_SHEET_MODEL,
95                       G_SIGNAL_RUN_LAST,
96                       G_STRUCT_OFFSET (GSheetModelIface, rows_inserted),
97                       NULL, NULL,
98                       psppire_marshal_VOID__INT_INT,
99                       G_TYPE_NONE, 2,
100                       G_TYPE_INT,
101                       G_TYPE_INT);
102
103
104       sheet_model_signals[ROWS_DELETED] =
105         g_signal_new ("rows_deleted",
106                       G_TYPE_SHEET_MODEL,
107                       G_SIGNAL_RUN_LAST,
108                       G_STRUCT_OFFSET (GSheetModelIface, rows_deleted),
109                       NULL, NULL,
110                       psppire_marshal_VOID__INT_INT,
111                       G_TYPE_NONE, 2,
112                       G_TYPE_INT,
113                       G_TYPE_INT);
114
115       sheet_model_signals[COLUMNS_INSERTED] =
116         g_signal_new ("columns_inserted",
117                       G_TYPE_SHEET_MODEL,
118                       G_SIGNAL_RUN_LAST,
119                       G_STRUCT_OFFSET (GSheetModelIface, columns_inserted),
120                       NULL, NULL,
121                       psppire_marshal_VOID__INT_INT,
122                       G_TYPE_NONE, 2,
123                       G_TYPE_INT,
124                       G_TYPE_INT);
125
126
127       sheet_model_signals[COLUMNS_DELETED] =
128         g_signal_new ("columns_deleted",
129                       G_TYPE_SHEET_MODEL,
130                       G_SIGNAL_RUN_LAST,
131                       G_STRUCT_OFFSET (GSheetModelIface, columns_deleted),
132                       NULL, NULL,
133                       psppire_marshal_VOID__INT_INT,
134                       G_TYPE_NONE, 2,
135                       G_TYPE_INT,
136                       G_TYPE_INT);
137
138
139       initialized = TRUE;
140     }
141 }
142
143
144 /**
145  * g_sheet_model_free_strings
146  * @sheet_model: A #GSheetModel
147  *
148  * Returns: True if strings obtained with get_string should be freed by the
149  * sheet when no longer required.
150  **/
151 gboolean
152 g_sheet_model_free_strings (const GSheetModel *sheet_model)
153 {
154   g_return_val_if_fail (G_IS_SHEET_MODEL (sheet_model), FALSE);
155
156   return G_SHEET_MODEL_GET_IFACE (sheet_model)->free_strings;
157 }
158
159
160 /**
161  * g_sheet_model_get_string:
162  * @sheet_model: A #GSheetModel
163  * @row: The row of the cell to be retrieved.
164  * @column: The column of the cell to be retrieved.
165  *
166  * Retrieves the datum at location ROW, COLUMN in the form of a string.
167  * Returns: The string representation of the datum, or NULL on error.
168  **/
169 gchar *
170 g_sheet_model_get_string (const GSheetModel *sheet_model,
171                           glong row, glong column)
172 {
173   g_return_val_if_fail (G_IS_SHEET_MODEL (sheet_model), 0);
174
175   g_assert (G_SHEET_MODEL_GET_IFACE (sheet_model)->get_string);
176
177   return (G_SHEET_MODEL_GET_IFACE (sheet_model)->get_string) (sheet_model, row, column);
178 }
179
180 /**
181  * g_sheet_model_set_string
182  * @sheet_model: A #GSheetModel
183  * @text: The text describing the datum to be set.
184  * @row: The row of the cell to be cleared.
185  * @column: The column of the cell to be cleared.
186  *
187  * Sets the datum at a location from a string.
188  * Returns: TRUE if the datum was changed, FALSE otherwise.
189  **/
190 gboolean
191 g_sheet_model_set_string      (GSheetModel *sheet_model,
192                                  const gchar *text,
193                                  glong row, glong column)
194 {
195   g_return_val_if_fail (G_IS_SHEET_MODEL (sheet_model), FALSE);
196
197   g_assert (G_SHEET_MODEL_GET_IFACE (sheet_model)->set_string);
198
199   return G_SHEET_MODEL_GET_IFACE (sheet_model)->set_string (sheet_model,
200                                                             text, row, column);
201 }
202
203
204
205 /**
206  * g_sheet_model_datum_clear:
207  * @sheet_model: A #GSheetModel
208  * @row: The row of the cell to be cleared.
209  * @column: The column of the cell to be cleared.
210  *
211  * Called when the datum at a location is to be cleared.
212  * Returns: TRUE if the datum was cleared, FALSE otherwise.
213  **/
214 gboolean
215 g_sheet_model_datum_clear    (GSheetModel *sheet_model,
216                                 glong row, glong column)
217 {
218   g_return_val_if_fail (G_IS_SHEET_MODEL (sheet_model), FALSE);
219
220   g_assert (G_SHEET_MODEL_GET_IFACE (sheet_model)->clear_datum);
221
222   return G_SHEET_MODEL_GET_IFACE (sheet_model)->clear_datum (sheet_model,
223                                                                 row, column);
224 }
225
226
227 /**
228  * g_sheet_model_range_changed:
229  * @sheet_model: A #GSheetModel
230  * @range: The #GSheetRange range of cells which have changed.
231  *
232  * Emits the "range_changed" signal on @sheet_model.
233  **/
234 void
235 g_sheet_model_range_changed (GSheetModel *sheet_model,
236                                glong row0, glong col0,
237                                glong rowi, glong coli)
238 {
239   g_return_if_fail (G_IS_SHEET_MODEL (sheet_model));
240
241   g_signal_emit (sheet_model, sheet_model_signals[RANGE_CHANGED], 0,
242                  row0, col0, rowi, coli);
243 }
244
245
246
247
248 /**
249  * g_sheet_model_rows_inserted:
250  * @sheet_model: A #GSheetModel
251  * @row: The row before which the new rows should be inserted.
252  * @n_rows: The number of rows to insert.
253  *
254  * Emits the "rows_inserted" signal on @sheet_model.
255  **/
256 void
257 g_sheet_model_rows_inserted (GSheetModel *sheet_model,
258                                glong row, glong n_rows)
259 {
260   g_return_if_fail (G_IS_SHEET_MODEL (sheet_model));
261
262   g_signal_emit (sheet_model, sheet_model_signals[ROWS_INSERTED], 0,
263                  row, n_rows);
264 }
265
266
267 /**
268  * g_sheet_model_columns_inserted:
269  * @sheet_model: A #GSheetModel
270  * @column: The column before which the new columns should be inserted.
271  * @n_columns: The number of columns to insert.
272  *
273  * Emits the "columns_inserted" signal on @sheet_model.
274  **/
275 void
276 g_sheet_model_columns_inserted (GSheetModel *sheet_model,
277                                glong column, glong n_columns)
278 {
279   g_return_if_fail (G_IS_SHEET_MODEL (sheet_model));
280
281   g_signal_emit (sheet_model, sheet_model_signals[COLUMNS_INSERTED], 0,
282                  column, n_columns);
283 }
284
285
286
287
288 /**
289  * g_sheet_model_rows_deleted:
290  * @sheet_model: A #GSheetModel
291  * @row: The first row to be deleted.
292  * @n_rows: The number of rows to delete.
293  *
294  * Emits the "rows_deleted" signal on @sheet_model.
295  **/
296 void
297 g_sheet_model_rows_deleted (GSheetModel *sheet_model,
298                                glong row, glong n_rows)
299 {
300   g_return_if_fail (G_IS_SHEET_MODEL (sheet_model));
301
302   g_signal_emit (sheet_model, sheet_model_signals[ROWS_DELETED], 0,
303                  row, n_rows);
304 }
305
306
307
308 /**
309  * g_sheet_model_columns_deleted:
310  * @sheet_model: A #GSheetModel
311  * @column: The first column to be deleted.
312  * @n_columns: The number of columns to delete.
313  *
314  * Emits the "columns_deleted" signal on @sheet_model.
315  **/
316 void
317 g_sheet_model_columns_deleted (GSheetModel *sheet_model,
318                                glong column, glong n_columns)
319 {
320   g_return_if_fail (G_IS_SHEET_MODEL (sheet_model));
321
322   g_signal_emit (sheet_model, sheet_model_signals[COLUMNS_DELETED], 0,
323                  column, n_columns);
324 }
325
326
327
328
329
330 /**
331  * g_sheet_model_is_editable:
332  * @sheet_model: A #GSheetModel
333  * @row: The row
334  * @column: The column
335  *
336  * Returns: TRUE if the cell is editable, FALSE otherwise
337  **/
338 gboolean
339 g_sheet_model_is_editable (const GSheetModel *model,
340                              glong row, glong column)
341 {
342   g_return_val_if_fail (G_IS_SHEET_MODEL (model), TRUE);
343
344   if ( ! G_SHEET_MODEL_GET_IFACE (model)->is_editable )
345     return TRUE;
346
347   return G_SHEET_MODEL_GET_IFACE (model)->is_editable (model,
348                                                           row, column);
349 }
350
351
352 /**
353  * g_sheet_model_get_foreground:
354  * @sheet_model: A #GSheetModel
355  * @row: The row
356  * @column: The column
357  *
358  * Returns the foreground colour of the cell at @row, @column
359  * The color is unallocated.  It will be allocated by the viewing object.
360  **/
361 GdkColor *
362 g_sheet_model_get_foreground (const GSheetModel *model,
363                                 glong row, glong column)
364 {
365   g_return_val_if_fail (G_IS_SHEET_MODEL (model), NULL);
366
367   if ( ! G_SHEET_MODEL_GET_IFACE (model)->get_foreground )
368     return NULL;
369
370   return G_SHEET_MODEL_GET_IFACE (model)->get_foreground (model,
371                                                             row, column);
372 }
373
374 /**
375  * g_sheet_model_get_background:
376  * @sheet_model: A #GSheetModel
377  * @row: The row
378  * @column: The column
379  *
380  * Returns the background colour of the cell at @row, @column
381  * The color is unallocated.  It will be allocated by the viewing object.
382  **/
383 GdkColor *
384 g_sheet_model_get_background (const GSheetModel *model,
385                                 glong row, glong column)
386 {
387   g_return_val_if_fail (G_IS_SHEET_MODEL (model), NULL);
388
389   if ( ! G_SHEET_MODEL_GET_IFACE (model)->get_background )
390     return NULL;
391
392   return G_SHEET_MODEL_GET_IFACE (model)->get_background (model,
393                                                             row, column);
394 }
395
396 /**
397  * g_sheet_model_get_justification:
398  * @sheet_model: A #GSheetModel
399  * @row: The row
400  * @column: The column
401  *
402  * Returns the justification of the cell at @row, @column
403  * Returns: the justification, or NULL on error.
404  **/
405 const GtkJustification *
406 g_sheet_model_get_justification (const GSheetModel *model,
407                                    glong row, glong column)
408 {
409   g_return_val_if_fail (G_IS_SHEET_MODEL (model), NULL);
410
411   if ( ! G_SHEET_MODEL_GET_IFACE (model)->get_justification)
412     return NULL;
413
414   return G_SHEET_MODEL_GET_IFACE (model)->get_justification (model,
415                                                                row, column);
416 }
417
418 /**
419  * g_sheet_model_get_cell_border:
420  * @sheet_model: A #GSheetModel
421  * @row: The row
422  * @column: The column
423  *
424  * Returns the cell border of the cell at @row, @column
425  * Returns: the cell border, or NULL on error.
426  **/
427 const GtkSheetCellBorder *
428 g_sheet_model_get_cell_border (const GSheetModel *model,
429                                  glong row, glong column)
430 {
431   g_return_val_if_fail (G_IS_SHEET_MODEL (model), NULL);
432   if ( ! G_SHEET_MODEL_GET_IFACE (model)->get_cell_border)
433     return NULL;
434
435   return G_SHEET_MODEL_GET_IFACE (model)->get_cell_border (model,
436                                                            row, column);
437 }
438
439
440
441 /**
442  * g_sheet_model_get_column_count:
443  * @model: A #GSheetModel
444  *
445  * Returns the total number of columns represented by the model
446  **/
447 glong
448 g_sheet_model_get_column_count (const GSheetModel *model)
449 {
450   g_return_val_if_fail (G_IS_SHEET_MODEL (model), -1);
451
452   return G_SHEET_MODEL_GET_IFACE (model)->get_column_count (model);
453 }
454
455 /**
456  * g_sheet_model_get_row_count:
457  * @model: A #GSheetModel
458  *
459  * Returns the total number of rows represented by the model
460  **/
461 gint
462 g_sheet_model_get_row_count(const GSheetModel *model)
463 {
464   g_return_val_if_fail (G_IS_SHEET_MODEL (model), -1);
465
466   return G_SHEET_MODEL_GET_IFACE (model)->get_row_count (model);
467 }
468
469 \f
470
471 /* Column related functions  */
472 gboolean
473 g_sheet_model_get_column_sensitivity (const GSheetModel *model, gint col)
474 {
475   g_return_val_if_fail (G_IS_SHEET_MODEL (model), FALSE);
476
477   if ( NULL == G_SHEET_MODEL_GET_IFACE (model)->get_column_sensitivity)
478     return TRUE;
479
480   return G_SHEET_MODEL_GET_IFACE (model)->get_column_sensitivity (model, col);
481 }
482
483
484 gchar *
485 g_sheet_model_get_column_subtitle (const GSheetModel *model,
486                                    gint col)
487 {
488   g_return_val_if_fail (G_IS_SHEET_MODEL (model), NULL);
489
490   if ( NULL == G_SHEET_MODEL_GET_IFACE (model)->get_column_subtitle)
491     return NULL;
492
493   return G_SHEET_MODEL_GET_IFACE (model)->get_column_subtitle (model, col);
494 }
495
496
497 GtkSheetButton *
498 g_sheet_model_get_column_button (const GSheetModel *model,
499                                  gint col)
500 {
501   GtkSheetButton *button = gtk_sheet_button_new ();
502
503   g_return_val_if_fail (G_IS_SHEET_MODEL (model), NULL);
504
505   if ( G_SHEET_MODEL_GET_IFACE (model)->get_column_title)
506     button->label = G_SHEET_MODEL_GET_IFACE (model)->get_column_title (model, col);
507
508   return button;
509 }
510
511 GtkJustification
512 g_sheet_model_get_column_justification (const GSheetModel *model,
513                                         gint col)
514 {
515   g_return_val_if_fail (G_IS_SHEET_MODEL (model), GTK_JUSTIFY_LEFT);
516
517   if ( G_SHEET_MODEL_GET_IFACE (model)->get_column_justification)
518     return G_SHEET_MODEL_GET_IFACE (model)->get_column_justification (model, col);
519
520   return GTK_JUSTIFY_LEFT;
521 }
522
523 \f
524
525 gboolean
526 g_sheet_model_get_row_sensitivity (const GSheetModel *model, gint row)
527 {
528   g_return_val_if_fail (G_IS_SHEET_MODEL (model), FALSE);
529
530   if ( NULL == G_SHEET_MODEL_GET_IFACE (model)->get_row_sensitivity)
531     return TRUE;
532
533   return G_SHEET_MODEL_GET_IFACE (model)->get_row_sensitivity (model, row);
534 }
535
536
537
538 gchar *
539 g_sheet_model_get_row_subtitle (const GSheetModel *model,
540                                 gint row)
541 {
542   g_return_val_if_fail (G_IS_SHEET_MODEL (model), NULL);
543
544   if ( NULL == G_SHEET_MODEL_GET_IFACE (model)->get_row_subtitle)
545     return NULL;
546
547   return G_SHEET_MODEL_GET_IFACE (model)->get_row_subtitle (model, row);
548 }
549
550
551 GtkSheetButton *
552 g_sheet_model_get_row_button (const GSheetModel *model,
553                                  gint row)
554 {
555   GtkSheetButton *button = gtk_sheet_button_new ();
556
557   g_return_val_if_fail (G_IS_SHEET_MODEL (model), NULL);
558
559   if ( G_SHEET_MODEL_GET_IFACE (model)->get_row_title)
560     button->label = G_SHEET_MODEL_GET_IFACE (model)->get_row_title (model, row);
561
562   return button;
563 }
564