f64f35ad096141bb0914ae56a6b580d126a8228b
[pspp] / src / ui / gui / psppire-spreadsheet-model.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2013  Free Software Foundation
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program 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
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17
18 #include <config.h>
19 #include <glib.h>
20
21 #include "psppire-spreadsheet-model.h"
22
23 #include "data/spreadsheet-reader.h"
24
25 #include "data/gnumeric-reader.h"
26
27 static void psppire_spreadsheet_model_init (PsppireSpreadsheetModel *
28                                             spreadsheetModel);
29 static void psppire_spreadsheet_model_class_init (PsppireSpreadsheetModelClass
30                                                   * class);
31
32 static void psppire_spreadsheet_model_finalize (GObject * object);
33 static void psppire_spreadsheet_model_dispose (GObject * object);
34
35 static GObjectClass *parent_class = NULL;
36
37
38 static void spreadsheet_tree_model_init (GtkTreeModelIface * iface);
39
40
41 GType
42 psppire_spreadsheet_model_get_type (void)
43 {
44   static GType object_type = 0;
45
46   if (!object_type)
47     {
48       static const GTypeInfo spreadsheet_model_info = {
49         sizeof (PsppireSpreadsheetModelClass),
50         NULL,                   /* base_init */
51         NULL,                   /* base_finalize */
52         (GClassInitFunc) psppire_spreadsheet_model_class_init,
53         NULL,                   /* class_finalize */
54         NULL,                   /* class_data */
55         sizeof (PsppireSpreadsheetModel),
56         0,
57         (GInstanceInitFunc) psppire_spreadsheet_model_init,
58       };
59
60       static const GInterfaceInfo tree_model_info = {
61         (GInterfaceInitFunc) spreadsheet_tree_model_init,
62         NULL,
63         NULL
64       };
65
66       object_type = g_type_register_static (G_TYPE_OBJECT,
67                                             "PsppireSpreadsheetModel",
68                                             &spreadsheet_model_info, 0);
69
70       g_type_add_interface_static (object_type, GTK_TYPE_TREE_MODEL,
71                                    &tree_model_info);
72     }
73
74   return object_type;
75 }
76
77
78 /* Properties */
79 enum
80 {
81   PROP_0,
82   PROP_SPREADSHEET
83 };
84
85
86 static void
87 psppire_spreadsheet_model_set_property (GObject * object,
88                                         guint prop_id,
89                                         const GValue * value,
90                                         GParamSpec * pspec)
91 {
92   PsppireSpreadsheetModel *spreadsheetModel = 
93     PSPPIRE_SPREADSHEET_MODEL (object);
94
95   switch (prop_id)
96     {
97     case PROP_SPREADSHEET:
98       spreadsheetModel->spreadsheet = g_value_get_pointer (value);
99       break;
100     default:
101       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
102       break;
103     };
104 }
105
106
107 static void
108 psppire_spreadsheet_model_dispose (GObject * object)
109 {
110 }
111
112 static void
113 psppire_spreadsheet_model_finalize (GObject * object)
114 {
115   //  PsppireSpreadsheetModel *spreadsheetModel = PSPPIRE_SPREADSHEET_MODEL (object);
116 }
117
118 static void
119 psppire_spreadsheet_model_class_init (PsppireSpreadsheetModelClass * class)
120 {
121   GObjectClass *object_class;
122
123   GParamSpec *spreadsheet_spec = g_param_spec_pointer ("spreadsheet",
124                                                        "Spreadsheet",
125                                                        "The spreadsheet that this model represents",
126                                                        G_PARAM_CONSTRUCT_ONLY
127                                                        | G_PARAM_WRITABLE);
128
129   parent_class = g_type_class_peek_parent (class);
130   object_class = (GObjectClass *) class;
131
132   object_class->set_property = psppire_spreadsheet_model_set_property;
133
134   g_object_class_install_property (object_class,
135                                    PROP_SPREADSHEET, spreadsheet_spec);
136
137   object_class->finalize = psppire_spreadsheet_model_finalize;
138   object_class->dispose = psppire_spreadsheet_model_dispose;
139 }
140
141
142 static void
143 psppire_spreadsheet_model_init (PsppireSpreadsheetModel * spreadsheetModel)
144 {
145   spreadsheetModel->dispose_has_run = FALSE;
146   spreadsheetModel->stamp = g_random_int ();
147 }
148
149
150 GtkTreeModel *
151 psppire_spreadsheet_model_new (struct spreadsheet *sp)
152 {
153   return g_object_new (psppire_spreadsheet_model_get_type (),
154                        "spreadsheet", sp, NULL);
155 }
156
157
158 \f
159
160 static gint
161 tree_model_n_columns (GtkTreeModel * model)
162 {
163   return PSPPIRE_SPREADSHEET_MODEL_N_COLS;
164 }
165
166 static GtkTreeModelFlags
167 tree_model_get_flags (GtkTreeModel * model)
168 {
169   g_return_val_if_fail (PSPPIRE_IS_SPREADSHEET_MODEL (model),
170                         (GtkTreeModelFlags) 0);
171
172   return GTK_TREE_MODEL_LIST_ONLY;
173 }
174
175 static GType
176 tree_model_column_type (GtkTreeModel * model, gint index)
177 {
178   g_return_val_if_fail (PSPPIRE_IS_SPREADSHEET_MODEL (model), (GType) 0);
179   g_return_val_if_fail (index < PSPPIRE_SPREADSHEET_MODEL_N_COLS, (GType) 0);
180
181   return G_TYPE_STRING;
182 }
183
184
185 static gboolean
186 tree_model_get_iter (GtkTreeModel * model, GtkTreeIter * iter,
187                      GtkTreePath * path)
188 {
189   PsppireSpreadsheetModel *spreadsheetModel =
190     PSPPIRE_SPREADSHEET_MODEL (model);
191   gint *indices, depth;
192   gint n;
193
194   g_return_val_if_fail (path, FALSE);
195
196   depth = gtk_tree_path_get_depth (path);
197
198   g_return_val_if_fail (depth == 1, FALSE);
199
200   indices = gtk_tree_path_get_indices (path);
201
202   n = indices[0];
203
204   iter->stamp = spreadsheetModel->stamp;
205   iter->user_data = (gpointer) n;
206
207   return TRUE;
208 }
209
210 static gboolean
211 tree_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter)
212 {
213   PsppireSpreadsheetModel *spreadsheetModel =
214     PSPPIRE_SPREADSHEET_MODEL (model);
215   g_return_val_if_fail (iter->stamp == spreadsheetModel->stamp, FALSE);
216
217   if (iter == NULL)
218     return FALSE;
219
220   if ((gint) iter->user_data >= spreadsheetModel->spreadsheet->n_sheets - 1)
221     {
222       iter->user_data = NULL;
223       iter->stamp = 0;
224       return FALSE;
225     }
226
227   iter->user_data++;
228
229   return TRUE;
230 }
231
232
233 static void
234 tree_model_get_value (GtkTreeModel * model, GtkTreeIter * iter,
235                       gint column, GValue * value)
236 {
237   PsppireSpreadsheetModel *spreadsheetModel =
238     PSPPIRE_SPREADSHEET_MODEL (model);
239   g_return_if_fail (column < PSPPIRE_SPREADSHEET_MODEL_N_COLS);
240   g_return_if_fail (iter->stamp == spreadsheetModel->stamp);
241
242   g_value_init (value, G_TYPE_STRING);
243   switch (column)
244     {
245     case PSPPIRE_SPREADSHEET_MODEL_COL_NAME:
246       {
247         const char *x =
248           gnumeric_get_sheet_name (spreadsheetModel->spreadsheet,
249                                    (gint) iter->user_data);
250         g_value_set_string (value, x);
251       }
252       break;
253     case PSPPIRE_SPREADSHEET_MODEL_COL_RANGE:
254       {
255         char *x =
256           gnumeric_get_sheet_range (spreadsheetModel->spreadsheet,
257                                     (gint) iter->user_data);
258         g_value_set_string (value, x);
259         g_free (x);
260       }
261       break;
262     default:
263       g_error ("%s:%d Invalid column in spreadsheet model",
264                __FILE__, __LINE__);
265       break;
266     }
267 }
268
269 static gboolean
270 tree_model_nth_child (GtkTreeModel * model, GtkTreeIter * iter,
271                       GtkTreeIter * parent, gint n)
272 {
273   PsppireSpreadsheetModel *spreadsheetModel =
274     PSPPIRE_SPREADSHEET_MODEL (model);
275
276   if (parent)
277     return FALSE;
278
279   if (n >= spreadsheetModel->spreadsheet->n_sheets)
280     return FALSE;
281
282   iter->stamp = spreadsheetModel->stamp;
283   iter->user_data = (gpointer) n;
284
285   return TRUE;
286 }
287
288 static gint
289 tree_model_n_children (GtkTreeModel * model, GtkTreeIter * iter)
290 {
291   PsppireSpreadsheetModel *spreadsheetModel =
292     PSPPIRE_SPREADSHEET_MODEL (model);
293
294   if (iter == NULL)
295     return spreadsheetModel->spreadsheet->n_sheets;
296
297   return 0;
298 }
299
300 static gboolean
301 tree_model_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter)
302 {
303   return FALSE;
304 }
305
306 static GtkTreePath *
307 tree_model_get_path (GtkTreeModel * model, GtkTreeIter * iter)
308 {
309   PsppireSpreadsheetModel *spreadsheetModel =
310     PSPPIRE_SPREADSHEET_MODEL (model);
311   GtkTreePath *path;
312   gint index = (gint) iter->user_data;
313
314   g_return_val_if_fail (iter->stamp == spreadsheetModel->stamp, NULL);
315
316   path = gtk_tree_path_new ();
317
318   gtk_tree_path_append_index (path, index);
319
320   return path;
321 }
322
323
324 static gboolean
325 tree_model_children (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent)
326 {
327   PsppireSpreadsheetModel *spreadsheetModel = PSPPIRE_SPREADSHEET_MODEL (model);
328
329   if (parent != NULL)
330     return FALSE;
331
332   iter->stamp = spreadsheetModel->stamp;
333   iter->user_data = 0;
334     
335   return TRUE;
336 }
337
338
339
340 static void
341 spreadsheet_tree_model_init (GtkTreeModelIface * iface)
342 {
343   iface->get_flags = tree_model_get_flags;
344   iface->get_n_columns = tree_model_n_columns;
345   iface->get_column_type = tree_model_column_type;
346   iface->get_iter = tree_model_get_iter;
347   iface->iter_next = tree_model_iter_next;
348   iface->get_value = tree_model_get_value;
349
350   iface->iter_children = tree_model_children;
351   iface->iter_parent = NULL;
352
353   iface->get_path = tree_model_get_path;
354   iface->iter_has_child = tree_model_iter_has_child;
355   iface->iter_n_children = tree_model_n_children;
356   iface->iter_nth_child = tree_model_nth_child;
357 }