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