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