1 /*
2  * Copyright (C) 2009 - 2012 Vivien Malerba <malerba@gnome-db.org>
3  * Copyright (C) 2010 David King <davidk@openismus.com>
4  * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA  02110-1301, USA.
20  */
21 
22 #include "gdaui-entry-wrapper.h"
23 #include <libgda/gda-data-handler.h>
24 #include <libgda/gda-enums.h>
25 
26 static void gdaui_entry_wrapper_class_init (GdauiEntryWrapperClass *klass);
27 static void gdaui_entry_wrapper_init (GdauiEntryWrapper *wid);
28 static void gdaui_entry_wrapper_dispose (GObject *object);
29 
30 static void gdaui_entry_wrapper_set_property (GObject *object,
31 					      guint param_id,
32 					      const GValue *value,
33 					      GParamSpec *pspec);
34 static void gdaui_entry_wrapper_get_property (GObject *object,
35 					      guint param_id,
36 					      GValue *value,
37 					      GParamSpec *pspec);
38 
39 static void contents_changed_cb (GtkWidget *entry, GdauiEntryWrapper *wrapper);
40 static void contents_activated_cb (GtkWidget *entry, GdauiEntryWrapper *wrapper);
41 static void check_correct_init (GdauiEntryWrapper *wid);
42 static void block_signals (GdauiEntryWrapper *wid);
43 static void unblock_signals (GdauiEntryWrapper *wid);
44 
45 /* GdauiDataEntry interface */
46 static void            gdaui_entry_wrapper_data_entry_init   (GdauiDataEntryIface *iface);
47 static void            gdaui_entry_wrapper_set_value_type    (GdauiDataEntry *de, GType type);
48 static GType           gdaui_entry_wrapper_get_value_type    (GdauiDataEntry *de);
49 static void            gdaui_entry_wrapper_set_value         (GdauiDataEntry *de, const GValue *value);
50 static GValue         *gdaui_entry_wrapper_get_value         (GdauiDataEntry *de);
51 static void            gdaui_entry_wrapper_set_ref_value     (GdauiDataEntry *de, const GValue *value);
52 static const GValue   *gdaui_entry_wrapper_get_ref_value     (GdauiDataEntry *de);
53 static void            gdaui_entry_wrapper_set_value_default (GdauiDataEntry *de, const GValue *value);
54 static void            gdaui_entry_wrapper_set_attributes    (GdauiDataEntry *de, GdaValueAttribute attrs, guint mask);
55 static GdaValueAttribute gdaui_entry_wrapper_get_attributes  (GdauiDataEntry *de);
56 static GdaDataHandler *gdaui_entry_wrapper_get_handler       (GdauiDataEntry *de);
57 static void            gdaui_entry_wrapper_set_editable      (GdauiDataEntry *de, gboolean editable);
58 static gboolean        gdaui_entry_wrapper_get_editable      (GdauiDataEntry *de);
59 static void            gdaui_entry_wrapper_grab_focus        (GdauiDataEntry *de);
60 static void            gdaui_entry_wrapper_set_unknown_color (GdauiDataEntry *de, gdouble red, gdouble green,
61 							      gdouble blue, gdouble alpha);
62 
63 /* properties */
64 enum {
65 	PROP_0,
66 	PROP_SET_DEFAULT_IF_INVALID
67 };
68 
69 struct  _GdauiEntryWrapperPriv {
70 	gboolean                  impl_is_correct;
71         GtkWidget                *entry;
72 	GdauiEntryWrapperClass   *real_class;
73 	guint                     signals_blocked;
74 
75 	GType                     type;
76 	GValue                   *value_ref;
77 	GValue                   *value_default; /* Can be of any type, not just @type */
78 
79 	gboolean                  null_forced;
80 	gboolean                  default_forced;
81 
82 	gboolean                  null_possible;
83 	gboolean                  default_possible;
84 	gboolean                  show_actions;
85 	gboolean                  editable;
86 	gboolean                  contents_has_changed; /* since this variable was reset */
87 
88 	/* property */
89 	gboolean                  set_default_if_invalid;
90 };
91 
92 /* get a pointer to the parents to be able to call their destructor */
93 static GObjectClass *parent_class = NULL;
94 
95 GType
gdaui_entry_wrapper_get_type(void)96 gdaui_entry_wrapper_get_type (void)
97 {
98 	static GType type = 0;
99 
100 	if (G_UNLIKELY (type == 0)) {
101 		static const GTypeInfo info = {
102 			sizeof (GdauiEntryWrapperClass),
103 			(GBaseInitFunc) NULL,
104 			(GBaseFinalizeFunc) NULL,
105 			(GClassInitFunc) gdaui_entry_wrapper_class_init,
106 			NULL,
107 			NULL,
108 			sizeof (GdauiEntryWrapper),
109 			0,
110 			(GInstanceInitFunc) gdaui_entry_wrapper_init,
111 			0
112 		};
113 
114 		static const GInterfaceInfo data_entry_info = {
115 			(GInterfaceInitFunc) gdaui_entry_wrapper_data_entry_init,
116 			NULL,
117 			NULL
118 		};
119 
120 		type = g_type_register_static (GDAUI_TYPE_ENTRY_SHELL, "GdauiEntryWrapper", &info, 0);
121 		g_type_add_interface_static (type, GDAUI_TYPE_DATA_ENTRY, &data_entry_info);
122 	}
123 	return type;
124 }
125 
126 static void
gdaui_entry_wrapper_data_entry_init(GdauiDataEntryIface * iface)127 gdaui_entry_wrapper_data_entry_init (GdauiDataEntryIface *iface)
128 {
129 	iface->set_value_type = gdaui_entry_wrapper_set_value_type;
130 	iface->get_value_type = gdaui_entry_wrapper_get_value_type;
131 	iface->set_value = gdaui_entry_wrapper_set_value;
132 	iface->get_value = gdaui_entry_wrapper_get_value;
133 	iface->set_ref_value = gdaui_entry_wrapper_set_ref_value;
134 	iface->get_ref_value = gdaui_entry_wrapper_get_ref_value;
135 	iface->set_value_default = gdaui_entry_wrapper_set_value_default;
136 	iface->set_attributes = gdaui_entry_wrapper_set_attributes;
137 	iface->get_attributes = gdaui_entry_wrapper_get_attributes;
138 	iface->get_handler = gdaui_entry_wrapper_get_handler;
139 	iface->set_editable = gdaui_entry_wrapper_set_editable;
140 	iface->get_editable = gdaui_entry_wrapper_get_editable;
141 	iface->grab_focus = gdaui_entry_wrapper_grab_focus;
142 	iface->set_unknown_color = gdaui_entry_wrapper_set_unknown_color;
143 }
144 
145 
146 static void
gdaui_entry_wrapper_class_init(GdauiEntryWrapperClass * klass)147 gdaui_entry_wrapper_class_init (GdauiEntryWrapperClass *klass)
148 {
149 	GObjectClass   *object_class = G_OBJECT_CLASS (klass);
150 
151 	parent_class = g_type_class_peek_parent (klass);
152 
153 	/* virtual functions */
154 	klass->create_entry = NULL;
155 	klass->real_set_value = NULL;
156 	klass->real_get_value = NULL;
157 
158 	/* Properties */
159         object_class->set_property = gdaui_entry_wrapper_set_property;
160         object_class->get_property = gdaui_entry_wrapper_get_property;
161         g_object_class_install_property (object_class, PROP_SET_DEFAULT_IF_INVALID,
162 					 g_param_spec_boolean ("set-default-if-invalid", NULL, NULL, FALSE,
163                                                                (G_PARAM_READABLE | G_PARAM_WRITABLE)));
164 
165 	object_class->dispose = gdaui_entry_wrapper_dispose;
166 }
167 
168 static void
check_correct_init(GdauiEntryWrapper * wrapper)169 check_correct_init (GdauiEntryWrapper *wrapper)
170 {
171 	if (!wrapper->priv->impl_is_correct) {
172 		GtkWidget *entry = NULL;
173 		GdauiEntryWrapperClass *klass;
174 		gboolean class_impl_error = FALSE;;
175 
176 		klass = GDAUI_ENTRY_WRAPPER_CLASS (G_OBJECT_GET_CLASS (wrapper));
177 		if (! klass->create_entry) {
178 			g_warning ("create_entry () virtual function not implemented for object class %s\n",
179 				   G_OBJECT_TYPE_NAME (wrapper));
180 			class_impl_error = TRUE;
181 		}
182 		if (! klass->real_set_value) {
183 			g_warning ("real_set_value () virtual function not implemented for object class %s\n",
184 				   G_OBJECT_TYPE_NAME (wrapper));
185 			class_impl_error = TRUE;
186 		}
187 		if (! klass->real_get_value) {
188 			g_warning ("real_get_value () virtual function not implemented for object class %s\n",
189 				   G_OBJECT_TYPE_NAME (wrapper));
190 			class_impl_error = TRUE;
191 		}
192 		if (! klass->connect_signals) {
193 			g_warning ("connect_signals () virtual function not implemented for object class %s\n",
194 				   G_OBJECT_TYPE_NAME (wrapper));
195 			class_impl_error = TRUE;
196 		}
197 
198 		if (!class_impl_error) {
199 			wrapper->priv->real_class = klass;
200 			wrapper->priv->impl_is_correct = TRUE;
201 			entry = (*wrapper->priv->real_class->create_entry) (wrapper);
202 
203 			gdaui_entry_shell_pack_entry (GDAUI_ENTRY_SHELL (wrapper), entry);
204 			gtk_widget_show (entry);
205 			wrapper->priv->entry = entry;
206 
207 			(*wrapper->priv->real_class->connect_signals) (wrapper, G_CALLBACK (contents_changed_cb),
208 								      G_CALLBACK (contents_activated_cb));
209 		}
210 		else {
211 			/* we need to exit because the program WILL BE unstable and WILL crash */
212 			g_assert_not_reached ();
213 		}
214 	}
215 }
216 
217 static void
block_signals(GdauiEntryWrapper * wrapper)218 block_signals (GdauiEntryWrapper *wrapper)
219 {
220 	wrapper->priv->signals_blocked ++;
221 }
222 
223 static void
unblock_signals(GdauiEntryWrapper * wrapper)224 unblock_signals (GdauiEntryWrapper *wrapper)
225 {
226 	wrapper->priv->signals_blocked --;
227 }
228 
229 
230 static void
gdaui_entry_wrapper_init(GdauiEntryWrapper * wrapper)231 gdaui_entry_wrapper_init (GdauiEntryWrapper *wrapper)
232 {
233 	/* Private structure */
234 	wrapper->priv = g_new0 (GdauiEntryWrapperPriv, 1);
235 	wrapper->priv->impl_is_correct = FALSE;
236 	wrapper->priv->entry = NULL;
237 	wrapper->priv->real_class = NULL;
238 	wrapper->priv->signals_blocked = 0;
239 
240 	wrapper->priv->type = GDA_TYPE_NULL;
241 	wrapper->priv->value_ref = NULL;
242 	wrapper->priv->value_default = NULL;
243 
244 	wrapper->priv->null_forced = FALSE;
245 	wrapper->priv->default_forced = FALSE;
246 
247 	wrapper->priv->null_possible = TRUE;
248 	wrapper->priv->default_possible = FALSE;
249 	wrapper->priv->show_actions = TRUE;
250 	wrapper->priv->editable = TRUE;
251 	wrapper->priv->contents_has_changed = FALSE;
252 
253 	wrapper->priv->set_default_if_invalid = FALSE;
254 
255 	gtk_widget_set_hexpand (GTK_WIDGET (wrapper), TRUE);
256 }
257 
258 static void
gdaui_entry_wrapper_dispose(GObject * object)259 gdaui_entry_wrapper_dispose (GObject *object)
260 {
261 	GdauiEntryWrapper *wrapper;
262 
263 	g_return_if_fail (object != NULL);
264 	g_return_if_fail (GDAUI_IS_ENTRY_WRAPPER (object));
265 
266 	wrapper = GDAUI_ENTRY_WRAPPER (object);
267 
268 	if (wrapper->priv) {
269 		if (wrapper->priv->value_ref)
270 			gda_value_free (wrapper->priv->value_ref);
271 		if (wrapper->priv->value_default)
272 			gda_value_free (wrapper->priv->value_default);
273 
274 		g_free (wrapper->priv);
275 		wrapper->priv = NULL;
276 	}
277 
278 	/* for the parent class */
279 	parent_class->dispose (object);
280 }
281 
282 
283 static void
gdaui_entry_wrapper_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)284 gdaui_entry_wrapper_set_property (GObject *object,
285 				  guint param_id,
286 				  const GValue *value,
287 				  GParamSpec *pspec)
288 {
289 	GdauiEntryWrapper *wrapper = GDAUI_ENTRY_WRAPPER (object);
290 	if (wrapper->priv) {
291 		switch (param_id) {
292 		case PROP_SET_DEFAULT_IF_INVALID: {
293 			guint attrs;
294 
295 			wrapper->priv->set_default_if_invalid = g_value_get_boolean (value);
296 			attrs = gdaui_data_entry_get_attributes (GDAUI_DATA_ENTRY (wrapper));
297 
298 			if (wrapper->priv->set_default_if_invalid && (attrs & GDA_VALUE_ATTR_DATA_NON_VALID)) {
299 				GValue *sane_value;
300 				GdaDataHandler *dh;
301 				GType type;
302 
303 				check_correct_init (wrapper);
304 				dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (wrapper));
305 				type = gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (wrapper));
306 				sane_value = gda_data_handler_get_sane_init_value (dh, type);
307 				(*wrapper->priv->real_class->real_set_value) (wrapper, sane_value);
308 				if (sane_value)
309 					gda_value_free (sane_value);
310 			}
311 			break;
312 		default:
313 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
314 			break;
315 		}
316 		}
317 	}
318 }
319 
320 static void
gdaui_entry_wrapper_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)321 gdaui_entry_wrapper_get_property (GObject *object,
322 				  guint param_id,
323 				  GValue *value,
324 				  GParamSpec *pspec)
325 {
326 	GdauiEntryWrapper *wrapper = GDAUI_ENTRY_WRAPPER (object);
327 	if (wrapper->priv) {
328 		switch (param_id) {
329 		case PROP_SET_DEFAULT_IF_INVALID:
330 			g_value_set_boolean (value, wrapper->priv->set_default_if_invalid);
331 			break;
332 		default:
333 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
334 			break;
335 		}
336 	}
337 }
338 
339 /**
340  * gdaui_entry_wrapper_contents_changed:
341  * @wrapper: a #GdauiEntryWrapper widget
342  *
343  * Signals to @gwrap that the entry has changed
344  */
345 void
gdaui_entry_wrapper_contents_changed(GdauiEntryWrapper * wrapper)346 gdaui_entry_wrapper_contents_changed (GdauiEntryWrapper *wrapper)
347 {
348 	g_return_if_fail (GDAUI_IS_ENTRY_WRAPPER (wrapper));
349 
350 	contents_changed_cb (NULL, wrapper);
351 }
352 
353 /**
354  * gdaui_entry_wrapper_contents_activated:
355  * @wrapper: a #GdauiEntryWrapper widget
356  *
357  * Signals to @gwrap that the entry has been activated (that is the user
358  * pressed ENTER for example to signify he has finished entering data)
359  */
360 void
gdaui_entry_wrapper_contents_activated(GdauiEntryWrapper * wrapper)361 gdaui_entry_wrapper_contents_activated (GdauiEntryWrapper *wrapper)
362 {
363 	g_return_if_fail (GDAUI_IS_ENTRY_WRAPPER (wrapper));
364 
365 	contents_activated_cb (NULL, wrapper);
366 }
367 
368 
369 static void gdaui_entry_wrapper_emit_signal (GdauiEntryWrapper *wrapper);
370 static void
contents_changed_cb(G_GNUC_UNUSED GtkWidget * entry,GdauiEntryWrapper * wrapper)371 contents_changed_cb (G_GNUC_UNUSED GtkWidget *entry, GdauiEntryWrapper *wrapper)
372 {
373 	/* @entry is not used */
374 	if (! wrapper->priv->signals_blocked) {
375 		wrapper->priv->null_forced = FALSE;
376 		wrapper->priv->default_forced = FALSE;
377 		wrapper->priv->contents_has_changed = TRUE;
378 		gdaui_entry_wrapper_emit_signal (wrapper);
379 	}
380 }
381 
382 static void
contents_activated_cb(G_GNUC_UNUSED GtkWidget * entry,GdauiEntryWrapper * wrapper)383 contents_activated_cb (G_GNUC_UNUSED GtkWidget *entry, GdauiEntryWrapper *wrapper)
384 {
385 	/* @entry is not used */
386 	if (! wrapper->priv->signals_blocked) {
387 		wrapper->priv->null_forced = FALSE;
388 		wrapper->priv->default_forced = FALSE;
389 #ifdef debug_signal
390 		g_print (">> 'CONTENTS_ACTIVATED' from %s\n", __FUNCTION__);
391 #endif
392 		g_signal_emit_by_name (G_OBJECT (wrapper), "contents-activated");
393 #ifdef debug_signal
394 		g_print ("<< 'CONTENTS_ACTIVATED' from %s\n", __FUNCTION__);
395 #endif
396 	}
397 }
398 
399 static void
gdaui_entry_wrapper_emit_signal(GdauiEntryWrapper * wrapper)400 gdaui_entry_wrapper_emit_signal (GdauiEntryWrapper *wrapper)
401 {
402 	if (! wrapper->priv->signals_blocked) {
403 #ifdef debug_signal
404 		g_print (">> 'CONTENTS_MODIFIED' from %s\n", __FUNCTION__);
405 #endif
406 		g_signal_emit_by_name (G_OBJECT (wrapper), "contents-modified");
407 #ifdef debug_signal
408 		g_print ("<< 'CONTENTS_MODIFIED' from %s\n", __FUNCTION__);
409 #endif
410 	}
411 }
412 
413 
414 
415 /* Interface implementation */
416 static void
gdaui_entry_wrapper_set_value_type(GdauiDataEntry * iface,GType type)417 gdaui_entry_wrapper_set_value_type (GdauiDataEntry *iface, GType type)
418 {
419 	GdauiEntryWrapper *wrapper;
420 
421 	g_return_if_fail (GDAUI_IS_ENTRY_WRAPPER (iface));
422 	wrapper = (GdauiEntryWrapper*) iface;
423 
424 	if (wrapper->priv->type != type) {
425 		GValue *value;
426 
427 		if (wrapper->priv->value_ref) {
428 			gda_value_free (wrapper->priv->value_ref);
429 			wrapper->priv->value_ref = NULL;
430 		}
431 		if (wrapper->priv->value_default) {
432 			gda_value_free (wrapper->priv->value_default);
433 			wrapper->priv->value_default = NULL;
434 		}
435 
436 		wrapper->priv->type = type;
437 		wrapper->priv->value_default = gda_value_new_null ();
438 
439 		/* Set original value */
440 		value = gda_value_new_null ();
441 		gdaui_entry_wrapper_set_ref_value (GDAUI_DATA_ENTRY (wrapper), value);
442  		gda_value_free (value);
443 	}
444 }
445 
446 static GType
gdaui_entry_wrapper_get_value_type(GdauiDataEntry * iface)447 gdaui_entry_wrapper_get_value_type (GdauiDataEntry *iface)
448 {
449 	GdauiEntryWrapper *wrapper;
450 
451 	g_return_val_if_fail (GDAUI_IS_ENTRY_WRAPPER (iface), G_TYPE_INVALID);
452 	wrapper = (GdauiEntryWrapper*) iface;
453 
454 	return wrapper->priv->type;
455 }
456 
457 
458 static void
gdaui_entry_wrapper_set_value(GdauiDataEntry * iface,const GValue * value)459 gdaui_entry_wrapper_set_value (GdauiDataEntry *iface, const GValue *value)
460 {
461 	GdauiEntryWrapper *wrapper;
462 
463 	g_return_if_fail (GDAUI_IS_ENTRY_WRAPPER (iface));
464 	wrapper = (GdauiEntryWrapper*) iface;
465 	check_correct_init (wrapper);
466 
467 	block_signals (wrapper);
468 	if (value) {
469 		g_return_if_fail ((G_VALUE_TYPE ((GValue *) value) == wrapper->priv->type) ||
470 				  (G_VALUE_TYPE ((GValue *) value) == GDA_TYPE_NULL));
471 		(*wrapper->priv->real_class->real_set_value) (wrapper, value);
472 		if (G_VALUE_TYPE ((GValue *) value) == GDA_TYPE_NULL)
473 			wrapper->priv->null_forced = TRUE;
474 		else
475 			wrapper->priv->null_forced = FALSE;
476 	}
477 	else {
478 		(*wrapper->priv->real_class->real_set_value) (wrapper, NULL);
479 		wrapper->priv->null_forced = TRUE;
480 	}
481 	unblock_signals (wrapper);
482 	wrapper->priv->default_forced = FALSE;
483 	wrapper->priv->contents_has_changed = FALSE;
484 
485 	gdaui_entry_wrapper_emit_signal (wrapper);
486 }
487 
488 static GValue *
gdaui_entry_wrapper_get_value(GdauiDataEntry * iface)489 gdaui_entry_wrapper_get_value (GdauiDataEntry *iface)
490 {
491 	GValue *value = NULL;
492 	GdauiEntryWrapper *wrapper;
493 
494 	g_return_val_if_fail (GDAUI_IS_ENTRY_WRAPPER (iface), NULL);
495 	wrapper = (GdauiEntryWrapper*) iface;
496 
497 	if (wrapper->priv->null_forced)
498 		value = gda_value_new_null ();
499 	else {
500 		if (wrapper->priv->default_forced) {
501 			if (G_VALUE_TYPE (wrapper->priv->value_default) == wrapper->priv->type)
502 				value = gda_value_copy (wrapper->priv->value_default);
503 			else
504 				value = gda_value_new_null ();
505 		}
506 		else {
507 			check_correct_init (wrapper);
508 			value = (wrapper->priv->real_class->real_get_value) (wrapper);
509 		}
510 	}
511 
512 	return value;
513 }
514 
515 static void
gdaui_entry_wrapper_set_ref_value(GdauiDataEntry * iface,const GValue * value)516 gdaui_entry_wrapper_set_ref_value (GdauiDataEntry *iface, const GValue *value)
517 {
518 	GdauiEntryWrapper *wrapper;
519 	gboolean changed = TRUE;
520 	GValue *evalue;
521 
522 	g_return_if_fail (GDAUI_IS_ENTRY_WRAPPER (iface));
523 	wrapper = (GdauiEntryWrapper*) iface;
524 	check_correct_init (wrapper);
525 
526 	/* compare existing value and the one provided as argument */
527 	if (wrapper->priv->real_class->value_is_equal_to)
528 		changed = ! wrapper->priv->real_class->value_is_equal_to (wrapper, value);
529 	else {
530 		evalue = gdaui_entry_wrapper_get_value (iface);
531 		if ((!value || (G_VALUE_TYPE (value) == GDA_TYPE_NULL)) &&
532 		    (!evalue || (G_VALUE_TYPE (evalue) == GDA_TYPE_NULL)))
533 			changed = FALSE;
534 		else if (!gda_value_differ ((GValue *) value, evalue))
535 			changed = FALSE;
536 		if (evalue)
537 			gda_value_free (evalue);
538 	}
539 
540 	/* get rid on any existing orig value */
541 	if (wrapper->priv->value_ref) {
542 		gda_value_free (wrapper->priv->value_ref);
543 		wrapper->priv->value_ref = NULL;
544 	}
545 
546 	/* apply changes, if any */
547 	if (changed) {
548 		block_signals (wrapper);
549 		gdaui_entry_wrapper_set_value (iface, value);
550 		unblock_signals (wrapper);
551 	}
552 
553 	if (value) {
554 		g_return_if_fail ((G_VALUE_TYPE ((GValue *) value) == wrapper->priv->type) ||
555 				  (G_VALUE_TYPE ((GValue *) value) == GDA_TYPE_NULL));
556 		wrapper->priv->value_ref = gda_value_copy ((GValue *) value);
557 	}
558 	else
559 		wrapper->priv->value_ref = gda_value_new_null ();
560 
561 	/* signal changes if any */
562 	if (changed)
563 		gdaui_entry_wrapper_emit_signal (wrapper);
564 }
565 
566 static const GValue *
gdaui_entry_wrapper_get_ref_value(GdauiDataEntry * iface)567 gdaui_entry_wrapper_get_ref_value (GdauiDataEntry *iface)
568 {
569 	g_return_val_if_fail (GDAUI_IS_ENTRY_WRAPPER (iface), NULL);
570 	g_return_val_if_fail (GDAUI_ENTRY_WRAPPER (iface)->priv, NULL);
571 
572 	return GDAUI_ENTRY_WRAPPER (iface)->priv->value_ref;
573 }
574 
575 static void
gdaui_entry_wrapper_set_value_default(GdauiDataEntry * iface,const GValue * value)576 gdaui_entry_wrapper_set_value_default (GdauiDataEntry *iface, const GValue *value)
577 {
578 	GdauiEntryWrapper *wrapper;
579 
580 	g_return_if_fail (GDAUI_IS_ENTRY_WRAPPER (iface));
581 	wrapper = (GdauiEntryWrapper*) iface;
582 
583 	if (wrapper->priv->value_default)
584 		gda_value_free (wrapper->priv->value_default);
585 
586 	if (value)
587 		wrapper->priv->value_default = gda_value_copy ((GValue *) value);
588 	else
589 		wrapper->priv->value_default = gda_value_new_null ();
590 
591 	if (wrapper->priv->default_forced) {
592 		if (G_VALUE_TYPE (wrapper->priv->value_default) == wrapper->priv->type) {
593 			check_correct_init (wrapper);
594 			block_signals (wrapper);
595 			gdaui_entry_wrapper_set_value (iface, wrapper->priv->value_default);
596 			unblock_signals (wrapper);
597 			wrapper->priv->default_forced = TRUE;
598 			gdaui_entry_wrapper_emit_signal (wrapper);
599 		}
600 		else {
601 			check_correct_init (wrapper);
602 			(*wrapper->priv->real_class->real_set_value) (wrapper, NULL);
603 			gdaui_entry_wrapper_emit_signal (wrapper);
604 		}
605 	}
606 }
607 
608 static void
gdaui_entry_wrapper_set_attributes(GdauiDataEntry * iface,GdaValueAttribute attrs,guint mask)609 gdaui_entry_wrapper_set_attributes (GdauiDataEntry *iface, GdaValueAttribute attrs, guint mask)
610 {
611 	GdauiEntryWrapper *wrapper;
612 	gboolean signal_contents_changed = FALSE;
613 
614 	g_return_if_fail (GDAUI_IS_ENTRY_WRAPPER (iface));
615 	wrapper = (GdauiEntryWrapper*) iface;
616 	check_correct_init (wrapper);
617 
618 	/* Setting to NULL */
619 	if (mask & GDA_VALUE_ATTR_IS_NULL) {
620 		if ((mask & GDA_VALUE_ATTR_CAN_BE_NULL) &&
621 		    !(attrs & GDA_VALUE_ATTR_CAN_BE_NULL))
622 			g_return_if_reached ();
623 		if (attrs & GDA_VALUE_ATTR_IS_NULL) {
624 			block_signals (wrapper);
625 			gdaui_entry_wrapper_set_value (iface, NULL);
626 			unblock_signals (wrapper);
627 			wrapper->priv->null_forced = TRUE;
628 
629 			/* if default is set, see if we can keep it that way */
630 			if (wrapper->priv->default_forced) {
631 				if (G_VALUE_TYPE (wrapper->priv->value_default) !=
632 				    GDA_TYPE_NULL) {
633 					wrapper->priv->default_forced = FALSE;
634 				}
635 			}
636 		}
637 		else
638 			wrapper->priv->null_forced = FALSE;
639 		signal_contents_changed = TRUE;
640 	}
641 
642 	/* Can be NULL ? */
643 	if (mask & GDA_VALUE_ATTR_CAN_BE_NULL)
644 		wrapper->priv->null_possible = (attrs & GDA_VALUE_ATTR_CAN_BE_NULL) ? TRUE : FALSE;
645 
646 	/* Setting to DEFAULT */
647 	guint current = gdaui_data_entry_get_attributes (iface);
648 	if (mask & GDA_VALUE_ATTR_IS_DEFAULT) {
649 		if (! (current & GDA_VALUE_ATTR_CAN_BE_DEFAULT))
650 			g_warning ("Data entry does not have a default value");
651 		if (attrs & GDA_VALUE_ATTR_IS_DEFAULT) {
652 			block_signals (wrapper);
653 			if (wrapper->priv->value_default) {
654 				if (G_VALUE_TYPE (wrapper->priv->value_default) == wrapper->priv->type)
655 					gdaui_entry_wrapper_set_value (iface, wrapper->priv->value_default);
656 				else
657 					(*wrapper->priv->real_class->real_set_value) (wrapper, NULL);
658 			}
659 			else
660 				gdaui_entry_wrapper_set_value (iface, NULL);
661 			unblock_signals (wrapper);
662 
663 			/* if NULL is set, see if we can keep it that way */
664 			if (wrapper->priv->null_forced) {
665 				if (G_VALUE_TYPE (wrapper->priv->value_default) !=
666 				    GDA_TYPE_NULL)
667 					wrapper->priv->null_forced = FALSE;
668 			}
669 
670 			wrapper->priv->default_forced = TRUE;
671 		}
672 		else
673 			wrapper->priv->default_forced = FALSE;
674 
675 		signal_contents_changed = TRUE;
676 	}
677 
678 	/* Can be DEFAULT ? */
679 	if (mask & GDA_VALUE_ATTR_CAN_BE_DEFAULT)
680 		wrapper->priv->default_possible = (attrs & GDA_VALUE_ATTR_CAN_BE_DEFAULT) ? TRUE : FALSE;
681 
682 	/* Modified ? */
683 	if (mask & GDA_VALUE_ATTR_IS_UNCHANGED) {
684 		if (attrs & GDA_VALUE_ATTR_IS_UNCHANGED) {
685 			wrapper->priv->default_forced = FALSE;
686 			block_signals (wrapper);
687 			gdaui_entry_wrapper_set_value (iface, wrapper->priv->value_ref);
688 			unblock_signals (wrapper);
689 			signal_contents_changed = TRUE;
690 		}
691 	}
692 
693 	/* Actions buttons ? */
694 	if (mask & GDA_VALUE_ATTR_ACTIONS_SHOWN) {
695 		GValue *gval;
696 		wrapper->priv->show_actions = (attrs & GDA_VALUE_ATTR_ACTIONS_SHOWN) ? TRUE : FALSE;
697 
698 		gval = g_new0 (GValue, 1);
699 		g_value_init (gval, G_TYPE_BOOLEAN);
700 		g_value_set_boolean (gval, wrapper->priv->show_actions);
701 		g_object_set_property (G_OBJECT (wrapper), "actions", gval);
702 		g_free (gval);
703 	}
704 
705 	/* NON WRITABLE attributes */
706 	if (mask & GDA_VALUE_ATTR_DATA_NON_VALID)
707 		g_warning ("Can't force a GdauiDataEntry to be invalid!");
708 
709 	if (mask & GDA_VALUE_ATTR_HAS_VALUE_ORIG)
710 		g_warning ("Having an original value is not a write attribute on GdauiDataEntry!");
711 
712 	current = gdaui_data_entry_get_attributes (iface);
713 
714 	if (signal_contents_changed) {
715 		wrapper->priv->contents_has_changed = FALSE;
716 		gdaui_entry_wrapper_emit_signal (wrapper);
717 	}
718 	g_signal_emit_by_name (G_OBJECT (wrapper), "status-changed");
719 }
720 
721 static GdaValueAttribute
gdaui_entry_wrapper_get_attributes(GdauiDataEntry * iface)722 gdaui_entry_wrapper_get_attributes (GdauiDataEntry *iface)
723 {
724 	GdaValueAttribute retval = 0;
725 	GdauiEntryWrapper *wrapper;
726 	GValue *value = NULL;
727 	gboolean has_current_value;
728 	gboolean value_is_null = FALSE;
729 
730 	g_return_val_if_fail (GDAUI_IS_ENTRY_WRAPPER (iface), 0);
731 	wrapper = (GdauiEntryWrapper*) iface;
732 
733 	check_correct_init (wrapper);
734 	if (!wrapper->priv->real_class->value_is_equal_to ||
735 	    !wrapper->priv->real_class->value_is_null) {
736 		value = gdaui_entry_wrapper_get_value (iface);
737 		has_current_value = TRUE;
738 	}
739 	else
740 		has_current_value = FALSE;
741 
742 	/* NULL? */
743 	if (has_current_value) {
744 		if ((value && (G_VALUE_TYPE (value) == GDA_TYPE_NULL)) || !value) {
745 			if (wrapper->priv->default_forced) {
746 				if (wrapper->priv->null_forced)
747 					value_is_null = TRUE;
748 			}
749 			else
750 				value_is_null = TRUE;
751 		}
752 	}
753 	else {
754 		if ((wrapper->priv->real_class->value_is_null) (wrapper))
755 			value_is_null = TRUE;
756 	}
757 	if (value_is_null)
758 		retval = retval | GDA_VALUE_ATTR_IS_NULL;
759 
760 	/* can be NULL? */
761 	if (wrapper->priv->null_possible)
762 		retval = retval | GDA_VALUE_ATTR_CAN_BE_NULL;
763 
764 	/* is default */
765 	if (wrapper->priv->default_forced)
766 		retval = retval | GDA_VALUE_ATTR_IS_DEFAULT;
767 
768 	/* can be default? */
769 	if (wrapper->priv->default_possible)
770 		retval = retval | GDA_VALUE_ATTR_CAN_BE_DEFAULT;
771 
772 	/* is unchanged */
773 	if (has_current_value) {
774 		if (wrapper->priv->value_ref &&
775 		    (G_VALUE_TYPE (value) == G_VALUE_TYPE (wrapper->priv->value_ref))) {
776 			if (gda_value_is_null (value))
777 				retval = retval | GDA_VALUE_ATTR_IS_UNCHANGED;
778 			else {
779 				if (! gda_value_differ (value, wrapper->priv->value_ref))
780 					retval = retval | GDA_VALUE_ATTR_IS_UNCHANGED;
781 			}
782 		}
783 	}
784 	else if ((wrapper->priv->real_class->value_is_equal_to) (wrapper, wrapper->priv->value_ref))
785 		retval = retval | GDA_VALUE_ATTR_IS_UNCHANGED;
786 
787 	/* actions shown */
788 	if (wrapper->priv->show_actions)
789 		retval = retval | GDA_VALUE_ATTR_ACTIONS_SHOWN;
790 
791 	/* data valid? */
792 	if (! (wrapper->priv->default_forced && wrapper->priv->default_possible)) {
793 		if (/*(value_is_null && !wrapper->priv->null_forced) ||*/
794 		    (value_is_null && !wrapper->priv->null_possible))
795 			retval = retval | GDA_VALUE_ATTR_DATA_NON_VALID;
796 	}
797 
798 	/* has original value? */
799 	if (wrapper->priv->value_ref)
800 		retval = retval | GDA_VALUE_ATTR_HAS_VALUE_ORIG;
801 
802 	if (has_current_value)
803 		gda_value_free (value);
804 
805 	if (!wrapper->priv->editable)
806 		retval = retval | GDA_VALUE_ATTR_NO_MODIF;
807 
808 	return retval;
809 }
810 
811 
812 static GdaDataHandler *
gdaui_entry_wrapper_get_handler(GdauiDataEntry * iface)813 gdaui_entry_wrapper_get_handler (GdauiDataEntry *iface)
814 {
815 	GdaDataHandler *dh;
816 
817 	g_return_val_if_fail (GDAUI_IS_ENTRY_WRAPPER (iface), NULL);
818 
819 	g_object_get (G_OBJECT (iface), "handler", &dh, NULL);
820 	if (dh) /* loose the reference before returning the object */
821 		g_object_unref (dh);
822 
823 	return dh;
824 }
825 
826 static void
gdaui_entry_wrapper_set_editable(GdauiDataEntry * iface,gboolean editable)827 gdaui_entry_wrapper_set_editable (GdauiDataEntry *iface, gboolean editable)
828 {
829 	GdauiEntryWrapper *wrapper;
830 
831 	g_return_if_fail (GDAUI_IS_ENTRY_WRAPPER (iface));
832 	wrapper = (GdauiEntryWrapper*) iface;
833 	check_correct_init (wrapper);
834 
835 	wrapper->priv->editable = editable;
836 	if (wrapper->priv->real_class->set_editable)
837 		(wrapper->priv->real_class->set_editable) (wrapper, editable);
838 	else
839 		gtk_widget_set_sensitive (GTK_WIDGET (iface), editable);
840 }
841 
842 static gboolean
gdaui_entry_wrapper_get_editable(GdauiDataEntry * iface)843 gdaui_entry_wrapper_get_editable (GdauiDataEntry *iface)
844 {
845 	GdauiEntryWrapper *wrapper;
846 
847 	g_return_val_if_fail (GDAUI_IS_ENTRY_WRAPPER (iface), FALSE);
848 	wrapper = (GdauiEntryWrapper*) iface;
849 
850 	return wrapper->priv->editable;
851 }
852 
853 static void
gdaui_entry_wrapper_grab_focus(GdauiDataEntry * iface)854 gdaui_entry_wrapper_grab_focus (GdauiDataEntry *iface)
855 {
856 	GdauiEntryWrapper *wrapper;
857 
858 	g_return_if_fail (GDAUI_IS_ENTRY_WRAPPER (iface));
859 	wrapper = (GdauiEntryWrapper*) iface;
860 	check_correct_init (wrapper);
861 
862 	if (wrapper->priv->real_class->grab_focus)
863 		(wrapper->priv->real_class->grab_focus) (wrapper);
864 	else if (wrapper->priv->entry) {
865 		gboolean canfocus;
866 		g_object_get ((GObject*) wrapper->priv->entry, "can-focus", &canfocus, NULL);
867 		if (canfocus)
868 			gtk_widget_grab_focus (wrapper->priv->entry);
869 	}
870 }
871 
872 static void
gdaui_entry_wrapper_set_unknown_color(GdauiDataEntry * de,gdouble red,gdouble green,gdouble blue,gdouble alpha)873 gdaui_entry_wrapper_set_unknown_color (GdauiDataEntry *de, gdouble red, gdouble green,
874 				       gdouble blue, gdouble alpha)
875 {
876 	gdaui_entry_shell_set_ucolor (GDAUI_ENTRY_SHELL (de), red, green, blue, alpha);
877 }
878