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
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
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",
gda_data_model_dir_data_model_init(GdaDataModelIface * iface)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
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
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) {
gda_data_model_dir_init(GdaDataModelDir * model,G_GNUC_UNUSED GdaDataModelDirClass * klass)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;
gda_data_model_dir_class_init(GdaDataModelDirClass * klass)187 }
188
189 g_free (model->priv);
190 model->priv = NULL;
191 }
192
193 parent_class->dispose (object);
194 }
195
196 static void
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
204 dsn_to_be_removed_cb (G_GNUC_UNUSED GdaConfig *conf, GdaDsnInfo *info, GdaDataModelDsnList *model)
205 {
file_row_foreach_func(FileRow * row,G_GNUC_UNUSED gpointer data)206 model->priv->row_to_remove = gda_config_get_dsn_info_index (info->name);
207 }
208
209 static void
210 dsn_removed_cb (G_GNUC_UNUSED GdaConfig *conf, G_GNUC_UNUSED GdaDsnInfo *info, GdaDataModelDsnList *model)
211 {
gda_data_model_dir_dispose(GObject * object)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
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
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,
add_error(GdaDataModelDir * model,const gchar * err)250 NULL
251 };
252
253 g_mutex_lock (®istering);
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 (®istering);
259 }
260
261 return type;
262 }
263
gda_data_model_dir_get_type(void)264 /*
265 * GdaDataModel implementation
266 */
267
268 static gint
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
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 *
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
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_dir_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)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
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