1 /*  HomeBank -- Free, easy, personal accounting for everyone.
2  *  Copyright (C) 1995-2021 Maxime DOYEN
3  *
4  *  This file is part of HomeBank.
5  *
6  *  HomeBank is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  HomeBank is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 
21 //#include <time.h>
22 #include <stdlib.h>		/* atoi, atof, atol */
23 #include <libintl.h>
24 
25 #include <gtk/gtk.h>
26 #include <gdk/gdkkeysyms.h>
27 
28 #include "gtk-dateentry.h"
29 
30 #define MYDEBUG 0
31 
32 #if MYDEBUG
33 #define DB(x) (x);
34 #else
35 #define DB(x);
36 #endif
37 
38 
39 enum {
40   CHANGED,
41   LAST_SIGNAL
42 };
43 
44 
45 enum {
46 	PROPERTY_DATE = 5,
47 };
48 
49 
50 static guint dateentry_signals[LAST_SIGNAL] = {0,};
51 
52 
53 //G_DEFINE_TYPE(GtkDateEntry, gtk_date_entry, GTK_TYPE_BOX)
54 G_DEFINE_TYPE_WITH_CODE(GtkDateEntry, gtk_date_entry, GTK_TYPE_BOX, G_ADD_PRIVATE (GtkDateEntry))
55 
56 
57 
58 // todo:finish this
59 // this is to be able to seizure d or d/m or m/d in the gtkdateentry
60 
61 /* order of these in the current locale */
62 static GDateDMY dmy_order[3] =
63 {
64    G_DATE_DAY, G_DATE_MONTH, G_DATE_YEAR
65 };
66 
67 struct _GDateParseTokens {
68   gint num_ints;
69   gint n[3];
70   guint month;
71 };
72 
73 typedef struct _GDateParseTokens GDateParseTokens;
74 
75 #define NUM_LEN 10
76 
77 static void gtk_date_entry_cb_calendar_today_mark(GtkWidget *calendar, GtkDateEntry *dateentry);
78 
79 static void
hb_date_fill_parse_tokens(const gchar * str,GDateParseTokens * pt)80 hb_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
81 {
82   gchar num[4][NUM_LEN+1];
83   gint i;
84   const guchar *s;
85 
86   //DB( g_print("\n[dateentry] fill parse token\n") );
87 
88   /* We count 4, but store 3; so we can give an error
89    * if there are 4.
90    */
91   num[0][0] = num[1][0] = num[2][0] = num[3][0] = '\0';
92 
93   s = (const guchar *) str;
94   pt->num_ints = 0;
95   while (*s && pt->num_ints < 4)
96     {
97 
98       i = 0;
99       while (*s && g_ascii_isdigit (*s) && i < NUM_LEN)
100         {
101           num[pt->num_ints][i] = *s;
102           ++s;
103           ++i;
104         }
105 
106       if (i > 0)
107         {
108           num[pt->num_ints][i] = '\0';
109           ++(pt->num_ints);
110         }
111 
112       if (*s == '\0') break;
113 
114       ++s;
115     }
116 
117   pt->n[0] = pt->num_ints > 0 ? atoi (num[0]) : 0;
118   pt->n[1] = pt->num_ints > 1 ? atoi (num[1]) : 0;
119   pt->n[2] = pt->num_ints > 2 ? atoi (num[2]) : 0;
120 
121 }
122 
123 
hb_date_parse_tokens(GDate * date,const gchar * str)124 static void hb_date_parse_tokens(GDate *date, const gchar *str)
125 {
126 GDateParseTokens pt;
127 
128 	hb_date_fill_parse_tokens(str, &pt);
129 	DB( g_print(" -> parsetoken return %d values: %d %d %d\n", pt.num_ints, pt.n[0], pt.n[1], pt.n[2]) );
130 
131 	// initialize with today's date
132 	g_date_set_time_t(date, time(NULL));
133 
134 	switch( pt.num_ints )
135 	{
136 		case 1:
137 			DB( g_print(" -> seizured 1 number\n") );
138 			if(g_date_valid_day(pt.n[0]))
139 				g_date_set_day(date, pt.n[0]);
140 			break;
141 		case 2:
142 			DB( g_print(" -> seizured 2 numbers\n") );
143 			if( dmy_order[0] != G_DATE_YEAR )
144 			{
145 				if( dmy_order[0] == G_DATE_DAY )
146 				{
147 					if(g_date_valid_day(pt.n[0]))
148 					    g_date_set_day(date, pt.n[0]);
149 					if(g_date_valid_month(pt.n[1]))
150 						g_date_set_month(date, pt.n[1]);
151 				}
152 				else
153 				{
154 					if(g_date_valid_day(pt.n[1]))
155 					    g_date_set_day(date, pt.n[1]);
156 					if(g_date_valid_month(pt.n[0]))
157 						g_date_set_month(date, pt.n[0]);
158 				}
159 			}
160 			break;
161 	}
162 }
163 
164 
165 static void
update_text(GtkDateEntry * self)166 update_text(GtkDateEntry *self)
167 {
168 GtkDateEntryPrivate *priv = self->priv;
169 gchar label[256];
170 
171 	DB( g_print("\n[dateentry] update text\n") );
172 
173 	//%x : The preferred date representation for the current locale without the time.
174 	g_date_strftime (label, 256 - 1, "%x", priv->date);
175 	gtk_entry_set_text (GTK_ENTRY (priv->entry), label);
176 	DB( g_print(" = %s\n", label) );
177 }
178 
179 
180 static void
eval_date(GtkDateEntry * self)181 eval_date(GtkDateEntry *self)
182 {
183 GtkDateEntryPrivate *priv = self->priv;
184 
185 	DB( g_print(" pre %d %d %d\n", g_date_get_day(priv->date), g_date_get_month(priv->date), g_date_get_year(priv->date)) );
186 
187 	g_date_clamp(priv->date, &priv->mindate, &priv->maxdate);
188 	DB( g_print(" min %d %d %d\n", g_date_get_day(&priv->mindate), g_date_get_month(&priv->mindate), g_date_get_year(&priv->mindate)) );
189 	DB( g_print(" max %d %d %d\n", g_date_get_day(&priv->maxdate), g_date_get_month(&priv->maxdate), g_date_get_year(&priv->maxdate)) );
190 
191 	update_text(self);
192 
193 	if(priv->lastdate != g_date_get_julian(priv->date))
194 	{
195 		DB( g_print(" **emit 'changed' signal**\n") );
196 		g_signal_emit_by_name (self, "changed", NULL, NULL);
197 	}
198 
199 	priv->lastdate = g_date_get_julian(priv->date);
200 
201 	DB( g_print(" post %d %d %d\n", g_date_get_day(priv->date), g_date_get_month(priv->date), g_date_get_year(priv->date)) );
202 }
203 
204 
205 static void
parse_date(GtkDateEntry * self)206 parse_date(GtkDateEntry *self)
207 {
208 GtkDateEntryPrivate *priv = self->priv;
209 const gchar *str;
210 
211 	DB( g_print("\n[dateentry] parse date\n") );
212 
213 	str = gtk_entry_get_text (GTK_ENTRY (priv->entry));
214 
215 	//1) we parse the string according to the locale
216 	g_date_set_parse (priv->date, str);
217 	DB( g_print(" parsed '%s' %d %d %d\n", str, g_date_get_day(priv->date), g_date_get_month(priv->date), g_date_get_year(priv->date)) );
218 
219 	if(!g_date_valid(priv->date) || g_date_get_julian (priv->date) <= HB_MINDATE)
220 	{
221 		//2) give a try to tokens: day, day/month, month/day
222 		hb_date_parse_tokens(priv->date, str);
223 		DB( g_print(" tokened %d %d %d\n", g_date_get_day(priv->date), g_date_get_month(priv->date), g_date_get_year(priv->date)) );
224 	}
225 
226 	//3) at last if date still invalid, put today's dateentry_signals
227 	// we should consider just warn the user here
228 	if(!g_date_valid(priv->date))
229 	{
230 		g_date_set_time_t(priv->date, time(NULL));
231 	}
232 	eval_date(self);
233 }
234 
235 
236 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
237 
238 
239 static void
gtk_date_entry_set_calendar(GtkWidget * widget,GtkDateEntry * dateentry)240 gtk_date_entry_set_calendar (GtkWidget * widget, GtkDateEntry * dateentry)
241 {
242 GtkDateEntryPrivate *priv = dateentry->priv;
243 guint day, month;
244 
245 	DB( g_print("\n[dateentry] set calendar\n") );
246 
247 	/* GtkCalendar expects month to be in 0-11 range (inclusive) */
248 	day   = g_date_get_day (priv->date);
249 	month = g_date_get_month (priv->date) - 1;
250 
251 	g_signal_handler_block(priv->calendar, priv->hid_dayselect);
252 
253 	gtk_calendar_select_month (GTK_CALENDAR (priv->calendar),
254 			   month,
255 			   g_date_get_year (priv->date));
256     gtk_calendar_select_day (GTK_CALENDAR (priv->calendar), day);
257 
258 	g_signal_handler_unblock(priv->calendar, priv->hid_dayselect);
259 }
260 
261 
262 
263 
264 static void
gtk_date_entry_cb_today_clicked(GtkWidget * widget,GtkDateEntry * dateentry)265 gtk_date_entry_cb_today_clicked (GtkWidget * widget, GtkDateEntry * dateentry)
266 {
267 GtkDateEntryPrivate *priv = dateentry->priv;
268 
269 	DB( g_print("\n[dateentry] today_clicked\n") );
270 
271 	//revert to now (today)
272 	g_date_set_time_t(priv->date, time(NULL));
273 	eval_date(dateentry);
274 
275 	gtk_date_entry_set_calendar(widget, dateentry);
276 
277 	gtk_widget_hide (priv->popover);
278 }
279 
280 
281 static void
gtk_date_entry_cb_calendar_day_selected(GtkWidget * calendar,GtkDateEntry * dateentry)282 gtk_date_entry_cb_calendar_day_selected(GtkWidget * calendar, GtkDateEntry * dateentry)
283 {
284 GtkDateEntryPrivate *priv = dateentry->priv;
285 guint year, month, day;
286 
287 	DB( g_print("\n[dateentry] calendar_day_selected\n") );
288 
289 	gtk_calendar_get_date (GTK_CALENDAR (priv->calendar), &year, &month, &day);
290 	g_date_set_dmy (priv->date, day, month + 1, year);
291 	eval_date(dateentry);
292 }
293 
294 
295 static gint
gtk_date_entry_cb_calendar_day_select_double_click(GtkWidget * calendar,gpointer user_data)296 gtk_date_entry_cb_calendar_day_select_double_click(GtkWidget * calendar, gpointer user_data)
297 {
298 GtkDateEntry *dateentry = user_data;
299 GtkDateEntryPrivate *priv = dateentry->priv;
300 
301 	DB( g_print("\n[dateentry] calendar_day_select_double_click\n") );
302 
303 	gtk_widget_hide (priv->popover);
304 
305 	return FALSE;
306 }
307 
308 
309 static void
gtk_date_entry_cb_calendar_today_mark(GtkWidget * calendar,GtkDateEntry * dateentry)310 gtk_date_entry_cb_calendar_today_mark(GtkWidget *calendar, GtkDateEntry *dateentry)
311 {
312 GtkDateEntryPrivate *priv = dateentry->priv;
313 guint year, month, day;
314 
315 	DB( g_print("\n[dateentry] cb_calendar_mark_day\n") );
316 
317 	gtk_calendar_get_date (GTK_CALENDAR (priv->calendar), &year, &month, &day);
318 
319 	//maybe 1828914
320 	gtk_calendar_clear_marks(GTK_CALENDAR(priv->calendar));
321 	if( year == g_date_get_year (&priv->nowdate) && month == (g_date_get_month (&priv->nowdate)-1) )
322 		gtk_calendar_mark_day(GTK_CALENDAR(priv->calendar), g_date_get_day (&priv->nowdate));
323 
324 }
325 
326 
327 static void
gtk_date_entry_cb_calendar_monthyear(GtkWidget * calendar,GtkDateEntry * dateentry)328 gtk_date_entry_cb_calendar_monthyear(GtkWidget *calendar, GtkDateEntry *dateentry)
329 {
330 GtkDateEntryPrivate *priv = dateentry->priv;
331 guint year, month, day;
332 
333 	DB( g_print("\n[dateentry] cb_calendar_monthyear\n") );
334 
335 	gtk_calendar_get_date (GTK_CALENDAR (priv->calendar), &year, &month, &day);
336 	if( year < 1900)
337 		g_object_set(calendar, "year", 1900, NULL);
338 
339 	if( year > 2200)
340 		g_object_set(calendar, "year", 2200, NULL);
341 
342 	gtk_date_entry_cb_calendar_today_mark(calendar, dateentry);
343 }
344 
345 
346 static gint
gtk_date_entry_cb_entry_key_pressed(GtkWidget * widget,GdkEventKey * event,gpointer user_data)347 gtk_date_entry_cb_entry_key_pressed (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
348 {
349 GtkDateEntry *dateentry = user_data;
350 GtkDateEntryPrivate *priv = dateentry->priv;
351 guint action;
352 
353 	DB( g_print("\n[dateentry] entry key pressed") );
354 
355 
356 	DB( g_print(" state: %s %s\n", (event->state & GDK_SHIFT_MASK) ? "shift" : "", (event->state & GDK_CONTROL_MASK) ? "ctrl" : "" ) );
357 	DB( g_print(" kyval: %s %s\n", (event->keyval == GDK_KEY_Up) ? "up" : "",  (event->keyval == GDK_KEY_Down) ? "down" : "") );
358 
359 	if( (event->type != GDK_KEY_PRESS) )
360 		return FALSE;
361 
362 	//#1873643 preserve Up/Down (+ctrl) natural GTK focus change
363 	if( (event->state & GDK_CONTROL_MASK) && !(event->state & GDK_SHIFT_MASK) )
364 		return FALSE;
365 
366 	if( (event->keyval == GDK_KEY_Up) || (event->keyval == GDK_KEY_Down) )
367 	{
368 		//let's bitwise key to an action-id
369 		action = 0;
370 		action |= (event->state & GDK_SHIFT_MASK)   ? 2 : 0;
371 		action |= (event->state & GDK_CONTROL_MASK) ? 4 : 0;
372 		action |= (event->keyval == GDK_KEY_Down)   ? 1 : 0;
373 
374 		DB( g_print(" action: %d\n", action) );
375 
376 		switch(action)
377 		{
378 			case 0: g_date_add_days (priv->date, 1); break;
379 			case 1: g_date_subtract_days (priv->date, 1); break;
380 			case 2:	g_date_add_months (priv->date, 1); break;
381 			case 3:	g_date_subtract_months (priv->date, 1); break;
382 			case 6:	g_date_add_years (priv->date, 1); break;
383 			case 7:	g_date_subtract_years (priv->date, 1); break;
384 		}
385 
386 		eval_date(dateentry);
387 
388 		//stop handlers
389 		return TRUE;
390 	}
391 	//propagate
392 	return FALSE;
393 }
394 
395 
396 static void
gtk_date_entry_cb_entry_activate(GtkWidget * gtkentry,gpointer user_data)397 gtk_date_entry_cb_entry_activate(GtkWidget *gtkentry, gpointer user_data)
398 {
399 GtkDateEntry *dateentry = user_data;
400 
401 	DB( g_print("\n[dateentry] entry_activate\n") );
402 
403 	parse_date(dateentry);
404 	eval_date(dateentry);
405 }
406 
407 
408 static gboolean
gtk_date_entry_cb_entry_focus_out(GtkWidget * widget,GdkEventFocus * event,gpointer user_data)409 gtk_date_entry_cb_entry_focus_out(GtkWidget *widget, GdkEventFocus *event, gpointer user_data)
410 {
411 GtkDateEntry *dateentry = user_data;
412 
413 	DB( g_print("\n[dateentry] entry focus-out-event %d\n", gtk_widget_is_focus(GTK_WIDGET(dateentry))) );
414 
415 	parse_date(dateentry);
416 	eval_date(dateentry);
417 	return FALSE;
418 }
419 
420 
421 static void
gtk_date_entry_cb_button_clicked(GtkWidget * widget,GtkDateEntry * dateentry)422 gtk_date_entry_cb_button_clicked (GtkWidget * widget, GtkDateEntry * dateentry)
423 {
424 GtkDateEntryPrivate *priv = dateentry->priv;
425 
426 	DB( g_print("\n[dateentry] button_clicked\n") );
427 
428 	gtk_date_entry_set_calendar(widget, dateentry);
429 
430 	gtk_popover_set_relative_to (GTK_POPOVER (priv->popover), GTK_WIDGET (priv->entry));
431 	//gtk_widget_get_clip(priv->arrow, &rect);
432 	//gtk_popover_set_pointing_to (GTK_POPOVER (priv->popover), &rect);
433 
434 	gtk_date_entry_cb_calendar_today_mark(widget, dateentry);
435 
436 	gtk_widget_show_all (priv->popover);
437 }
438 
439 
440 static void
gtk_date_entry_destroy(GtkWidget * object)441 gtk_date_entry_destroy (GtkWidget *object)
442 {
443 GtkDateEntry *dateentry = GTK_DATE_ENTRY (object);
444 GtkDateEntryPrivate *priv = dateentry->priv;
445 
446 	g_return_if_fail(object != NULL);
447 	g_return_if_fail(GTK_IS_DATE_ENTRY(object));
448 
449 	DB( g_print("\n[dateentry] destroy\n") );
450 
451 	DB( g_print(" free gtkentry: %p\n", priv->entry) );
452 	DB( g_print(" free arrow: %p\n", priv->button) );
453 
454 	DB( g_print(" free dateentry: %p\n", dateentry) );
455 
456 	if(priv->date)
457 		g_date_free(priv->date);
458 	priv->date = NULL;
459 
460 	GTK_WIDGET_CLASS (gtk_date_entry_parent_class)->destroy (object);
461 }
462 
463 
464 
465 static void
gtk_date_entry_dispose(GObject * gobject)466 gtk_date_entry_dispose (GObject *gobject)
467 {
468 //GtkDateEntry *self = GTK_DATE_ENTRY (gobject);
469 
470 	DB( g_print("\n[dateentry] dispose\n") );
471 
472 
473   //g_clear_object (&self->priv->an_object);
474 
475   G_OBJECT_CLASS (gtk_date_entry_parent_class)->dispose (gobject);
476 }
477 
478 
479 
480 
481 static void
gtk_date_entry_finalize(GObject * gobject)482 gtk_date_entry_finalize (GObject *gobject)
483 {
484 //GtkDateEntry *self = GTK_DATE_ENTRY (gobject);
485 
486 	DB( g_print("\n[dateentry] finalize\n") );
487 
488 
489 	//g_date_free(self->date);
490   //g_free (self->priv->a_string);
491 
492   /* Always chain up to the parent class; as with dispose(), finalize()
493    * is guaranteed to exist on the parent's class virtual function table
494    */
495   G_OBJECT_CLASS(gtk_date_entry_parent_class)->finalize (gobject);
496 }
497 
498 
499 
500 static void
gtk_date_entry_class_init(GtkDateEntryClass * class)501 gtk_date_entry_class_init (GtkDateEntryClass *class)
502 {
503 GObjectClass *object_class;
504 GtkWidgetClass *widget_class;
505 
506 	object_class = G_OBJECT_CLASS (class);
507 	widget_class = GTK_WIDGET_CLASS (class);
508 
509 	DB( g_print("\n[dateentry] class_init\n") );
510 
511 	//object_class->constructor = gtk_date_entry_constructor;
512 	//object_class->set_property = gtk_date_entry_set_property;
513 	//object_class->get_property = gtk_date_entry_get_property;
514 	object_class->dispose  = gtk_date_entry_dispose;
515 	object_class->finalize = gtk_date_entry_finalize;
516 
517 	widget_class->destroy  = gtk_date_entry_destroy;
518 
519 	dateentry_signals[CHANGED] =
520 		g_signal_new ("changed",
521                   G_TYPE_FROM_CLASS (class),
522                   G_SIGNAL_RUN_LAST,
523                   G_STRUCT_OFFSET (GtkDateEntryClass, changed),
524                   NULL, NULL,
525                   g_cclosure_marshal_VOID__VOID,
526                   G_TYPE_NONE, 0);
527 
528 	//g_type_class_add_private (object_class, sizeof (GtkDateEntryPrivate));
529 
530 }
531 
532 static void
gtk_date_entry_init(GtkDateEntry * dateentry)533 gtk_date_entry_init (GtkDateEntry *dateentry)
534 {
535 GtkDateEntryPrivate *priv;
536 GtkWidget *vbox;
537 
538 	DB( g_print("\n[dateentry] init\n") );
539 
540 	/* yes, also priv, need to keep the code readable */
541 	/*dateentry->priv = G_TYPE_INSTANCE_GET_PRIVATE (dateentry,
542                                                   GTK_TYPE_DATE_ENTRY,
543                                                   GtkDateEntryPrivate);*/
544 
545 	dateentry->priv = gtk_date_entry_get_instance_private(dateentry);
546 
547 	priv = dateentry->priv;
548 
549 	gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(dateentry)), GTK_STYLE_CLASS_LINKED);
550 
551 	priv->entry = gtk_entry_new ();
552 	//todo: see if really useful
553 	gtk_entry_set_width_chars(GTK_ENTRY(priv->entry), 16);
554 	gtk_entry_set_max_width_chars(GTK_ENTRY(priv->entry), 16);
555 	gtk_box_pack_start (GTK_BOX (dateentry), priv->entry, TRUE, TRUE, 0);
556 
557 	priv->button = gtk_button_new ();
558 	priv->arrow = gtk_image_new_from_icon_name ("pan-down-symbolic", GTK_ICON_SIZE_BUTTON);
559 	gtk_container_add (GTK_CONTAINER (priv->button), priv->arrow);
560 	gtk_box_pack_end (GTK_BOX (dateentry), priv->button, FALSE, FALSE, 0);
561 
562 	priv->popover = gtk_popover_new (priv->button);
563 	gtk_popover_set_position(GTK_POPOVER(priv->popover), GTK_POS_BOTTOM);
564 	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
565 	gtk_container_add (GTK_CONTAINER (priv->popover), vbox);
566 
567 	gtk_widget_set_margin_start (vbox, 10);
568 	gtk_widget_set_margin_end (vbox, 10);
569 	gtk_widget_set_margin_top (vbox, 10);
570 	gtk_widget_set_margin_bottom (vbox, 10);
571 
572 	priv->calendar = gtk_calendar_new ();
573 	gtk_box_pack_start(GTK_BOX(vbox), priv->calendar, FALSE, FALSE, 0);
574 
575 	priv->BT_today = gtk_button_new_with_mnemonic ( gettext("_Today"));
576 	gtk_box_pack_start(GTK_BOX(vbox), priv->BT_today, FALSE, FALSE, 0);
577 
578 	gtk_widget_show_all (GTK_WIDGET(dateentry));
579 
580 	/* initialize datas */
581 	priv->date = g_date_new();
582 	g_date_set_time_t(priv->date, time(NULL));
583 	g_date_set_time_t(&priv->nowdate, time(NULL));
584 	g_date_set_dmy(&priv->mindate,  1,  1, 1900);	//693596
585 	g_date_set_dmy(&priv->maxdate, 31, 12, 2200);	//803533
586 	update_text(dateentry);
587 
588 
589 	g_signal_connect (priv->entry, "key-press-event",
590 				G_CALLBACK (gtk_date_entry_cb_entry_key_pressed), dateentry);
591 
592 	g_signal_connect_after (priv->entry, "focus-out-event",
593 				G_CALLBACK (gtk_date_entry_cb_entry_focus_out), dateentry);
594 
595 	g_signal_connect (priv->entry, "activate",
596 				G_CALLBACK (gtk_date_entry_cb_entry_activate), dateentry);
597 
598 
599 	g_signal_connect (priv->button, "clicked",
600 				G_CALLBACK (gtk_date_entry_cb_button_clicked), dateentry);
601 
602 
603 	g_signal_connect (priv->calendar, "prev-year",
604 				G_CALLBACK (gtk_date_entry_cb_calendar_monthyear), dateentry);
605 	g_signal_connect (priv->calendar, "next-year",
606 				G_CALLBACK (gtk_date_entry_cb_calendar_monthyear), dateentry);
607 	g_signal_connect (priv->calendar, "prev-month",
608 				G_CALLBACK (gtk_date_entry_cb_calendar_monthyear), dateentry);
609 	g_signal_connect (priv->calendar, "next-month",
610 				G_CALLBACK (gtk_date_entry_cb_calendar_monthyear), dateentry);
611 
612 	priv->hid_dayselect = g_signal_connect (priv->calendar, "day-selected",
613 				G_CALLBACK (gtk_date_entry_cb_calendar_day_selected), dateentry);
614 
615 	g_signal_connect (priv->calendar, "day-selected-double-click",
616 				G_CALLBACK (gtk_date_entry_cb_calendar_day_select_double_click), dateentry);
617 
618 	g_signal_connect (priv->BT_today, "clicked",
619 				G_CALLBACK (gtk_date_entry_cb_today_clicked), dateentry);
620 
621 }
622 
623 
624 GtkWidget *
gtk_date_entry_new(GtkWidget * label)625 gtk_date_entry_new (GtkWidget *label)
626 {
627 GtkDateEntry *dateentry;
628 
629 	DB( g_print("\n[dateentry] new\n") );
630 
631 	dateentry = g_object_new (GTK_TYPE_DATE_ENTRY, NULL);
632 
633 	if(dateentry)
634 	{
635 	GtkDateEntryPrivate *priv = dateentry->priv;
636 
637 		if(label)
638 			gtk_label_set_mnemonic_widget (GTK_LABEL(label), priv->entry);
639 	}
640 	return GTK_WIDGET(dateentry);
641 }
642 
643 
644 /*
645 **
646 */
647 void
gtk_date_entry_set_mindate(GtkDateEntry * dateentry,guint32 julian_days)648 gtk_date_entry_set_mindate(GtkDateEntry *dateentry, guint32 julian_days)
649 {
650 GtkDateEntryPrivate *priv = dateentry->priv;
651 
652 	DB( g_print("\n[dateentry] set mindate\n") );
653 
654 	g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry));
655 
656 	if(g_date_valid_julian(julian_days))
657 	{
658 		g_date_set_julian (&priv->mindate, julian_days);
659 	}
660 }
661 
662 
663 /*
664 **
665 */
666 void
gtk_date_entry_set_maxdate(GtkDateEntry * dateentry,guint32 julian_days)667 gtk_date_entry_set_maxdate(GtkDateEntry *dateentry, guint32 julian_days)
668 {
669 GtkDateEntryPrivate *priv = dateentry->priv;
670 
671 	DB( g_print("\n[dateentry] set maxdate\n") );
672 
673 	g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry));
674 
675 	if(g_date_valid_julian(julian_days))
676 	{
677 		g_date_set_julian (&priv->maxdate, julian_days);
678 	}
679 }
680 
681 
682 /*
683 **
684 */
685 void
gtk_date_entry_set_date(GtkDateEntry * dateentry,guint32 julian_days)686 gtk_date_entry_set_date(GtkDateEntry *dateentry, guint32 julian_days)
687 {
688 GtkDateEntryPrivate *priv = dateentry->priv;
689 
690 	DB( g_print("\n[dateentry] set date\n") );
691 
692 	g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry));
693 
694 	if(g_date_valid_julian(julian_days))
695 	{
696 		g_date_set_julian (priv->date, julian_days);
697 	}
698 	else
699 	{
700 		g_date_set_time_t(priv->date, time(NULL));
701 	}
702 	eval_date(dateentry);
703 }
704 
705 
706 /*
707 **
708 */
709 guint32
gtk_date_entry_get_date(GtkDateEntry * dateentry)710 gtk_date_entry_get_date(GtkDateEntry *dateentry)
711 {
712 GtkDateEntryPrivate *priv = dateentry->priv;
713 
714 	DB( g_print("\n[dateentry] get date\n") );
715 
716 	g_return_val_if_fail (GTK_IS_DATE_ENTRY (dateentry), 0);
717 
718 	return(g_date_get_julian(priv->date));
719 }
720 
721 
722 GDateWeekday
gtk_date_entry_get_weekday(GtkDateEntry * dateentry)723 gtk_date_entry_get_weekday(GtkDateEntry *dateentry)
724 {
725 GtkDateEntryPrivate *priv = dateentry->priv;
726 
727 	DB( g_print("\n[dateentry] get weekday\n") );
728 
729 	g_return_val_if_fail (GTK_IS_DATE_ENTRY (dateentry), 0);
730 
731 	return(g_date_get_weekday(priv->date));
732 }
733