1 /*
2 * Copyright (C) 2010 David King <davidk@openismus.com>
3 * Copyright (C) 2010 - 2011 Vivien Malerba <malerba@gnome-db.org>
4 * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include <string.h>
22 #include <glib/gstdio.h>
23 #include <libgda/gda-data-model.h>
24 #include <libgda/gda-data-model-extra.h>
25 #include <libgda/gda-row.h>
26 #include <data-model-errors.h>
27 #include <libgda/gda-debug-macros.h>
28 #include "test-errors.h"
29
30 #define NCOLS 4
31 typedef struct {
32 gchar *col0;
33 gchar *col1;
34 gchar *col2;
35 gchar *col3;
36 } ARow;
37
38 ARow data[] = {
39 {"-", "Cell 0,1", "Cell 0,2", "Cell 0,3"},
40 {"Cell 1,0", "-", NULL, "Cell 1,3"},
41 {"Cell 2,0", "Cell 2,1", NULL, "Cell 2,3"},
42 {"Cell 3,0", "Cell 3,1", "-", NULL },
43 };
44
45 struct _DataModelErrorsPrivate {
46 GSList *columns; /* list of GdaColumn objects */
47 GPtrArray *rows; /* array of GdaRow pointers */
48 };
49
50 static void data_model_errors_class_init (DataModelErrorsClass *klass);
51 static void data_model_errors_init (DataModelErrors *model,
52 DataModelErrorsClass *klass);
53 static void data_model_errors_dispose (GObject *object);
54
55 /* GdaDataModel interface */
56 static void data_model_errors_data_model_init (GdaDataModelIface *iface);
57 static gint data_model_errors_get_n_rows (GdaDataModel *model);
58 static gint data_model_errors_get_n_columns (GdaDataModel *model);
59 static GdaColumn *data_model_errors_describe_column (GdaDataModel *model, gint col);
60 static GdaDataModelAccessFlags data_model_errors_get_access_flags(GdaDataModel *model);
61 static const GValue *data_model_errors_get_value_at (GdaDataModel *model, gint col, gint row, GError **error);
62 static GdaValueAttribute data_model_errors_get_attributes_at (GdaDataModel *model, gint col, gint row);
63
64 static gboolean data_model_errors_set_value_at (GdaDataModel *model, gint col, gint row, const GValue *value, GError **error);
65 static gint data_model_errors_append_values (GdaDataModel *model, const GList *values, GError **error);
66 static gboolean data_model_errors_remove_row (GdaDataModel *model, gint row, GError **error);
67
68 static GObjectClass *parent_class = NULL;
69 #define CLASS(model) (DATA_MODEL_ERRORS_CLASS (G_OBJECT_GET_CLASS (model)))
70
71 /*
72 * Object init and dispose
73 */
74 static void
data_model_errors_data_model_init(GdaDataModelIface * iface)75 data_model_errors_data_model_init (GdaDataModelIface *iface)
76 {
77 iface->i_get_n_rows = data_model_errors_get_n_rows;
78 iface->i_get_n_columns = data_model_errors_get_n_columns;
79 iface->i_describe_column = data_model_errors_describe_column;
80 iface->i_get_access_flags = data_model_errors_get_access_flags;
81 iface->i_get_value_at = data_model_errors_get_value_at;
82 iface->i_get_attributes_at = data_model_errors_get_attributes_at;
83
84 iface->i_create_iter = NULL;
85 iface->i_iter_at_row = NULL;
86 iface->i_iter_next = NULL;
87 iface->i_iter_prev = NULL;
88
89 iface->i_set_value_at = data_model_errors_set_value_at;
90 iface->i_iter_set_value = NULL;
91 iface->i_set_values = NULL;
92 iface->i_append_values = data_model_errors_append_values;
93 iface->i_append_row = NULL;
94 iface->i_remove_row = data_model_errors_remove_row;
95 iface->i_find_row = NULL;
96
97 iface->i_set_notify = NULL;
98 iface->i_get_notify = NULL;
99 iface->i_send_hint = NULL;
100 }
101
102 static void
data_model_errors_init(DataModelErrors * model,G_GNUC_UNUSED DataModelErrorsClass * klass)103 data_model_errors_init (DataModelErrors *model,
104 G_GNUC_UNUSED DataModelErrorsClass *klass)
105 {
106 gsize i;
107 g_return_if_fail (IS_DATA_MODEL_ERRORS (model));
108
109 model->priv = g_new0 (DataModelErrorsPrivate, 1);
110
111 /* columns */
112 model->priv->columns = NULL;
113 for (i = 0; i < NCOLS; i++) {
114 GdaColumn *col;
115 gchar *str;
116 col = gda_column_new ();
117 gda_column_set_g_type (col, G_TYPE_STRING);
118 str = g_strdup_printf ("col%" G_GSIZE_FORMAT, i);
119 gda_column_set_name (col, str);
120 gda_column_set_description (col, str);
121 g_object_set (G_OBJECT (col), "id", str, NULL);
122 g_free (str);
123
124 model->priv->columns = g_slist_append (model->priv->columns, col);
125 }
126
127 /* rows */
128 model->priv->rows = g_ptr_array_new (); /* array of GdaRow pointers */
129 for (i = 0; i < (sizeof (data) / sizeof (ARow)); i++) {
130 ARow *arow = &(data[i]);
131 GdaRow *row = gda_row_new (NCOLS);
132 GValue *value;
133 value = gda_row_get_value (row, 0);
134 if (arow->col0) {
135 if (*arow->col0 == '-')
136 G_VALUE_TYPE (value) = G_TYPE_INVALID;
137 else {
138 gda_value_reset_with_type (value, G_TYPE_STRING);
139 g_value_set_string (value, arow->col0);
140 }
141 }
142
143 value = gda_row_get_value (row, 1);
144 if (arow->col1) {
145 if (*arow->col1 == '-')
146 G_VALUE_TYPE (value) = G_TYPE_INVALID;
147 else {
148 gda_value_reset_with_type (value, G_TYPE_STRING);
149 g_value_set_string (value, arow->col1);
150 }
151 }
152
153 value = gda_row_get_value (row, 2);
154 if (arow->col2) {
155 if (*arow->col2 == '-')
156 G_VALUE_TYPE (value) = G_TYPE_INVALID;
157 else {
158 gda_value_reset_with_type (value, G_TYPE_STRING);
159 g_value_set_string (value, arow->col2);
160 }
161 }
162
163 value = gda_row_get_value (row, 3);
164 if (arow->col3) {
165 if (*arow->col3 == '-')
166 G_VALUE_TYPE (value) = G_TYPE_INVALID;
167 else {
168 gda_value_reset_with_type (value, G_TYPE_STRING);
169 g_value_set_string (value, arow->col3);
170 }
171 }
172
173 g_ptr_array_add (model->priv->rows, row);
174 }
175 }
176
177 static void
data_model_errors_class_init(DataModelErrorsClass * klass)178 data_model_errors_class_init (DataModelErrorsClass *klass)
179 {
180 GObjectClass *object_class = G_OBJECT_CLASS (klass);
181
182 parent_class = g_type_class_peek_parent (klass);
183
184 /* virtual functions */
185 object_class->dispose = data_model_errors_dispose;
186 }
187
188 static void
data_model_errors_dispose(GObject * object)189 data_model_errors_dispose (GObject * object)
190 {
191 DataModelErrors *model = (DataModelErrors *) object;
192
193 g_return_if_fail (IS_DATA_MODEL_ERRORS (model));
194
195 if (model->priv) {
196 if (model->priv->columns) {
197 g_slist_foreach (model->priv->columns, (GFunc) g_object_unref, NULL);
198 g_slist_free (model->priv->columns);
199 model->priv->columns = NULL;
200 }
201
202 /* DONT: g_ptr_array_foreach (model->priv->rows, (GFunc) g_object_unref, NULL);
203 * because we use the convention that G_VALUE_TYPE() == G_TYPE_INVALID for errors */
204 g_ptr_array_free (model->priv->rows, TRUE);
205 g_free (model->priv);
206 model->priv = NULL;
207 }
208
209 parent_class->dispose (object);
210 }
211
212 GType
data_model_errors_get_type(void)213 data_model_errors_get_type (void)
214 {
215 static GType type = 0;
216
217 if (G_UNLIKELY (type == 0)) {
218 static GMutex registering;
219 static const GTypeInfo info = {
220 sizeof (DataModelErrorsClass),
221 (GBaseInitFunc) NULL,
222 (GBaseFinalizeFunc) NULL,
223 (GClassInitFunc) data_model_errors_class_init,
224 NULL,
225 NULL,
226 sizeof (DataModelErrors),
227 0,
228 (GInstanceInitFunc) data_model_errors_init,
229 0
230 };
231 static const GInterfaceInfo data_model_info = {
232 (GInterfaceInitFunc) data_model_errors_data_model_init,
233 NULL,
234 NULL
235 };
236
237 g_mutex_lock (®istering);
238 if (type == 0) {
239 type = g_type_register_static (G_TYPE_OBJECT, "DataModelErrors", &info, 0);
240 g_type_add_interface_static (type, GDA_TYPE_DATA_MODEL, &data_model_info);
241 }
242 g_mutex_unlock (®istering);
243 }
244 return type;
245 }
246
247 /*
248 * data_model_errors_new
249 *
250 * Creates a new #GdaDataModel object
251 *
252 * Returns: a new #GdaDataModel
253 */
254 GdaDataModel *
data_model_errors_new(void)255 data_model_errors_new (void)
256 {
257 GdaDataModel *model;
258 model = (GdaDataModel *) g_object_new (TYPE_DATA_MODEL_ERRORS, NULL);
259
260 return model;
261 }
262
263 static gint
data_model_errors_get_n_rows(GdaDataModel * model)264 data_model_errors_get_n_rows (GdaDataModel *model)
265 {
266 DataModelErrors *imodel = (DataModelErrors *) model;
267
268 g_return_val_if_fail (IS_DATA_MODEL_ERRORS (imodel), 0);
269 g_return_val_if_fail (imodel->priv != NULL, 0);
270
271 return imodel->priv->rows->len;
272 }
273
274 static gint
data_model_errors_get_n_columns(GdaDataModel * model)275 data_model_errors_get_n_columns (GdaDataModel *model)
276 {
277 DataModelErrors *imodel;
278 g_return_val_if_fail (IS_DATA_MODEL_ERRORS (model), 0);
279 imodel = DATA_MODEL_ERRORS (model);
280 g_return_val_if_fail (imodel->priv, 0);
281
282 return NCOLS;
283 }
284
285 static GdaColumn *
data_model_errors_describe_column(GdaDataModel * model,gint col)286 data_model_errors_describe_column (GdaDataModel *model, gint col)
287 {
288 DataModelErrors *imodel;
289 g_return_val_if_fail (IS_DATA_MODEL_ERRORS (model), NULL);
290 imodel = DATA_MODEL_ERRORS (model);
291 g_return_val_if_fail (imodel->priv, NULL);
292
293 return g_slist_nth_data (imodel->priv->columns, col);
294 }
295
296 static GdaDataModelAccessFlags
data_model_errors_get_access_flags(GdaDataModel * model)297 data_model_errors_get_access_flags (GdaDataModel *model)
298 {
299 DataModelErrors *imodel;
300 GdaDataModelAccessFlags flags;
301
302 g_return_val_if_fail (IS_DATA_MODEL_ERRORS (model), 0);
303 imodel = DATA_MODEL_ERRORS (model);
304 g_return_val_if_fail (imodel->priv, 0);
305
306 flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD |
307 GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD |
308 GDA_DATA_MODEL_ACCESS_RANDOM |
309 GDA_DATA_MODEL_ACCESS_WRITE;
310
311 return flags;
312 }
313
314 static const GValue *
data_model_errors_get_value_at(GdaDataModel * model,gint col,gint row,GError ** error)315 data_model_errors_get_value_at (GdaDataModel *model, gint col, gint row, GError **error)
316 {
317 DataModelErrors *imodel;
318 GValue *value = NULL;
319 GdaRow *drow;
320
321 g_return_val_if_fail (IS_DATA_MODEL_ERRORS (model), NULL);
322 imodel = DATA_MODEL_ERRORS (model);
323 g_return_val_if_fail (imodel->priv, NULL);
324
325 if ((col < 0) || (col > NCOLS)) {
326 gchar *tmp;
327 tmp = g_strdup_printf ("Column %d out of range (0-%d)", col, NCOLS-1);
328 g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_COLUMN_OUT_OF_RANGE_ERROR,
329 "%s", tmp);
330 g_free (tmp);
331 return NULL;
332 }
333
334 if (row >= (gint)imodel->priv->rows->len) {
335 gchar *str;
336 if (imodel->priv->rows->len > 0)
337 str = g_strdup_printf ("Row %d out of range (0-%d)", row,
338 imodel->priv->rows->len - 1);
339 else
340 str = g_strdup_printf ("Row %d not found (empty data model)", row);
341 g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR,
342 "%s", str);
343 g_free (str);
344 return NULL;
345 }
346
347 drow = g_ptr_array_index (imodel->priv->rows, row);
348 if (drow) {
349 GValue *val = gda_row_get_value (drow, col);
350 if (G_VALUE_TYPE (val) == G_TYPE_INVALID) {
351 /* simulates an error */
352 g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR,
353 "%s", "Simulated error");
354 }
355 else
356 value = val;
357 }
358 else
359 g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_NOT_FOUND_ERROR,
360 "%s", "Row not found");
361
362 return value;
363 }
364
365 static GdaValueAttribute
data_model_errors_get_attributes_at(GdaDataModel * model,gint col,G_GNUC_UNUSED gint row)366 data_model_errors_get_attributes_at (GdaDataModel *model, gint col, G_GNUC_UNUSED gint row)
367 {
368 DataModelErrors *imodel;
369 GdaValueAttribute flags = 0;
370 g_return_val_if_fail (IS_DATA_MODEL_ERRORS (model), 0);
371 imodel = DATA_MODEL_ERRORS (model);
372 g_return_val_if_fail (imodel->priv, 0);
373
374 if ((col < 0) || (col > NCOLS)) {
375 gchar *tmp;
376 tmp = g_strdup_printf ("Column %d out of range (0-%d)", col, NCOLS-1);
377 g_free (tmp);
378 return 0;
379 }
380
381 flags = 0;
382 return flags;
383 }
384
385 static gboolean
data_model_errors_set_value_at(GdaDataModel * model,gint col,gint row,const GValue * value,GError ** error)386 data_model_errors_set_value_at (GdaDataModel *model, gint col, gint row, const GValue *value, GError **error)
387 {
388 gboolean retval = TRUE;
389 DataModelErrors *imodel;
390
391 g_return_val_if_fail (IS_DATA_MODEL_ERRORS (model), FALSE);
392 imodel = DATA_MODEL_ERRORS (model);
393 g_return_val_if_fail (imodel->priv, FALSE);
394
395 if ((col < 0) || (col > NCOLS)) {
396 gchar *tmp;
397 tmp = g_strdup_printf ("Column %d out of range (0-%d)", col, NCOLS-1);
398 g_set_error (error, TEST_ERROR, TEST_ERROR_GENERIC, "%s", tmp);
399 g_free (tmp);
400 return FALSE;
401 }
402
403 GdaRow *drow;
404 drow = g_ptr_array_index (imodel->priv->rows, row);
405 if (drow) {
406 GValue *dvalue;
407 dvalue = gda_row_get_value (drow, col);
408 gda_value_reset_with_type (dvalue, G_VALUE_TYPE (value));
409 g_value_copy (value, dvalue);
410 gda_data_model_row_updated (model, row);
411 }
412 else {
413 g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_NOT_FOUND_ERROR,
414 "%s", "Row not found");
415 retval = FALSE;
416 }
417
418 return retval;
419 }
420
421
422
423 static gint
data_model_errors_append_values(GdaDataModel * model,G_GNUC_UNUSED const GList * values,GError ** error)424 data_model_errors_append_values (GdaDataModel *model, G_GNUC_UNUSED const GList *values, GError **error)
425 {
426 DataModelErrors *imodel;
427
428 g_return_val_if_fail (IS_DATA_MODEL_ERRORS (model), -1);
429 imodel = (DataModelErrors *) model;
430 g_return_val_if_fail (imodel->priv, -1);
431
432 TO_IMPLEMENT;
433 g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_FEATURE_NON_SUPPORTED_ERROR,
434 "%s", "Not implemented");
435 return -1;
436 }
437
438 static gboolean
data_model_errors_remove_row(GdaDataModel * model,gint row,GError ** error)439 data_model_errors_remove_row (GdaDataModel *model, gint row, GError **error)
440 {
441 DataModelErrors *imodel;
442
443 g_return_val_if_fail (IS_DATA_MODEL_ERRORS (model), FALSE);
444 imodel = (DataModelErrors *) model;
445 g_return_val_if_fail (imodel->priv, FALSE);
446
447 if (row >= (gint)imodel->priv->rows->len) {
448 gchar *str;
449 if (imodel->priv->rows->len > 0)
450 str = g_strdup_printf ("Row %d out of range (0-%d)", row,
451 imodel->priv->rows->len - 1);
452 else
453 str = g_strdup_printf ("Row %d not found (empty data model)", row);
454 g_set_error (error, TEST_ERROR, TEST_ERROR_GENERIC, "%s", str);
455 g_free (str);
456 return FALSE;
457 }
458
459 GdaRow *drow;
460 drow = g_ptr_array_index (imodel->priv->rows, row);
461 /* remove row from data model */
462 g_object_unref (drow);
463 g_ptr_array_remove_index (imodel->priv->rows, row);
464 gda_data_model_row_removed (model, row);
465
466 return TRUE;
467 }
468
469