1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2018 Maxime DOYEN
4 * This file is part of HomeBank.
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.
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.
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/>.
25 #include <gdk/gdkkeysyms.h>
27 #include "gtk-dateentry.h"
49 static guint dateentry_signals
[LAST_SIGNAL
] = {0,};
52 G_DEFINE_TYPE(GtkDateEntry
, gtk_date_entry
, GTK_TYPE_BOX
)
58 update_text(GtkDateEntry
*self
)
60 GtkDateEntryPrivate
*priv
= self
->priv
;
63 DB( g_print("\n[dateentry] update text\n") );
65 g_date_strftime (label
, 17 - 1, "%x", priv
->date
);
66 gtk_entry_set_text (GTK_ENTRY (priv
->entry
), label
);
67 DB( g_print(" = %s\n", label
) );
72 eval_date(GtkDateEntry
*self
)
74 GtkDateEntryPrivate
*priv
= self
->priv
;
76 g_date_clamp(priv
->date
, &priv
->mindate
, &priv
->maxdate
);
80 if(priv
->lastdate
!= g_date_get_julian(priv
->date
))
82 DB( g_print(" **emit 'changed' signal**\n") );
83 g_signal_emit_by_name (self
, "changed", NULL
, NULL
);
86 priv
->lastdate
= g_date_get_julian(priv
->date
);
90 parse_date(GtkDateEntry
*self
)
92 GtkDateEntryPrivate
*priv
= self
->priv
;
94 DB( g_print("\n[dateentry] parse date\n") );
96 g_date_set_parse (priv
->date
, gtk_entry_get_text (GTK_ENTRY (priv
->entry
)));
97 if(!g_date_valid(priv
->date
))
99 g_date_set_time_t(priv
->date
, time(NULL
));
106 gtk_date_entry_cb_calendar_day_selected(GtkWidget
* calendar
, GtkDateEntry
* dateentry
)
108 GtkDateEntryPrivate
*priv
= dateentry
->priv
;
109 guint year
, month
, day
;
111 DB( g_print("\n[dateentry] calendar_day_selected\n") );
113 gtk_calendar_get_date (GTK_CALENDAR (priv
->calendar
), &year
, &month
, &day
);
114 g_date_set_dmy (priv
->date
, day
, month
+ 1, year
);
115 eval_date(dateentry
);
120 gtk_date_entry_cb_calendar_day_select_double_click(GtkWidget
* calendar
, gpointer user_data
)
122 GtkDateEntry
*dateentry
= user_data
;
123 GtkDateEntryPrivate
*priv
= dateentry
->priv
;
125 DB( g_print("\n[dateentry] calendar_day_select_double_click\n") );
127 gtk_widget_hide (priv
->popover
);
134 gtk_date_entry_cb_calendar_monthyear(GtkWidget
*calendar
, GtkDateEntry
*dateentry
)
136 GtkDateEntryPrivate
*priv
= dateentry
->priv
;
137 guint year
, month
, day
;
139 DB( g_print("\n[dateentry] cb_calendar_monthyear\n") );
141 gtk_calendar_get_date (GTK_CALENDAR (priv
->calendar
), &year
, &month
, &day
);
143 g_object_set(calendar
, "year", 1900, NULL
);
146 g_object_set(calendar
, "year", 2200, NULL
);
152 gtk_date_entry_cb_entry_key_pressed (GtkWidget
*widget
, GdkEventKey
*event
, gpointer user_data
)
154 GtkDateEntry
*dateentry
= user_data
;
155 GtkDateEntryPrivate
*priv
= dateentry
->priv
;
157 DB( g_print("\n[dateentry] entry key pressed: state=%04x, keyval=%04x\n", event
->state
, event
->keyval
) );
159 if( event
->keyval
== GDK_KEY_Up
)
161 if( !(event
->state
& (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
)) )
163 g_date_add_days (priv
->date
, 1);
164 eval_date(dateentry
);
167 if( event
->state
& GDK_SHIFT_MASK
)
169 g_date_add_months (priv
->date
, 1);
170 eval_date(dateentry
);
173 if( event
->state
& GDK_CONTROL_MASK
)
175 g_date_add_years (priv
->date
, 1);
176 eval_date(dateentry
);
181 if( event
->keyval
== GDK_KEY_Down
)
183 if( !(event
->state
& (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
)) )
185 g_date_subtract_days (priv
->date
, 1);
186 eval_date(dateentry
);
189 if( event
->state
& GDK_SHIFT_MASK
)
191 g_date_subtract_months (priv
->date
, 1);
192 eval_date(dateentry
);
195 if( event
->state
& GDK_CONTROL_MASK
)
197 g_date_subtract_years (priv
->date
, 1);
198 eval_date(dateentry
);
208 gtk_date_entry_cb_entry_activate(GtkWidget
*gtkentry
, gpointer user_data
)
210 GtkDateEntry
*dateentry
= user_data
;
212 DB( g_print("\n[dateentry] entry_activate\n") );
214 parse_date(dateentry
);
215 eval_date(dateentry
);
220 gtk_date_entry_cb_entry_focus_out(GtkWidget
*widget
, GdkEventFocus
*event
, gpointer user_data
)
222 GtkDateEntry
*dateentry
= user_data
;
224 DB( g_print("\n[dateentry] entry focus-out-event %d\n", gtk_widget_is_focus(GTK_WIDGET(dateentry
))) );
226 parse_date(dateentry
);
227 eval_date(dateentry
);
233 gtk_date_entry_cb_button_clicked (GtkWidget
* widget
, GtkDateEntry
* dateentry
)
235 GtkDateEntryPrivate
*priv
= dateentry
->priv
;
239 DB( g_print("\n[dateentry] button_clicked\n") );
241 /* GtkCalendar expects month to be in 0-11 range (inclusive) */
242 month
= g_date_get_month (priv
->date
) - 1;
244 g_signal_handler_block(priv
->calendar
, priv
->hid_dayselect
);
246 gtk_calendar_select_month (GTK_CALENDAR (priv
->calendar
),
247 CLAMP (month
, 0, 11),
248 g_date_get_year (priv
->date
));
249 gtk_calendar_select_day (GTK_CALENDAR (priv
->calendar
),
250 g_date_get_day (priv
->date
));
252 g_signal_handler_unblock(priv
->calendar
, priv
->hid_dayselect
);
254 gtk_popover_set_relative_to (GTK_POPOVER (priv
->popover
), GTK_WIDGET (priv
->entry
));
255 //gtk_widget_get_clip(priv->arrow, &rect);
256 //gtk_popover_set_pointing_to (GTK_POPOVER (priv->popover), &rect);
258 gtk_widget_show_all (priv
->popover
);
263 gtk_date_entry_destroy (GtkWidget
*object
)
265 GtkDateEntry
*dateentry
= GTK_DATE_ENTRY (object
);
266 GtkDateEntryPrivate
*priv
= dateentry
->priv
;
268 g_return_if_fail(object
!= NULL
);
269 g_return_if_fail(GTK_IS_DATE_ENTRY(object
));
271 DB( g_print("\n[dateentry] destroy\n") );
273 DB( g_print(" free gtkentry: %p\n", priv
->entry
) );
274 DB( g_print(" free arrow: %p\n", priv
->button
) );
276 DB( g_print(" free dateentry: %p\n", dateentry
) );
279 g_date_free(priv
->date
);
282 GTK_WIDGET_CLASS (gtk_date_entry_parent_class
)->destroy (object
);
288 gtk_date_entry_dispose (GObject
*gobject
)
290 //GtkDateEntry *self = GTK_DATE_ENTRY (gobject);
292 DB( g_print("\n[dateentry] dispose\n") );
295 //g_clear_object (&self->priv->an_object);
297 G_OBJECT_CLASS (gtk_date_entry_parent_class
)->dispose (gobject
);
304 gtk_date_entry_finalize (GObject
*gobject
)
306 //GtkDateEntry *self = GTK_DATE_ENTRY (gobject);
308 DB( g_print("\n[dateentry] finalize\n") );
311 //g_date_free(self->date);
312 //g_free (self->priv->a_string);
314 /* Always chain up to the parent class; as with dispose(), finalize()
315 * is guaranteed to exist on the parent's class virtual function table
317 G_OBJECT_CLASS(gtk_date_entry_parent_class
)->finalize (gobject
);
323 gtk_date_entry_class_init (GtkDateEntryClass
*class)
325 GObjectClass
*object_class
;
326 GtkWidgetClass
*widget_class
;
328 object_class
= G_OBJECT_CLASS (class);
329 widget_class
= GTK_WIDGET_CLASS (class);
331 DB( g_print("\n[dateentry] class_init\n") );
333 //object_class->constructor = gtk_date_entry_constructor;
334 //object_class->set_property = gtk_date_entry_set_property;
335 //object_class->get_property = gtk_date_entry_get_property;
336 object_class
->dispose
= gtk_date_entry_dispose
;
337 object_class
->finalize
= gtk_date_entry_finalize
;
339 widget_class
->destroy
= gtk_date_entry_destroy
;
341 dateentry_signals
[CHANGED
] =
342 g_signal_new ("changed",
343 G_TYPE_FROM_CLASS (class),
345 G_STRUCT_OFFSET (GtkDateEntryClass
, changed
),
347 g_cclosure_marshal_VOID__VOID
,
350 g_type_class_add_private (object_class
, sizeof (GtkDateEntryPrivate
));
355 gtk_date_entry_init (GtkDateEntry
*dateentry
)
357 GtkDateEntryPrivate
*priv
;
359 DB( g_print("\n[dateentry] init\n") );
361 /* yes, also priv, need to keep the code readable */
362 dateentry
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (dateentry
,
364 GtkDateEntryPrivate
);
365 priv
= dateentry
->priv
;
367 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(dateentry
)), GTK_STYLE_CLASS_LINKED
);
369 priv
->entry
= gtk_entry_new ();
370 gtk_entry_set_width_chars(GTK_ENTRY(priv
->entry
), 16);
371 gtk_entry_set_max_width_chars(GTK_ENTRY(priv
->entry
), 16);
372 gtk_box_pack_start (GTK_BOX (dateentry
), priv
->entry
, TRUE
, TRUE
, 0);
374 priv
->button
= gtk_button_new ();
375 priv
->arrow
= gtk_image_new_from_icon_name ("pan-down-symbolic", GTK_ICON_SIZE_BUTTON
);
376 gtk_container_add (GTK_CONTAINER (priv
->button
), priv
->arrow
);
377 gtk_box_pack_end (GTK_BOX (dateentry
), priv
->button
, FALSE
, FALSE
, 0);
379 priv
->popover
= gtk_popover_new (priv
->button
);
380 gtk_popover_set_position(GTK_POPOVER(priv
->popover
), GTK_POS_BOTTOM
);
381 gtk_container_set_border_width (GTK_CONTAINER (priv
->popover
), 6);
382 priv
->calendar
= gtk_calendar_new ();
383 gtk_container_add (GTK_CONTAINER (priv
->popover
), priv
->calendar
);
385 gtk_widget_show_all (GTK_WIDGET(dateentry
));
387 /* initialize datas */
388 priv
->date
= g_date_new();
389 g_date_set_time_t(priv
->date
, time(NULL
));
390 g_date_set_dmy(&priv
->mindate
, 1, 1, 1900); //693596
391 g_date_set_dmy(&priv
->maxdate
, 31, 12, 2200); //803533
392 update_text(dateentry
);
395 g_signal_connect (priv
->entry
, "key-press-event",
396 G_CALLBACK (gtk_date_entry_cb_entry_key_pressed
), dateentry
);
398 g_signal_connect_after (priv
->entry
, "focus-out-event",
399 G_CALLBACK (gtk_date_entry_cb_entry_focus_out
), dateentry
);
401 g_signal_connect (priv
->entry
, "activate",
402 G_CALLBACK (gtk_date_entry_cb_entry_activate
), dateentry
);
405 g_signal_connect (priv
->button
, "clicked",
406 G_CALLBACK (gtk_date_entry_cb_button_clicked
), dateentry
);
409 g_signal_connect (priv
->calendar
, "prev-year",
410 G_CALLBACK (gtk_date_entry_cb_calendar_monthyear
), dateentry
);
411 g_signal_connect (priv
->calendar
, "next-year",
412 G_CALLBACK (gtk_date_entry_cb_calendar_monthyear
), dateentry
);
413 g_signal_connect (priv
->calendar
, "prev-month",
414 G_CALLBACK (gtk_date_entry_cb_calendar_monthyear
), dateentry
);
415 g_signal_connect (priv
->calendar
, "next-month",
416 G_CALLBACK (gtk_date_entry_cb_calendar_monthyear
), dateentry
);
418 priv
->hid_dayselect
= g_signal_connect (priv
->calendar
, "day-selected",
419 G_CALLBACK (gtk_date_entry_cb_calendar_day_selected
), dateentry
);
421 g_signal_connect (priv
->calendar
, "day-selected-double-click",
422 G_CALLBACK (gtk_date_entry_cb_calendar_day_select_double_click
), dateentry
);
428 gtk_date_entry_new ()
430 GtkDateEntry
*dateentry
;
432 DB( g_print("\n[dateentry] new\n") );
434 dateentry
= g_object_new (GTK_TYPE_DATE_ENTRY
, NULL
);
436 return GTK_WIDGET(dateentry
);
444 gtk_date_entry_set_mindate(GtkDateEntry
*dateentry
, guint32 julian_days
)
446 GtkDateEntryPrivate
*priv
= dateentry
->priv
;
448 DB( g_print("\n[dateentry] set mindate\n") );
450 g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry
));
452 if(g_date_valid_julian(julian_days
))
454 g_date_set_julian (&priv
->mindate
, julian_days
);
463 gtk_date_entry_set_maxdate(GtkDateEntry
*dateentry
, guint32 julian_days
)
465 GtkDateEntryPrivate
*priv
= dateentry
->priv
;
467 DB( g_print("\n[dateentry] set maxdate\n") );
469 g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry
));
471 if(g_date_valid_julian(julian_days
))
473 g_date_set_julian (&priv
->maxdate
, julian_days
);
482 gtk_date_entry_set_date(GtkDateEntry
*dateentry
, guint32 julian_days
)
484 GtkDateEntryPrivate
*priv
= dateentry
->priv
;
486 DB( g_print("\n[dateentry] set date\n") );
488 g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry
));
490 if(g_date_valid_julian(julian_days
))
492 g_date_set_julian (priv
->date
, julian_days
);
496 g_date_set_time_t(priv
->date
, time(NULL
));
498 eval_date(dateentry
);
506 gtk_date_entry_get_date(GtkDateEntry
*dateentry
)
508 GtkDateEntryPrivate
*priv
= dateentry
->priv
;
510 DB( g_print("\n[dateentry] get date\n") );
512 g_return_val_if_fail (GTK_IS_DATE_ENTRY (dateentry
), 0);
514 return(g_date_get_julian(priv
->date
));