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