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 (&registering);
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 (&registering);
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