b5ac123755714ec24f6102b4688b7ac81eead721
[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
261         g_value_set_string (value, x ? x : "(empty)");
262         g_free (x);
263       }
264       break;
265     default:
266       g_error ("%s:%d Invalid column in spreadsheet model",
267                __FILE__, __LINE__);
268       break;
269     }
270 }
271
272 static gboolean
273 tree_model_nth_child (GtkTreeModel * model, GtkTreeIter * iter,
274                       GtkTreeIter * parent, gint n)
275 {
276   PsppireSpreadsheetModel *spreadsheetModel =
277     PSPPIRE_SPREADSHEET_MODEL (model);
278
279   if (parent)
280     return FALSE;
281
282   if (n >= spreadsheetModel->spreadsheet->n_sheets)
283     return FALSE;
284
285   iter->stamp = spreadsheetModel->stamp;
286   iter->user_data = (gpointer) n;
287
288   return TRUE;
289 }
290
291 static gint
292 tree_model_n_children (GtkTreeModel * model, GtkTreeIter * iter)
293 {
294   PsppireSpreadsheetModel *spreadsheetModel =
295     PSPPIRE_SPREADSHEET_MODEL (model);
296
297   if (iter == NULL)
298     return spreadsheetModel->spreadsheet->n_sheets;
299
300   return 0;
301 }
302
303 static gboolean
304 tree_model_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter)
305 {
306   return FALSE;
307 }
308
309 static GtkTreePath *
310 tree_model_get_path (GtkTreeModel * model, GtkTreeIter * iter)
311 {
312   PsppireSpreadsheetModel *spreadsheetModel =
313     PSPPIRE_SPREADSHEET_MODEL (model);
314   GtkTreePath *path;
315   gint index = (gint) iter->user_data;
316
317   g_return_val_if_fail (iter->stamp == spreadsheetModel->stamp, NULL);
318
319   path = gtk_tree_path_new ();
320
321   gtk_tree_path_append_index (path, index);
322
323   return path;
324 }
325
326
327 static gboolean
328 tree_model_children (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent)
329 {
330   PsppireSpreadsheetModel *spreadsheetModel = PSPPIRE_SPREADSHEET_MODEL (model);
331
332   if (parent != NULL)
333     return FALSE;
334
335   iter->stamp = spreadsheetModel->stamp;
336   iter->user_data = 0;
337     
338   return TRUE;
339 }
340
341
342
343 static void
344 spreadsheet_tree_model_init (GtkTreeModelIface * iface)
345 {
346   iface->get_flags = tree_model_get_flags;
347   iface->get_n_columns = tree_model_n_columns;
348   iface->get_column_type = tree_model_column_type;
349   iface->get_iter = tree_model_get_iter;
350   iface->iter_next = tree_model_iter_next;
351   iface->get_value = tree_model_get_value;
352
353   iface->iter_children = tree_model_children;
354   iface->iter_parent = NULL;
355
356   iface->get_path = tree_model_get_path;
357   iface->iter_has_child = tree_model_iter_has_child;
358   iface->iter_n_children = tree_model_n_children;
359   iface->iter_nth_child = tree_model_nth_child;
360 }