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 <glib/gi18n-lib.h>
23 #include "gdaui-entry-common-time.h"
24 #include <libgda/gda-data-handler.h>
25 #include <gdk/gdkkeysyms.h>
26 #include <string.h>
27 #include "gdaui-formatted-entry.h"
28 #include <libgda/gda-debug-macros.h>
29 
30 /*
31  * Main static functions
32  */
33 static void gdaui_entry_common_time_class_init (GdauiEntryCommonTimeClass * class);
34 static void gdaui_entry_common_time_init (GdauiEntryCommonTime * srv);
35 static void gdaui_entry_common_time_dispose (GObject *object);
36 static void gdaui_entry_common_time_finalize (GObject *object);
37 
38 static void gdaui_entry_common_time_set_property (GObject *object,
39 						  guint param_id,
40 						  const GValue *value,
41 						  GParamSpec *pspec);
42 static void gdaui_entry_common_time_get_property (GObject *object,
43 						  guint param_id,
44 						  GValue *value,
45 						  GParamSpec *pspec);
46 
47 /* properties */
48 enum
49 {
50 	PROP_0,
51 	PROP_EDITING_CANCELED,
52 	PROP_TYPE
53 };
54 
55 /* GtkCellEditable interface */
56 static void gdaui_entry_common_time_cell_editable_init (GtkCellEditableIface *iface);
57 static void gdaui_entry_common_time_start_editing (GtkCellEditable *iface, GdkEvent *event);
58 
59 /* virtual functions */
60 static GtkWidget *create_entry (GdauiEntryWrapper *mgwrap);
61 static void       real_set_value (GdauiEntryWrapper *mgwrap, const GValue *value);
62 static GValue    *real_get_value (GdauiEntryWrapper *mgwrap);
63 static void       connect_signals(GdauiEntryWrapper *mgwrap, GCallback modify_cb, GCallback activate_cb);
64 static void       set_editable (GdauiEntryWrapper *mgwrap, gboolean editable);
65 static void       grab_focus (GdauiEntryWrapper *mgwrap);
66 
67 /* get a pointer to the parents to be able to call their destructor */
68 static GObjectClass  *parent_class = NULL;
69 
70 
71 /* private structure */
72 struct _GdauiEntryCommonTimePrivate
73 {
74 	/* for date */
75 	GtkWidget *entry_date;
76 	GtkWidget *date;
77         GtkWidget *window;
78         GtkWidget *date_button;
79 	gboolean   editing_canceled;
80 
81 	/* for time */
82 	GtkWidget *entry_time;
83 
84 	/* for timestamp */
85 	GtkWidget *hbox;
86 
87 	/* Last value set */
88 	GValue    *last_value_set;
89 };
90 
91 static void
gdaui_entry_common_time_cell_editable_init(GtkCellEditableIface * iface)92 gdaui_entry_common_time_cell_editable_init (GtkCellEditableIface *iface)
93 {
94 	iface->start_editing = gdaui_entry_common_time_start_editing;
95 }
96 
97 GType
gdaui_entry_common_time_get_type(void)98 gdaui_entry_common_time_get_type (void)
99 {
100 	static GType type = 0;
101 
102 	if (G_UNLIKELY (type == 0)) {
103 		static const GTypeInfo info = {
104 			sizeof (GdauiEntryCommonTimeClass),
105 			(GBaseInitFunc) NULL,
106 			(GBaseFinalizeFunc) NULL,
107 			(GClassInitFunc) gdaui_entry_common_time_class_init,
108 			NULL,
109 			NULL,
110 			sizeof (GdauiEntryCommonTime),
111 			0,
112 			(GInstanceInitFunc) gdaui_entry_common_time_init,
113 			0
114 		};
115 
116 		static const GInterfaceInfo cell_editable_info = {
117 			(GInterfaceInitFunc) gdaui_entry_common_time_cell_editable_init,    /* interface_init */
118 			NULL,                                                 /* interface_finalize */
119 			NULL                                                  /* interface_data */
120 		};
121 
122 		type = g_type_register_static (GDAUI_TYPE_ENTRY_WRAPPER, "GdauiEntryCommonTime", &info, 0);
123 		g_type_add_interface_static (type, GTK_TYPE_CELL_EDITABLE, &cell_editable_info);
124 	}
125 	return type;
126 }
127 
128 static void
gdaui_entry_common_time_class_init(GdauiEntryCommonTimeClass * class)129 gdaui_entry_common_time_class_init (GdauiEntryCommonTimeClass * class)
130 {
131 	GObjectClass   *object_class = G_OBJECT_CLASS (class);
132 
133 	parent_class = g_type_class_peek_parent (class);
134 
135 	object_class->dispose = gdaui_entry_common_time_dispose;
136 	object_class->finalize = gdaui_entry_common_time_finalize;
137 
138 	GDAUI_ENTRY_WRAPPER_CLASS (class)->create_entry = create_entry;
139 	GDAUI_ENTRY_WRAPPER_CLASS (class)->real_set_value = real_set_value;
140 	GDAUI_ENTRY_WRAPPER_CLASS (class)->real_get_value = real_get_value;
141 	GDAUI_ENTRY_WRAPPER_CLASS (class)->connect_signals = connect_signals;
142 	GDAUI_ENTRY_WRAPPER_CLASS (class)->set_editable = set_editable;
143 	GDAUI_ENTRY_WRAPPER_CLASS (class)->grab_focus = grab_focus;
144 
145 	/* Properties */
146 	object_class->set_property = gdaui_entry_common_time_set_property;
147 	object_class->get_property = gdaui_entry_common_time_get_property;
148 
149 	g_object_class_install_property (object_class, PROP_EDITING_CANCELED,
150 					 g_param_spec_boolean ("editing-canceled", NULL, NULL, FALSE,
151 							       G_PARAM_READABLE | G_PARAM_WRITABLE));
152 	g_object_class_install_property (object_class, PROP_TYPE,
153 					 g_param_spec_uint ("type", NULL, NULL, 0, G_MAXUINT, GDA_TYPE_TIME,
154 							    G_PARAM_WRITABLE | G_PARAM_READABLE));
155 }
156 
157 static gboolean
key_press_event_cb(GdauiEntryCommonTime * mgtim,GdkEventKey * key_event,G_GNUC_UNUSED gpointer data)158 key_press_event_cb (GdauiEntryCommonTime *mgtim, GdkEventKey *key_event, G_GNUC_UNUSED gpointer data)
159 {
160 	if (key_event->keyval == GDK_KEY_Escape)
161 		mgtim->priv->editing_canceled = TRUE;
162 	return FALSE;
163 }
164 
165 static void
gdaui_entry_common_time_init(GdauiEntryCommonTime * gdaui_entry_common_time)166 gdaui_entry_common_time_init (GdauiEntryCommonTime *gdaui_entry_common_time)
167 {
168 	gdaui_entry_common_time->priv = g_new0 (GdauiEntryCommonTimePrivate, 1);
169 	gdaui_entry_common_time->priv->entry_date = NULL;
170 	gdaui_entry_common_time->priv->entry_time = NULL;
171 	gdaui_entry_common_time->priv->date = NULL;
172 	gdaui_entry_common_time->priv->window = NULL;
173 	gdaui_entry_common_time->priv->date_button = NULL;
174 	gdaui_entry_common_time->priv->hbox = NULL;
175 	gdaui_entry_common_time->priv->last_value_set = NULL;
176 	gdaui_entry_common_time->priv->editing_canceled = FALSE;
177 	g_signal_connect (gdaui_entry_common_time, "key-press-event",
178 			  G_CALLBACK (key_press_event_cb), NULL);
179 }
180 
181 /**
182  * gdaui_entry_common_time_new:
183  * @dh: the data handler to be used by the new widget
184  * @type: the requested data type (compatible with @dh)
185  *
186  * Creates a new data entry widget
187  *
188  * Returns: (transfer full): the new widget
189  */
190 GtkWidget *
gdaui_entry_common_time_new(GdaDataHandler * dh,GType type)191 gdaui_entry_common_time_new (GdaDataHandler *dh, GType type)
192 {
193 	GObject *obj;
194 	GdauiEntryCommonTime *mgtim;
195 
196 	g_return_val_if_fail (dh && GDA_IS_DATA_HANDLER (dh), NULL);
197 	g_return_val_if_fail (gda_data_handler_accepts_g_type (dh, type), NULL);
198 
199 	obj = g_object_new (GDAUI_TYPE_ENTRY_COMMON_TIME, "handler", dh, NULL);
200 	mgtim = GDAUI_ENTRY_COMMON_TIME (obj);
201 	gdaui_data_entry_set_value_type (GDAUI_DATA_ENTRY (mgtim), type);
202 
203 	return GTK_WIDGET (obj);
204 }
205 
206 
207 static void
gdaui_entry_common_time_dispose(GObject * object)208 gdaui_entry_common_time_dispose (GObject   * object)
209 {
210 	GdauiEntryCommonTime *gdaui_entry_common_time;
211 
212 	g_return_if_fail (object != NULL);
213 	g_return_if_fail (GDAUI_IS_ENTRY_COMMON_TIME (object));
214 
215 	gdaui_entry_common_time = GDAUI_ENTRY_COMMON_TIME (object);
216 	if (gdaui_entry_common_time->priv) {
217 		if (gdaui_entry_common_time->priv->window) {
218 			gtk_widget_destroy (gdaui_entry_common_time->priv->window);
219 			gdaui_entry_common_time->priv->window = NULL;
220 		}
221 	}
222 
223 	/* parent class */
224 	parent_class->dispose (object);
225 }
226 
227 static void
gdaui_entry_common_time_finalize(GObject * object)228 gdaui_entry_common_time_finalize (GObject   * object)
229 {
230 	GdauiEntryCommonTime *gdaui_entry_common_time;
231 
232 	g_return_if_fail (object != NULL);
233 	g_return_if_fail (GDAUI_IS_ENTRY_COMMON_TIME (object));
234 
235 	gdaui_entry_common_time = GDAUI_ENTRY_COMMON_TIME (object);
236 	if (gdaui_entry_common_time->priv) {
237 		if (gdaui_entry_common_time->priv->last_value_set)
238 			gda_value_free (gdaui_entry_common_time->priv->last_value_set);
239 
240 		g_free (gdaui_entry_common_time->priv);
241 		gdaui_entry_common_time->priv = NULL;
242 	}
243 
244 	/* parent class */
245 	parent_class->finalize (object);
246 }
247 
248 static void
gdaui_entry_common_time_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)249 gdaui_entry_common_time_set_property (GObject *object,
250 				      guint param_id,
251 				      const GValue *value,
252 				      GParamSpec *pspec)
253 {
254 	GdauiEntryCommonTime *mgtim;
255 
256 	mgtim = GDAUI_ENTRY_COMMON_TIME (object);
257 	if (mgtim->priv) {
258 		switch (param_id) {
259 		case PROP_TYPE:
260 			gdaui_data_entry_set_value_type (GDAUI_DATA_ENTRY (object), g_value_get_uint (value));
261 			break;
262 		case PROP_EDITING_CANCELED:
263 			TO_IMPLEMENT;
264 			break;
265 		default:
266 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
267 			break;
268 		}
269 	}
270 }
271 
272 static void
gdaui_entry_common_time_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)273 gdaui_entry_common_time_get_property (GObject *object,
274 				      guint param_id,
275 				      GValue *value,
276 				      GParamSpec *pspec)
277 {
278 	GdauiEntryCommonTime *mgtim;
279 
280 	mgtim = GDAUI_ENTRY_COMMON_TIME (object);
281 	if (mgtim->priv) {
282 		switch (param_id) {
283 		case PROP_EDITING_CANCELED:
284 			g_value_set_boolean (value, mgtim->priv->editing_canceled);
285 			break;
286 		case PROP_TYPE:
287 			g_value_set_uint (value, gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (object)));
288 			break;
289 		default:
290 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
291 			break;
292 		}
293 	}
294 }
295 
296 static GtkWidget *create_entry_date (GdauiEntryCommonTime *mgtim);
297 static GtkWidget *create_entry_time (GdauiEntryCommonTime *mgtim);
298 static GtkWidget *create_entry_ts (GdauiEntryCommonTime *mgtim);
299 static GtkWidget *
create_entry(GdauiEntryWrapper * mgwrap)300 create_entry (GdauiEntryWrapper *mgwrap)
301 {
302 	GdauiEntryCommonTime *mgtim;
303 	GtkWidget *entry = NULL;
304 	GType type;
305 
306 	g_return_val_if_fail (mgwrap && GDAUI_IS_ENTRY_COMMON_TIME (mgwrap), NULL);
307 	mgtim = GDAUI_ENTRY_COMMON_TIME (mgwrap);
308 	g_return_val_if_fail (mgtim->priv, NULL);
309 
310 	type = gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (mgtim));
311 	if (type == G_TYPE_DATE)
312 		entry = create_entry_date (mgtim);
313 	else if (type == GDA_TYPE_TIME)
314 		entry = create_entry_time (mgtim);
315 	else if (type == GDA_TYPE_TIMESTAMP)
316 		entry = create_entry_ts (mgtim);
317 	else
318 		g_assert_not_reached ();
319 
320 	return entry;
321 }
322 
323 static void
real_set_value(GdauiEntryWrapper * mgwrap,const GValue * value)324 real_set_value (GdauiEntryWrapper *mgwrap, const GValue *value)
325 {
326 	GdauiEntryCommonTime *mgtim;
327 	GType type;
328 	GdaDataHandler *dh;
329 
330 	g_return_if_fail (mgwrap && GDAUI_IS_ENTRY_COMMON_TIME (mgwrap));
331 	mgtim = GDAUI_ENTRY_COMMON_TIME (mgwrap);
332 	g_return_if_fail (mgtim->priv);
333 
334 	dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (mgwrap));
335 	type = gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (mgtim));
336 
337 	if (type == G_TYPE_DATE) {
338 		if (value) {
339 			if (gda_value_is_null ((GValue *) value))
340 				gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_date), NULL);
341 			else {
342 				gchar *str;
343 
344 				str = gda_data_handler_get_str_from_value (dh, value);
345 				gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_date), str);
346 				g_free (str);
347 			}
348 		}
349 		else
350 			gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_date), NULL);
351 	}
352 	else if (type == GDA_TYPE_TIME) {
353 		if (value) {
354 			if (gda_value_is_null ((GValue *) value))
355 				gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_time), NULL);
356 			else {
357 				gchar *str;
358 
359 				str = gda_data_handler_get_str_from_value (dh, value);
360 				gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_time), str);
361 				g_free (str);
362 			}
363 		}
364 		else
365 			gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_time), NULL);
366 	}
367 	else if (type == GDA_TYPE_TIMESTAMP) {
368 		if (value) {
369 			if (gda_value_is_null ((GValue *) value)) {
370 				gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_date), NULL);
371 				gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_time), NULL);
372 			}
373 			else {
374 				gchar *str, *ptr;
375 
376 				str = gda_data_handler_get_str_from_value (dh, value);
377 				ptr = strtok (str, " ");
378 				gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_date), ptr);
379 				ptr = strtok (NULL, " ");
380 				gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_time), ptr);
381 				g_free (str);
382 			}
383 		}
384 		else {
385 			gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_date), NULL);
386 			gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_time), NULL);
387 		}
388 	}
389 	else
390 		g_assert_not_reached ();
391 
392 	/* keep track of the last value set */
393 	if (mgtim->priv->last_value_set) {
394 		gda_value_free (mgtim->priv->last_value_set);
395 		mgtim->priv->last_value_set = NULL;
396 	}
397 	if (value)
398 		mgtim->priv->last_value_set = gda_value_copy ((GValue *) value);
399 }
400 
401 static GValue *
real_get_value(GdauiEntryWrapper * mgwrap)402 real_get_value (GdauiEntryWrapper *mgwrap)
403 {
404 	GValue *value = NULL;
405 	GdauiEntryCommonTime *mgtim;
406 	GdaDataHandler *dh;
407 	gchar *str2;
408 	GType type;
409 
410 	g_return_val_if_fail (mgwrap && GDAUI_IS_ENTRY_COMMON_TIME (mgwrap), NULL);
411 	mgtim = GDAUI_ENTRY_COMMON_TIME (mgwrap);
412 	g_return_val_if_fail (mgtim->priv, NULL);
413 
414 	type = gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (mgtim));
415 	dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (mgwrap));
416 
417 	if (type == G_TYPE_DATE) {
418 		str2 = gdaui_formatted_entry_get_text (GDAUI_FORMATTED_ENTRY (mgtim->priv->entry_date));
419 		if (str2) {
420 			value = gda_data_handler_get_value_from_str (dh, str2, type);
421 			g_free (str2);
422 		}
423 	}
424 	else if (type == GDA_TYPE_TIME) {
425 		str2 = gdaui_formatted_entry_get_text (GDAUI_FORMATTED_ENTRY (mgtim->priv->entry_time));
426 		if (str2) {
427 			value = gda_data_handler_get_value_from_str (dh, str2, type);
428 			g_free (str2);
429 		}
430 
431 		if (value && (G_VALUE_TYPE (value) != GDA_TYPE_NULL) &&
432 		    mgtim->priv->last_value_set &&
433 		    gda_value_isa (mgtim->priv->last_value_set, GDA_TYPE_TIME)) {
434 			/* copy the 'timezone' part, we we have not modified */
435 			const GdaTime *dgatime_set = gda_value_get_time (mgtim->priv->last_value_set);
436 			GdaTime *gdatime = g_new (GdaTime, 1);
437 			*gdatime = *(gda_value_get_time (value));
438 			gdatime->timezone = dgatime_set->timezone;
439 			gda_value_set_time (value, gdatime);
440 			g_free (gdatime);
441 		}
442 	}
443 	else if (type == GDA_TYPE_TIMESTAMP) {
444 		gchar *tmpstr, *tmpstr2;
445 
446 		tmpstr = gdaui_formatted_entry_get_text (GDAUI_FORMATTED_ENTRY (mgtim->priv->entry_time));
447 		tmpstr2 = gdaui_formatted_entry_get_text (GDAUI_FORMATTED_ENTRY (mgtim->priv->entry_date));
448 		if (tmpstr && tmpstr2) {
449 			str2 = g_strdup_printf ("%s %s", tmpstr2, tmpstr);
450 			value = gda_data_handler_get_value_from_str (dh, str2, type);
451 			g_free (str2);
452 		}
453 		g_free (tmpstr);
454 		g_free (tmpstr2);
455 		if (value && (G_VALUE_TYPE (value) != GDA_TYPE_NULL) &&
456 		    mgtim->priv->last_value_set &&
457 		    gda_value_isa (mgtim->priv->last_value_set, GDA_TYPE_TIMESTAMP)) {
458 			/* copy the 'fraction' and 'timezone' parts, we have not modified */
459 			const GdaTimestamp *dgatime_set = gda_value_get_timestamp (mgtim->priv->last_value_set);
460 			GdaTimestamp *gdatime = g_new (GdaTimestamp, 1);
461 			*gdatime = *(gda_value_get_timestamp (value));
462 			gdatime->fraction = dgatime_set->fraction;
463 			gdatime->timezone = dgatime_set->timezone;
464 			gda_value_set_timestamp (value, gdatime);
465 			g_free (gdatime);
466 		}
467 	}
468 	else
469 		g_assert_not_reached ();
470 
471 	if (!value) {
472 		/* in case the gda_data_handler_get_value_from_str() returned an error because
473 		   the contents of the GtkEntry cannot be interpreted as a GValue */
474 		value = gda_value_new_null ();
475 	}
476 
477 	return value;
478 }
479 
480 static void
connect_signals(GdauiEntryWrapper * mgwrap,GCallback modify_cb,GCallback activate_cb)481 connect_signals (GdauiEntryWrapper *mgwrap, GCallback modify_cb, GCallback activate_cb)
482 {
483 	GdauiEntryCommonTime *mgtim;
484 	GType type;
485 
486 	g_return_if_fail (mgwrap && GDAUI_IS_ENTRY_COMMON_TIME (mgwrap));
487 	mgtim = GDAUI_ENTRY_COMMON_TIME (mgwrap);
488 	g_return_if_fail (mgtim->priv);
489 
490 	type = gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (mgtim));
491 
492 	if ((type == G_TYPE_DATE) || (type == GDA_TYPE_TIMESTAMP)) {
493 		g_signal_connect (G_OBJECT (mgtim->priv->entry_date), "changed",
494 				  modify_cb, mgwrap);
495 		g_signal_connect (G_OBJECT (mgtim->priv->entry_date), "activate",
496 				  activate_cb, mgwrap);
497 	}
498 
499 	if ((type == GDA_TYPE_TIME) || (type == GDA_TYPE_TIMESTAMP)) {
500 		g_signal_connect (G_OBJECT (mgtim->priv->entry_time), "changed",
501 				  modify_cb, mgwrap);
502 		g_signal_connect (G_OBJECT (mgtim->priv->entry_time), "activate",
503 				  activate_cb, mgwrap);
504 	}
505 }
506 
507 static void
set_editable(GdauiEntryWrapper * mgwrap,gboolean editable)508 set_editable (GdauiEntryWrapper *mgwrap, gboolean editable)
509 {
510 	GdauiEntryCommonTime *mgtim;
511 
512 	g_return_if_fail (mgwrap && GDAUI_IS_ENTRY_COMMON_TIME (mgwrap));
513 	mgtim = GDAUI_ENTRY_COMMON_TIME (mgwrap);
514 	g_return_if_fail (mgtim->priv);
515 
516 	if (mgtim->priv->entry_date)
517 		gtk_editable_set_editable (GTK_EDITABLE (mgtim->priv->entry_date), editable);
518 	if (mgtim->priv->entry_time)
519 		gtk_editable_set_editable (GTK_EDITABLE (mgtim->priv->entry_time), editable);
520 	if (mgtim->priv->date_button)
521 		gtk_widget_set_sensitive (mgtim->priv->date_button, editable);
522 }
523 
524 static void
grab_focus(GdauiEntryWrapper * mgwrap)525 grab_focus (GdauiEntryWrapper *mgwrap)
526 {
527 	GdauiEntryCommonTime *mgtim;
528 
529 	g_return_if_fail (mgwrap && GDAUI_IS_ENTRY_COMMON_TIME (mgwrap));
530 	mgtim = GDAUI_ENTRY_COMMON_TIME (mgwrap);
531 	g_return_if_fail (mgtim->priv);
532 
533 	if (mgtim->priv->entry_date)
534 		gtk_widget_grab_focus (mgtim->priv->entry_date);
535 	if (mgtim->priv->entry_time)
536 		gtk_widget_grab_focus (mgtim->priv->entry_time);
537 }
538 
539 
540 
541 /*
542  * callbacks for the date
543  */
544 static gint date_delete_popup (GtkWidget *widget, GdauiEntryCommonTime *mgtim);
545 static gint date_key_press_popup (GtkWidget *widget, GdkEventKey *event, GdauiEntryCommonTime *mgtim);
546 static gint date_button_press_popup (GtkWidget *widget, GdkEventButton *event, GdauiEntryCommonTime *mgtim);
547 static void date_day_selected (GtkCalendar *calendar, GdauiEntryCommonTime *mgtim);
548 static void date_day_selected_double_click (GtkCalendar *calendar, GdauiEntryCommonTime *mgtim);
549 static void date_calendar_choose_cb (GtkWidget *button, GdauiEntryCommonTime *mgtim);
550 
551 static void entry_date_insert_func (GdauiFormattedEntry *fentry, gunichar insert_char, gint virt_pos, gpointer data);
552 
553 static GtkWidget *
create_entry_date(GdauiEntryCommonTime * mgtim)554 create_entry_date (GdauiEntryCommonTime *mgtim)
555 {
556 	GtkWidget *wid, *hb, *window, *arrow;
557 	GdaDataHandler *dh;
558 
559 	/* top widget */
560 	hb = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
561 
562 	/* text entry */
563 	dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (mgtim));
564 	if (GDA_IS_HANDLER_TIME (dh)) {
565 		gchar *str, *mask, *ptr;
566 		str = gda_handler_time_get_format (GDA_HANDLER_TIME (dh), G_TYPE_DATE);
567 		mask = g_strdup (str);
568 		for (ptr = mask; *ptr; ptr++) {
569 			if (*ptr == '0')
570 				*ptr = '-';
571 		}
572 		wid = gdaui_formatted_entry_new (str, mask);
573 		g_free (str);
574 		g_free (mask);
575 
576 		gdaui_formatted_entry_set_insert_func (GDAUI_FORMATTED_ENTRY (wid), entry_date_insert_func,
577 						       mgtim);
578 	}
579 	else
580 		wid = gdaui_entry_new (NULL, NULL);
581 	gtk_box_pack_start (GTK_BOX (hb), wid, FALSE, FALSE, 0);
582 	gtk_widget_show (wid);
583 	mgtim->priv->entry_date = wid;
584 
585 	/* window to hold the calendar popup */
586 	window = gtk_window_new (GTK_WINDOW_POPUP);
587 	gtk_widget_set_events (window, gtk_widget_get_events (window) | GDK_KEY_PRESS_MASK);
588 	gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
589 	g_signal_connect (G_OBJECT (window), "delete-event",
590 			  G_CALLBACK (date_delete_popup), mgtim);
591 	g_signal_connect (G_OBJECT (window), "key-press-event",
592 			  G_CALLBACK (date_key_press_popup), mgtim);
593 	g_signal_connect (G_OBJECT (window), "button-press-event",
594 			  G_CALLBACK (date_button_press_popup), mgtim);
595 	mgtim->priv->window = window;
596 
597 	/* calendar */
598 	wid = gtk_calendar_new ();
599 	mgtim->priv->date = wid;
600 	gtk_container_add (GTK_CONTAINER (window), wid);
601 	gtk_widget_show (wid);
602 	g_signal_connect (G_OBJECT (wid), "day-selected",
603 			  G_CALLBACK (date_day_selected), mgtim);
604 	g_signal_connect (G_OBJECT (wid), "day-selected-double-click",
605 			  G_CALLBACK (date_day_selected_double_click), mgtim);
606 
607 	/* button to pop up the calendar */
608 	wid = gtk_button_new ();
609 	arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
610 	gtk_container_add (GTK_CONTAINER (wid), arrow);
611 	gtk_box_pack_start (GTK_BOX (hb), wid, FALSE, FALSE, 0);
612 	gtk_widget_show_all (wid);
613 	g_signal_connect (G_OBJECT (wid), "clicked",
614 			  G_CALLBACK (date_calendar_choose_cb), mgtim);
615 	mgtim->priv->date_button = wid;
616 
617 	/* padding */
618 	wid = gtk_label_new ("");
619 	gtk_box_pack_start (GTK_BOX (hb), wid, TRUE, TRUE, 0);
620 	gtk_widget_show (wid);
621 
622 	return hb;
623 }
624 
625 static void
entry_date_insert_func(G_GNUC_UNUSED GdauiFormattedEntry * fentry,gunichar insert_char,G_GNUC_UNUSED gint virt_pos,gpointer data)626 entry_date_insert_func (G_GNUC_UNUSED GdauiFormattedEntry *fentry, gunichar insert_char,
627 			G_GNUC_UNUSED gint virt_pos, gpointer data)
628 {
629 	GValue *value;
630 	GType type;
631 
632 	type = gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (data));
633 	value = real_get_value (GDAUI_ENTRY_WRAPPER (data));
634 	if (!value)
635 		return;
636 
637 	if (G_VALUE_TYPE (value) == GDA_TYPE_NULL) {
638 		if (type == G_TYPE_DATE) {
639 			/* set current date, whatever @insert_char is */
640 			GDate *ndate;
641 			ndate = g_new0 (GDate, 1);
642 			g_date_set_time_t (ndate, time (NULL));
643 
644 			gda_value_reset_with_type (value, type);
645 			g_value_take_boxed (value, ndate);
646 			real_set_value (GDAUI_ENTRY_WRAPPER (data), value);
647 		}
648 		else if (type == GDA_TYPE_TIMESTAMP) {
649 			GValue *tsvalue;
650 			gchar *str;
651 			GdauiEntryCommonTime *mgtim = GDAUI_ENTRY_COMMON_TIME (data);
652 			str = gdaui_formatted_entry_get_text (GDAUI_FORMATTED_ENTRY (mgtim->priv->entry_time));
653 			tsvalue = gda_value_new_timestamp_from_timet (time (NULL));
654 			real_set_value (GDAUI_ENTRY_WRAPPER (data), tsvalue);
655 			gda_value_free (tsvalue);
656 			if (str && g_ascii_isdigit (*str))
657 				gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_time), str);
658 			g_free (str);
659 		}
660 	}
661 	else {
662 		GDate *date = NULL;
663 		if (type == G_TYPE_DATE) {
664 			date = (GDate*) g_value_get_boxed (value);
665 		}
666 		else if (type == GDA_TYPE_TIMESTAMP) {
667 			const GdaTimestamp *ts;
668 			ts = gda_value_get_timestamp (value);
669 			date = g_date_new_dmy (ts->day, ts->month, ts->year);
670 		}
671 
672 		if (date) {
673 			GDate *ndate;
674 			gboolean changed = FALSE;
675 
676 			ndate = g_new (GDate, 1);
677 			*ndate = *date;
678 			if ((insert_char == g_utf8_get_char ("+")) ||
679 			    (insert_char == g_utf8_get_char ("="))) {
680 				g_date_add_days (ndate, 1);
681 				changed = TRUE;
682 			}
683 			else if ((insert_char == g_utf8_get_char ("-")) ||
684 				 (insert_char == g_utf8_get_char ("6"))) {
685 				g_date_subtract_days (ndate, 1);
686 				changed = TRUE;
687 			}
688 
689 			if (changed) {
690 				if (type == G_TYPE_DATE) {
691 					g_value_take_boxed (value, ndate);
692 				}
693 				else if (type == GDA_TYPE_TIMESTAMP) {
694 					GdaTimestamp *ts;
695 					ts = (GdaTimestamp*) gda_timestamp_copy ((gpointer) gda_value_get_timestamp (value));
696 					ts->day = g_date_get_day (ndate);
697 					ts->month = g_date_get_month (ndate);
698 					ts->year = g_date_get_year (ndate);
699 					g_date_free (date);
700 					g_date_free (ndate);
701 					gda_value_set_timestamp (value, ts);
702 					gda_timestamp_free (ts);
703 				}
704 				real_set_value (GDAUI_ENTRY_WRAPPER (data), value);
705 			}
706 		}
707 	}
708 	gda_value_free (value);
709 }
710 
711 static void
hide_popup(GdauiEntryCommonTime * mgtim)712 hide_popup (GdauiEntryCommonTime *mgtim)
713 {
714         gtk_widget_hide (mgtim->priv->window);
715         gtk_grab_remove (mgtim->priv->window);
716 }
717 
718 static gint
date_delete_popup(G_GNUC_UNUSED GtkWidget * widget,GdauiEntryCommonTime * mgtim)719 date_delete_popup (G_GNUC_UNUSED GtkWidget *widget, GdauiEntryCommonTime *mgtim)
720 {
721 	hide_popup (mgtim);
722 	return TRUE;
723 }
724 
725 static gint
date_key_press_popup(GtkWidget * widget,GdkEventKey * event,GdauiEntryCommonTime * mgtim)726 date_key_press_popup (GtkWidget *widget, GdkEventKey *event, GdauiEntryCommonTime *mgtim)
727 {
728 	if (event->keyval != GDK_KEY_Escape)
729                 return FALSE;
730 
731         g_signal_stop_emission_by_name (widget, "key-press-event");
732         hide_popup (mgtim);
733 
734         return TRUE;
735 }
736 
737 static gint
date_button_press_popup(GtkWidget * widget,GdkEventButton * event,GdauiEntryCommonTime * mgtim)738 date_button_press_popup (GtkWidget *widget, GdkEventButton *event, GdauiEntryCommonTime *mgtim)
739 {
740 	GtkWidget *child;
741 
742         child = gtk_get_event_widget ((GdkEvent *) event);
743 
744         /* We don't ask for button press events on the grab widget, so
745          *  if an event is reported directly to the grab widget, it must
746          *  be on a window outside the application (and thus we remove
747          *  the popup window). Otherwise, we check if the widget is a child
748          *  of the grab widget, and only remove the popup window if it
749          *  is not.
750          */
751         if (child != widget) {
752                 while (child) {
753                         if (child == widget)
754                                 return FALSE;
755                         child = gtk_widget_get_parent (child);
756                 }
757         }
758 
759         hide_popup (mgtim);
760 
761         return TRUE;
762 }
763 
764 static void
date_day_selected(GtkCalendar * calendar,GdauiEntryCommonTime * mgtim)765 date_day_selected (GtkCalendar *calendar, GdauiEntryCommonTime *mgtim)
766 {
767 	char buffer [256];
768         guint year, month, day;
769         struct tm mtm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
770         char *str_utf8;
771 
772         gtk_calendar_get_date (calendar, &year, &month, &day);
773 
774         mtm.tm_mday = day;
775         mtm.tm_mon = month;
776         if (year > 1900)
777                 mtm.tm_year = year - 1900;
778         else
779                 mtm.tm_year = year;
780 
781         if (strftime (buffer, sizeof (buffer), "%x", &mtm) == 0)
782                 strcpy (buffer, "???");
783         buffer[sizeof(buffer)-1] = '\0';
784 
785         str_utf8 = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
786         gdaui_entry_set_text (GDAUI_ENTRY (mgtim->priv->entry_date), str_utf8);
787         g_free (str_utf8);
788 }
789 
790 static void
date_day_selected_double_click(G_GNUC_UNUSED GtkCalendar * calendar,GdauiEntryCommonTime * mgtim)791 date_day_selected_double_click (G_GNUC_UNUSED GtkCalendar *calendar, GdauiEntryCommonTime *mgtim)
792 {
793 	hide_popup (mgtim);
794 }
795 
796 
797 static gboolean popup_grab_on_window (GtkWidget *widget, guint32 activate_time);
798 static void position_popup (GdauiEntryCommonTime *mgtim);
799 static void
date_calendar_choose_cb(GtkWidget * button,GdauiEntryCommonTime * mgtim)800 date_calendar_choose_cb (GtkWidget *button, GdauiEntryCommonTime *mgtim)
801 {
802 	GValue *value;
803         guint year=0, month=0, day=0;
804 	gboolean unset = TRUE;
805 
806         /* setting the calendar to the latest displayed date */
807 	value = gdaui_data_entry_get_value (GDAUI_DATA_ENTRY (mgtim));
808 
809         if (value && !gda_value_is_null (value)) {
810 		const GDate *date;
811 		const GdaTimestamp *ts;
812 		GType type;
813 
814 		type = gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (mgtim));
815 		if (type == G_TYPE_DATE) {
816 			date = (GDate*) g_value_get_boxed (value);
817 			if (date) {
818 				month = g_date_get_month (date);
819 				year = g_date_get_year (date);
820 				day = g_date_get_day (date);
821 				if ((month != G_DATE_BAD_MONTH) &&
822 				    (day != G_DATE_BAD_DAY) &&
823 				    (year != G_DATE_BAD_YEAR)) {
824 					month -= 1;
825 					unset = FALSE;
826 				}
827 			}
828 		}
829 		else if (type == GDA_TYPE_TIMESTAMP) {
830 			ts = gda_value_get_timestamp (value);
831 			if (ts) {
832 				year = ts->year;
833 				month = ts->month - 1;
834 				day = ts->day;
835 				unset = FALSE;
836 			}
837 		}
838 		else
839 			g_assert_not_reached ();
840         }
841 
842 	if (unset) {
843                 time_t now;
844                 struct tm *stm;
845 
846                 now = time (NULL);
847 #ifdef HAVE_LOCALTIME_R
848 		struct tm tmpstm;
849 		stm = localtime_r (&now, &tmpstm);
850 #elif HAVE_LOCALTIME_S
851 		struct tm tmpstm;
852 		g_assert (localtime_s (&tmpstm, &now) == 0);
853 		stm = &tmpstm;
854 #else
855                 stm = localtime (&now);
856 #endif
857                 year = stm->tm_year + 1900;
858                 month = stm->tm_mon;
859                 day = stm->tm_mday;
860         }
861 
862         gtk_calendar_select_month (GTK_CALENDAR (mgtim->priv->date), month, year);
863         gtk_calendar_select_day (GTK_CALENDAR (mgtim->priv->date), day);
864 
865         /* popup window */
866         /* Temporarily grab pointer and keyboard, copied from GnomeDateEdit */
867         if (!popup_grab_on_window (button, gtk_get_current_event_time ()))
868                 return;
869 
870         position_popup (mgtim);
871         gtk_widget_show (mgtim->priv->window);
872         gtk_grab_add (mgtim->priv->window);
873 
874 	GdkScreen *screen;
875 	gint swidth, sheight;
876 	gint root_x, root_y;
877 	gint wwidth, wheight;
878 	gboolean do_move = FALSE;
879 	screen = gtk_window_get_screen (GTK_WINDOW (mgtim->priv->window));
880 	if (screen) {
881 		swidth = gdk_screen_get_width (screen);
882 		sheight = gdk_screen_get_height (screen);
883 	}
884 	else {
885 		swidth = gdk_screen_width ();
886 		sheight = gdk_screen_height ();
887 	}
888 	gtk_window_get_position (GTK_WINDOW (mgtim->priv->window), &root_x, &root_y);
889 	gtk_window_get_size (GTK_WINDOW (mgtim->priv->window), &wwidth, &wheight);
890 	if (root_x + wwidth > swidth) {
891 		do_move = TRUE;
892 		root_x = swidth - wwidth;
893 	}
894 	else if (root_x < 0) {
895 		do_move = TRUE;
896 		root_x = 0;
897 	}
898 	if (root_y + wheight > sheight) {
899 		do_move = TRUE;
900 		root_y = sheight - wheight;
901 	}
902 	else if (root_y < 0) {
903 		do_move = TRUE;
904 		root_y = 0;
905 	}
906 	if (do_move)
907 		gtk_window_move (GTK_WINDOW (mgtim->priv->window), root_x, root_y);
908 
909         gtk_widget_grab_focus (mgtim->priv->date);
910         popup_grab_on_window (mgtim->priv->window,
911                               gtk_get_current_event_time ());
912 }
913 
914 static gboolean
popup_grab_on_window(GtkWidget * widget,guint32 activate_time)915 popup_grab_on_window (GtkWidget *widget, guint32 activate_time)
916 {
917 	GdkDeviceManager *manager;
918 	GdkDevice *pointer;
919 	GdkWindow *window;
920 	window = gtk_widget_get_window (widget);
921 	manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
922 	pointer = gdk_device_manager_get_client_pointer (manager);
923         if (gdk_device_grab (pointer, window, GDK_OWNERSHIP_WINDOW, TRUE,
924 			     GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
925 			     GDK_POINTER_MOTION_MASK,
926 			     NULL, activate_time) == GDK_GRAB_SUCCESS) {
927 		GdkDevice *keyb;
928 		keyb = gdk_device_get_associated_device (pointer);
929                 if (gdk_device_grab (keyb, window, GDK_OWNERSHIP_WINDOW, TRUE,
930 				     GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, NULL, activate_time) ==
931 		    GDK_GRAB_SUCCESS)
932                         return TRUE;
933                 else {
934                         gdk_device_ungrab (pointer, activate_time);
935                         return FALSE;
936                 }
937         }
938         return FALSE;
939 }
940 
941 static void
position_popup(GdauiEntryCommonTime * mgtim)942 position_popup (GdauiEntryCommonTime *mgtim)
943 {
944         gint x, y;
945         gint bwidth, bheight;
946         GtkRequisition req_minimum, req_natural;
947 
948         gtk_widget_get_preferred_size (mgtim->priv->window, &req_minimum,
949 				       &req_natural);
950 
951         gdk_window_get_origin (gtk_widget_get_window (mgtim->priv->date_button), &x, &y);
952 	GtkAllocation alloc;
953 	gtk_widget_get_allocation (mgtim->priv->date_button, &alloc);
954         x += alloc.x;
955         y += alloc.y;
956         bwidth = alloc.width;
957         bheight = alloc.height;
958 
959         x += bwidth - req_natural.width;
960         y += bheight;
961 
962         if (x < 0)
963                 x = 0;
964 
965         if (y < 0)
966                 y = 0;
967 
968         gtk_window_move (GTK_WINDOW (mgtim->priv->window), x, y);
969 }
970 
971 
972 
973 
974 /*
975  * callbacks for the time
976  */
977 static void entry_time_insert_func (GdauiFormattedEntry *fentry, gunichar insert_char, gint virt_pos, gpointer data);
978 
979 static GtkWidget *
create_entry_time(GdauiEntryCommonTime * mgtim)980 create_entry_time (GdauiEntryCommonTime *mgtim)
981 {
982 	GtkWidget *wid;
983 	GdaDataHandler *dh;
984 
985 	/* text entry */
986 	dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (mgtim));
987 	if (GDA_IS_HANDLER_TIME (dh)) {
988 		gchar *str, *mask, *ptr;
989 		str = gda_handler_time_get_format (GDA_HANDLER_TIME (dh), GDA_TYPE_TIME);
990 		mask = g_strdup (str);
991 		for (ptr = mask; *ptr; ptr++) {
992 			if (*ptr == '0')
993 				*ptr = '-';
994 		}
995 		wid = gdaui_formatted_entry_new (str, mask);
996 		g_free (str);
997 		g_free (mask);
998 
999 		gdaui_formatted_entry_set_insert_func (GDAUI_FORMATTED_ENTRY (wid), entry_time_insert_func,
1000 						       mgtim);
1001 	}
1002 	else
1003 		wid = gdaui_entry_new (NULL, NULL);
1004         mgtim->priv->entry_time = wid;
1005 
1006         /* format tooltip */
1007 	gtk_widget_set_tooltip_text (wid, _("Format is hh:mm:ss"));
1008 
1009         return wid;
1010 }
1011 
1012 static void
entry_time_insert_func(G_GNUC_UNUSED GdauiFormattedEntry * fentry,gunichar insert_char,G_GNUC_UNUSED gint virt_pos,gpointer data)1013 entry_time_insert_func (G_GNUC_UNUSED GdauiFormattedEntry *fentry, gunichar insert_char,
1014 			G_GNUC_UNUSED gint virt_pos, gpointer data)
1015 {
1016 	GValue *value;
1017 	GType type;
1018 
1019 	type = gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (data));
1020 	value = real_get_value (GDAUI_ENTRY_WRAPPER (data));
1021 	if (!value)
1022 		return;
1023 
1024 	if (insert_char != g_utf8_get_char (" "))
1025 		return;
1026 
1027 	if (type == GDA_TYPE_TIME) {
1028 		/* set current time */
1029 		gda_value_reset_with_type (value, type);
1030 		struct tm *ltm;
1031 		time_t val;
1032 
1033 		val = time (NULL);
1034 		ltm = localtime ((const time_t *) &val);
1035 		if (ltm) {
1036 			GdaTime tim;
1037 			memset (&tim, 0, sizeof (GdaTime));
1038 			tim.hour = ltm->tm_hour;
1039 			tim.minute = ltm->tm_min;
1040 			tim.second = ltm->tm_sec;
1041 			tim.fraction = 0;
1042 			tim.timezone = GDA_TIMEZONE_INVALID;
1043 			gda_value_set_time (value, (const GdaTime *) &tim);
1044 			real_set_value (GDAUI_ENTRY_WRAPPER (data), value);
1045 		}
1046 	}
1047 	else if (type == GDA_TYPE_TIMESTAMP && (G_VALUE_TYPE (value) == GDA_TYPE_TIMESTAMP)) {
1048 		const GdaTimestamp *ts;
1049 		ts = gda_value_get_timestamp (value);
1050 		if (ts) {
1051 			struct tm *ltm;
1052 			time_t val;
1053 
1054 			val = time (NULL);
1055 			ltm = localtime ((const time_t *) &val);
1056 			if (ltm) {
1057 				GdaTimestamp tim;
1058 				tim = *ts;
1059 				tim.hour = ltm->tm_hour;
1060 				tim.minute = ltm->tm_min;
1061 				tim.second = ltm->tm_sec;
1062 				tim.fraction = 0;
1063 				tim.timezone = GDA_TIMEZONE_INVALID;
1064 				gda_value_set_timestamp (value, (const GdaTimestamp *) &tim);
1065 				real_set_value (GDAUI_ENTRY_WRAPPER (data), value);
1066 			}
1067 		}
1068 	}
1069 	else if (type == GDA_TYPE_TIMESTAMP) {
1070 		/* value is GDA_TYPE_NULL */
1071 		entry_date_insert_func (NULL, insert_char, 0, data);
1072 	}
1073 
1074 	gda_value_free (value);
1075 }
1076 
1077 /*
1078  * callbacks for the timestamp
1079  */
1080 static GtkWidget *
create_entry_ts(GdauiEntryCommonTime * mgtim)1081 create_entry_ts (GdauiEntryCommonTime *mgtim)
1082 {
1083 	GtkWidget *hb, *wid;
1084 
1085 	hb = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1086 
1087 	/* date part */
1088 	wid = create_entry_date (mgtim);
1089 	gtk_box_pack_start (GTK_BOX (hb), wid, FALSE, FALSE, 0);
1090 	gtk_widget_show (wid);
1091 
1092 	/* time part */
1093 	wid = create_entry_time (mgtim);
1094 	gtk_box_pack_start (GTK_BOX (hb), wid, FALSE, FALSE, 0);
1095 	gtk_widget_show (wid);
1096 
1097 	mgtim->priv->hbox = hb;
1098 
1099 	return hb;
1100 }
1101 
1102 
1103 
1104 /*
1105  * GtkCellEditable interface
1106  */
1107 static void
gtk_cell_editable_entry_editing_done_cb(G_GNUC_UNUSED GtkEntry * entry,GdauiEntryCommonTime * mgtim)1108 gtk_cell_editable_entry_editing_done_cb (G_GNUC_UNUSED GtkEntry *entry, GdauiEntryCommonTime *mgtim)
1109 {
1110 	gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (mgtim));
1111 }
1112 
1113 static void
gtk_cell_editable_entry_remove_widget_cb(G_GNUC_UNUSED GtkEntry * entry,GdauiEntryCommonTime * mgtim)1114 gtk_cell_editable_entry_remove_widget_cb (G_GNUC_UNUSED GtkEntry *entry, GdauiEntryCommonTime *mgtim)
1115 {
1116 	gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (mgtim));
1117 }
1118 
1119 static void
gdaui_entry_common_time_start_editing(GtkCellEditable * iface,GdkEvent * event)1120 gdaui_entry_common_time_start_editing (GtkCellEditable *iface, GdkEvent *event)
1121 {
1122 	GdauiEntryCommonTime *mgtim;
1123 
1124 	g_return_if_fail (GDAUI_IS_ENTRY_COMMON_TIME (iface));
1125 	mgtim = GDAUI_ENTRY_COMMON_TIME (iface);
1126 	g_return_if_fail (mgtim->priv);
1127 
1128 	mgtim->priv->editing_canceled = FALSE;
1129 	if (mgtim->priv->date_button) {
1130 		gtk_widget_destroy (mgtim->priv->date_button);
1131 		mgtim->priv->date_button = NULL;
1132 	}
1133 
1134 	if (mgtim->priv->hbox) {
1135 		gtk_box_set_spacing (GTK_BOX (mgtim->priv->hbox), 0);
1136 		gtk_container_set_border_width (GTK_CONTAINER (mgtim->priv->hbox), 0);
1137 	}
1138 
1139 	if (mgtim->priv->entry_date) {
1140 		g_object_set (G_OBJECT (mgtim->priv->entry_date), "has-frame", FALSE, NULL);
1141 		gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (mgtim->priv->entry_date), event);
1142 		g_signal_connect (G_OBJECT (mgtim->priv->entry_date), "editing-done",
1143 				  G_CALLBACK (gtk_cell_editable_entry_editing_done_cb), mgtim);
1144 		g_signal_connect (G_OBJECT (mgtim->priv->entry_date), "remove-widget",
1145 				  G_CALLBACK (gtk_cell_editable_entry_remove_widget_cb), mgtim);
1146 	}
1147 
1148 	if (mgtim->priv->entry_time) {
1149 		g_object_set (G_OBJECT (mgtim->priv->entry_time), "has-frame", FALSE, NULL);
1150 		gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (mgtim->priv->entry_time), event);
1151 		g_signal_connect (G_OBJECT (mgtim->priv->entry_time), "editing-done",
1152 				  G_CALLBACK (gtk_cell_editable_entry_editing_done_cb), mgtim);
1153 		g_signal_connect (G_OBJECT (mgtim->priv->entry_time), "remove-widget",
1154 				  G_CALLBACK (gtk_cell_editable_entry_remove_widget_cb), mgtim);
1155 	}
1156 
1157 	gdaui_entry_shell_refresh (GDAUI_ENTRY_SHELL (mgtim));
1158 
1159 	if (mgtim->priv->entry_date)
1160 		gtk_widget_grab_focus (mgtim->priv->entry_date);
1161 	else
1162 		gtk_widget_grab_focus (mgtim->priv->entry_time);
1163 	gtk_widget_queue_draw (GTK_WIDGET (mgtim));
1164 }
1165