1 /*
2  * Copyright (C) 2008 - 2011 Vivien Malerba <malerba@gnome-db.org>
3  * Copyright (C) 2010 David King <davidk@openismus.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA  02110-1301, USA.
19  */
20 
21 #include <stdarg.h>
22 #include <string.h>
23 #include <glib/gi18n-lib.h>
24 #include <libgda/gda-data-model.h>
25 #include <libgda/gda-quark-list.h>
26 #include <libgda/gda-data-model-extra.h>
27 #include <libgda/gda-data-model-dsn-list.h>
28 #include <libgda/gda-config.h>
29 
30 struct _GdaDataModelDsnListPrivate {
31 	gint    nb_dsn;
32 	GSList *columns;
33 	gint    row_to_remove;
34 	GValue *tmp_value;
35 };
36 
37 static void gda_data_model_dsn_list_class_init (GdaDataModelDsnListClass *klass);
38 static void gda_data_model_dsn_list_init       (GdaDataModelDsnList *model,
39 						GdaDataModelDsnListClass *klass);
40 static void gda_data_model_dsn_list_dispose    (GObject *object);
41 
42 /* GdaDataModel interface */
43 static void                 gda_data_model_dsn_list_data_model_init (GdaDataModelIface *iface);
44 static gint                 gda_data_model_dsn_list_get_n_rows      (GdaDataModel *model);
45 static gint                 gda_data_model_dsn_list_get_n_columns   (GdaDataModel *model);
46 static GdaColumn           *gda_data_model_dsn_list_describe_column (GdaDataModel *model, gint col);
47 static GdaDataModelAccessFlags gda_data_model_dsn_list_get_access_flags(GdaDataModel *model);
48 static const GValue        *gda_data_model_dsn_list_get_value_at    (GdaDataModel *model, gint col, gint row, GError **error);
49 static GdaValueAttribute    gda_data_model_dsn_list_get_attributes_at (GdaDataModel *model, gint col, gint row);
50 
51 static GObjectClass *parent_class = NULL;
52 
53 static void dsn_added_cb (GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model);
54 static void dsn_to_be_removed_cb (GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model);
55 static void dsn_removed_cb (GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model);
56 static void dsn_changed_cb (GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model);
57 
58 /*
59  * Object init and finalize
60  */
61 static void
gda_data_model_dsn_list_data_model_init(GdaDataModelIface * iface)62 gda_data_model_dsn_list_data_model_init (GdaDataModelIface *iface)
63 {
64         iface->i_get_n_rows = gda_data_model_dsn_list_get_n_rows;
65         iface->i_get_n_columns = gda_data_model_dsn_list_get_n_columns;
66         iface->i_describe_column = gda_data_model_dsn_list_describe_column;
67         iface->i_get_access_flags = gda_data_model_dsn_list_get_access_flags;
68         iface->i_get_value_at = gda_data_model_dsn_list_get_value_at;
69         iface->i_get_attributes_at = gda_data_model_dsn_list_get_attributes_at;
70 
71         iface->i_create_iter = NULL;
72         iface->i_iter_at_row = NULL;
73         iface->i_iter_next = NULL;
74         iface->i_iter_prev = NULL;
75 
76         iface->i_set_value_at = NULL;
77 	iface->i_iter_set_value = NULL;
78         iface->i_set_values = NULL;
79         iface->i_append_values = NULL;
80         iface->i_append_row = NULL;
81         iface->i_remove_row = NULL;
82         iface->i_find_row = NULL;
83 
84         iface->i_set_notify = NULL;
85         iface->i_get_notify = NULL;
86         iface->i_send_hint = NULL;
87 }
88 
89 static void
gda_data_model_dsn_list_init(GdaDataModelDsnList * model,G_GNUC_UNUSED GdaDataModelDsnListClass * klass)90 gda_data_model_dsn_list_init (GdaDataModelDsnList *model,
91 			      G_GNUC_UNUSED GdaDataModelDsnListClass *klass)
92 {
93 	GdaConfig *config;
94 	GdaColumn *col;
95 
96 	g_return_if_fail (GDA_IS_DATA_MODEL_DSN_LIST (model));
97 
98 	model->priv = g_new0 (GdaDataModelDsnListPrivate, 1);
99 	model->priv->nb_dsn = gda_config_get_nb_dsn ();
100 	model->priv->row_to_remove = -1;
101 
102 	col = gda_column_new ();
103 	gda_column_set_name (col, _("DSN"));
104 	gda_column_set_description (col, _("DSN"));
105 	gda_column_set_g_type (col, G_TYPE_STRING);
106 	model->priv->columns = g_slist_append (NULL, col);
107 
108 	col = gda_column_new ();
109 	gda_column_set_name (col, _("Provider"));
110 	gda_column_set_description (col, _("Provider"));
111 	gda_column_set_g_type (col, G_TYPE_STRING);
112 	model->priv->columns = g_slist_append (model->priv->columns, col);
113 
114 	col = gda_column_new ();
115 	gda_column_set_name (col, _("Description"));
116 	gda_column_set_description (col, _("Description"));
117 	gda_column_set_g_type (col, G_TYPE_STRING);
118 	model->priv->columns = g_slist_append (model->priv->columns, col);
119 
120 	col = gda_column_new ();
121 	/* To translators: a "Connection string" is a semi-colon delimited list of key=value pairs which
122 	 * define the parameters for a connection, such as "DB_NAME=thedb;HOSTNAME=moon */
123 	gda_column_set_name (col, _("Connection string"));
124 	gda_column_set_description (col, _("Connection string"));
125 	gda_column_set_g_type (col, G_TYPE_STRING);
126 	model->priv->columns = g_slist_append (model->priv->columns, col);
127 
128 	col = gda_column_new ();
129 	gda_column_set_name (col, _("Username"));
130 	gda_column_set_description (col, _("Username"));
131 	gda_column_set_g_type (col, G_TYPE_STRING);
132 	model->priv->columns = g_slist_append (model->priv->columns, col);
133 
134 	col = gda_column_new ();
135 	gda_column_set_name (col, _("Global"));
136 	gda_column_set_description (col, _("Global"));
137 	gda_column_set_g_type (col, G_TYPE_BOOLEAN);
138 	model->priv->columns = g_slist_append (model->priv->columns, col);
139 
140 	g_object_set_data (G_OBJECT (model), "name", _("List of defined data sources"));
141 
142 	config = gda_config_get ();
143 	g_signal_connect (G_OBJECT (config), "dsn-added",
144 			  G_CALLBACK (dsn_added_cb), model);
145 	g_signal_connect (G_OBJECT (config), "dsn-to-be-removed",
146 			  G_CALLBACK (dsn_to_be_removed_cb), model);
147 	g_signal_connect (G_OBJECT (config), "dsn-removed",
148 			  G_CALLBACK (dsn_removed_cb), model);
149 	g_signal_connect (G_OBJECT (config), "dsn-changed",
150 			  G_CALLBACK (dsn_changed_cb), model);
151 	g_object_unref (config);
152 
153 	model->priv->tmp_value = NULL;
154 }
155 
156 static void
gda_data_model_dsn_list_class_init(GdaDataModelDsnListClass * klass)157 gda_data_model_dsn_list_class_init (GdaDataModelDsnListClass *klass)
158 {
159 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
160 
161 	parent_class = g_type_class_peek_parent (klass);
162 
163 	object_class->dispose = gda_data_model_dsn_list_dispose;
164 }
165 
166 static void
gda_data_model_dsn_list_dispose(GObject * object)167 gda_data_model_dsn_list_dispose (GObject *object)
168 {
169 	GdaDataModelDsnList *model = (GdaDataModelDsnList *) object;
170 
171 	g_return_if_fail (GDA_IS_DATA_MODEL_DSN_LIST (model));
172 
173 	if (model->priv) {
174 		GdaConfig *config = gda_config_get ();
175 		g_signal_handlers_disconnect_by_func (G_OBJECT (config),
176 						      G_CALLBACK (dsn_added_cb), model);
177 		g_signal_handlers_disconnect_by_func (G_OBJECT (config),
178 						      G_CALLBACK (dsn_removed_cb), model);
179 		g_signal_handlers_disconnect_by_func (G_OBJECT (config),
180 						      G_CALLBACK (dsn_to_be_removed_cb), model);
181 		g_signal_handlers_disconnect_by_func (G_OBJECT (config),
182 						      G_CALLBACK (dsn_changed_cb), model);
183 		g_object_unref (config);
184 		if (model->priv->tmp_value) {
185 			gda_value_free (model->priv->tmp_value);
186 			model->priv->tmp_value = NULL;
187 		}
188 
189 		g_free (model->priv);
190 		model->priv = NULL;
191 	}
192 
193 	parent_class->dispose (object);
194 }
195 
196 static void
dsn_added_cb(G_GNUC_UNUSED GdaConfig * conf,GdaDsnInfo * info,GdaDataModelDsnList * model)197 dsn_added_cb (G_GNUC_UNUSED GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model)
198 {
199 	model->priv->nb_dsn++;
200 	gda_data_model_row_inserted ((GdaDataModel *) model, gda_config_get_dsn_info_index (info->name));
201 }
202 
203 static void
dsn_to_be_removed_cb(G_GNUC_UNUSED GdaConfig * conf,GdaDsnInfo * info,GdaDataModelDsnList * model)204 dsn_to_be_removed_cb (G_GNUC_UNUSED GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model)
205 {
206 	model->priv->row_to_remove = gda_config_get_dsn_info_index (info->name);
207 }
208 
209 static void
dsn_removed_cb(G_GNUC_UNUSED GdaConfig * conf,G_GNUC_UNUSED GdaDsnInfo * info,GdaDataModelDsnList * model)210 dsn_removed_cb (G_GNUC_UNUSED GdaConfig *conf, G_GNUC_UNUSED GdaDsnInfo *info, GdaDataModelDsnList *model)
211 {
212 	model->priv->nb_dsn--;
213 	gda_data_model_row_removed ((GdaDataModel *) model, model->priv->row_to_remove);
214 	model->priv->row_to_remove = -1;
215 }
216 
217 static void
dsn_changed_cb(G_GNUC_UNUSED GdaConfig * conf,GdaDsnInfo * info,GdaDataModelDsnList * model)218 dsn_changed_cb (G_GNUC_UNUSED GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model)
219 {
220 	gda_data_model_row_updated ((GdaDataModel *) model, gda_config_get_dsn_info_index (info->name));
221 }
222 
223 
224 /*
225  * Public functions
226  */
227 
228 GType
_gda_data_model_dsn_list_get_type(void)229 _gda_data_model_dsn_list_get_type (void)
230 {
231 	static GType type = 0;
232 
233 	if (G_UNLIKELY (type == 0)) {
234 		static GMutex registering;
235 		static const GTypeInfo info = {
236 			sizeof (GdaDataModelDsnListClass),
237 			(GBaseInitFunc) NULL,
238 			(GBaseFinalizeFunc) NULL,
239 			(GClassInitFunc) gda_data_model_dsn_list_class_init,
240 			NULL,
241 			NULL,
242 			sizeof (GdaDataModelDsnList),
243 			0,
244 			(GInstanceInitFunc) gda_data_model_dsn_list_init,
245 			0
246 		};
247 		static const GInterfaceInfo data_model_info = {
248                         (GInterfaceInitFunc) gda_data_model_dsn_list_data_model_init,
249                         NULL,
250                         NULL
251                 };
252 
253 		g_mutex_lock (&registering);
254 		if (type == 0) {
255 			type = g_type_register_static (G_TYPE_OBJECT, "GdaDataModelDsnList", &info, 0);
256 			g_type_add_interface_static (type, GDA_TYPE_DATA_MODEL, &data_model_info);
257 		}
258 		g_mutex_unlock (&registering);
259 	}
260 
261 	return type;
262 }
263 
264 /*
265  * GdaDataModel implementation
266  */
267 
268 static gint
gda_data_model_dsn_list_get_n_rows(GdaDataModel * model)269 gda_data_model_dsn_list_get_n_rows (GdaDataModel *model)
270 {
271 	GdaDataModelDsnList *dmodel = GDA_DATA_MODEL_DSN_LIST (model);
272 
273 	return dmodel->priv->nb_dsn;
274 }
275 
276 static gint
gda_data_model_dsn_list_get_n_columns(GdaDataModel * model)277 gda_data_model_dsn_list_get_n_columns (GdaDataModel *model)
278 {
279 	GdaDataModelDsnList *dmodel = GDA_DATA_MODEL_DSN_LIST (model);
280 
281 	return g_slist_length (dmodel->priv->columns);
282 }
283 
284 static GdaColumn *
gda_data_model_dsn_list_describe_column(GdaDataModel * model,gint col)285 gda_data_model_dsn_list_describe_column (GdaDataModel *model, gint col)
286 {
287 	GdaDataModelDsnList *dmodel = GDA_DATA_MODEL_DSN_LIST (model);
288 
289 	return g_slist_nth_data (dmodel->priv->columns, col);
290 }
291 
292 static GdaDataModelAccessFlags
gda_data_model_dsn_list_get_access_flags(G_GNUC_UNUSED GdaDataModel * model)293 gda_data_model_dsn_list_get_access_flags (G_GNUC_UNUSED GdaDataModel *model)
294 {
295 	return GDA_DATA_MODEL_ACCESS_RANDOM;
296 }
297 
298 static const GValue *
gda_data_model_dsn_list_get_value_at(GdaDataModel * model,gint col,gint row,GError ** error)299 gda_data_model_dsn_list_get_value_at (GdaDataModel *model, gint col, gint row, GError **error)
300 {
301 	GdaDataModelDsnList *dmodel = GDA_DATA_MODEL_DSN_LIST (model);
302 
303 	if (dmodel->priv->tmp_value) {
304 		gda_value_free (dmodel->priv->tmp_value);
305 		dmodel->priv->tmp_value = NULL;
306 	}
307 
308 	if ((col >= gda_data_model_dsn_list_get_n_columns (model)) ||
309 	    (col < 0)) {
310 		g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_COLUMN_OUT_OF_RANGE_ERROR,
311                              _("Column %d out of range (0-%d)"), col, gda_data_model_dsn_list_get_n_columns (model) - 1);
312                 return NULL;
313 	}
314 	if ((row < 0) || (row >= gda_data_model_dsn_list_get_n_rows (model))) {
315 		gint n;
316 		n = gda_data_model_dsn_list_get_n_rows (model);
317 		if (n > 0)
318 			g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR,
319 				     _("Row %d out of range (0-%d)"), row, n - 1);
320 		else
321 			g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR,
322 				     _("Row %d not found (empty data model)"), row);
323 		return NULL;
324 	}
325 
326 	GdaDsnInfo *info = gda_config_get_dsn_info_at_index (row);
327 	g_assert (info);
328 	if (col != 5)
329 		dmodel->priv->tmp_value = gda_value_new (G_TYPE_STRING);
330 	else
331 		dmodel->priv->tmp_value = gda_value_new (G_TYPE_BOOLEAN);
332 	switch (col) {
333 	case 0:
334 		g_value_set_string (dmodel->priv->tmp_value, info->name);
335 		break;
336 	case 1:
337 		g_value_set_string (dmodel->priv->tmp_value, info->provider);
338 		break;
339 	case 2:
340 		g_value_set_string (dmodel->priv->tmp_value, info->description);
341 		break;
342 	case 3:
343 		g_value_set_string (dmodel->priv->tmp_value, info->cnc_string);
344 		break;
345 	case 4:
346 		if (info->auth_string) {
347 			GdaQuarkList* ql;
348 			ql = gda_quark_list_new_from_string (info->auth_string);
349 
350 			g_value_set_string (dmodel->priv->tmp_value, gda_quark_list_find (ql, "USERNAME"));
351 			gda_quark_list_free (ql);
352 		}
353 		else
354 			g_value_set_string (dmodel->priv->tmp_value, "");
355 		break;
356 	case 5:
357 		g_value_set_boolean (dmodel->priv->tmp_value, info->is_system);
358 		break;
359 	default:
360 		g_assert_not_reached ();
361 	}
362 
363 	return dmodel->priv->tmp_value;
364 }
365 
366 static GdaValueAttribute
gda_data_model_dsn_list_get_attributes_at(G_GNUC_UNUSED GdaDataModel * model,G_GNUC_UNUSED gint col,G_GNUC_UNUSED gint row)367 gda_data_model_dsn_list_get_attributes_at (G_GNUC_UNUSED GdaDataModel *model, G_GNUC_UNUSED gint col, G_GNUC_UNUSED gint row)
368 {
369 	return GDA_VALUE_ATTR_NO_MODIF;
370 }
371