GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-cell-renderer-date.c
1 /*************************************************************************
2  * The following code has come from Planner. This code implements a
3  * GtkCalendar in a custom GtkCellEditable popup from GtkCellRenderer.
4  *
5  * These files have been renamed and changed to remove code not required
6  * and to remove a dependency on libplanner.
7  *
8  * Copyright (C) 2012 Robert Fewell
9  *
10  * Copyright (C) 2005 Imendio AB
11  * Copyright (C) 2001-2002 CodeFactory AB
12  * Copyright (C) 2001-2002 Richard Hult <[email protected]>
13  * Copyright (C) 2001-2002 Mikael Hallendal <[email protected]>
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License as
17  * published by the Free Software Foundation; either version 2 of the
18  * License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23  * General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public
26  * License along with this program; if not, write to the
27  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
28  * Boston, MA 02111-1307, USA.
29  **************************************************************************/
30 #include "config.h"
31 
32 #include <gtk/gtk.h>
33 #include <glib/gi18n.h>
34 #include <gdk/gdkkeysyms.h>
35 #include <string.h>
36 #include <time.h>
37 
38 #include "gnc-cell-renderer-date.h"
39 #include "gnc-cell-renderer-popup-entry.h"
40 #include "gnc-date.h"
41 
42 enum {
43  PROP_0,
44  PROP_USE_BUTTONS,
45 };
46 
47 static void gcrd_init (GncCellRendererDate *date);
48 
49 static void gcrd_class_init (GncCellRendererDateClass *klass);
50 
51 static void gcrd_set_property (GObject *object,
52  guint param_id,
53  const GValue *value,
54  GParamSpec *pspec);
55 
56 static void gcrd_get_property (GObject *object,
57  guint param_id,
58  GValue *value,
59  GParamSpec *pspec);
60 
61 static void gcrd_today_clicked (GtkWidget *button,
62  GncCellRendererDate *cell);
63 
64 static void gcrd_selected_double_click (GtkWidget *calendar,
65  GncCellRendererDate *cell);
66 
67 static void gcrd_cancel_clicked (GtkWidget *popup_window,
68  GncCellRendererDate *cell);
69 
70 static void gcrd_ok_clicked (GtkWidget *popup_window,
71  GncCellRendererDate *cell);
72 
73 static void gcrd_day_selected (GtkWidget *popup_window,
74  GncCellRendererDate *cell);
75 
76 GtkCellEditable *gcrd_start_editing (GtkCellRenderer *cell,
77  GdkEvent *event,
78  GtkWidget *widget,
79  const gchar *path,
80  GdkRectangle *background_area,
81  GdkRectangle *cell_area,
82  GtkCellRendererState flags);
83 
84 static void gcrd_show (GncCellRendererPopup *cell,
85  const gchar *path,
86  gint x1,
87  gint y1,
88  gint x2,
89  gint y2);
90 static void gcrd_hide (GncCellRendererPopup *cell);
91 
92 
93 /* These two functions are used internally */
94 gboolean gcrd_time2dmy (time64 raw_time, gint *day, gint *month, gint *year);
95 static time64 gcrd_dmy2time (gint day, gint month, gint year);
96 
97 /* These two functions convert string to date to string */
98 static gchar * gcrd_time2dmy_string (time64 raw_time);
99 static time64 gcrd_string_dmy2time (const gchar *date_string);
100 
101 
102 static GncCellRendererPopupClass *parent_class;
103 
104 GType
105 gnc_cell_renderer_date_get_type (void)
106 {
107  static GType cell_text_type = 0;
108 
109  if (!cell_text_type) {
110  static const GTypeInfo cell_text_info = {
111  sizeof (GncCellRendererDateClass),
112  NULL, /* base_init */
113  NULL, /* base_finalize */
114  (GClassInitFunc) gcrd_class_init,
115  NULL, /* class_finalize */
116  NULL, /* class_data */
117  sizeof (GncCellRendererDate),
118  0, /* n_preallocs */
119  (GInstanceInitFunc) gcrd_init,
120  };
121 
122  cell_text_type = g_type_register_static (GNC_TYPE_CELL_RENDERER_POPUP,
123  "GncCellRendererDate",
124  &cell_text_info,
125  0);
126  }
127 
128  return cell_text_type;
129 }
130 
131 static void
132 gcrd_init (GncCellRendererDate *date)
133 {
134  GncCellRendererPopup *popup;
135  GtkWidget *frame;
136  GtkWidget *vbox;
137  GtkWidget *bbox;
138  GtkWidget *button;
139 
140  popup = GNC_CELL_RENDERER_POPUP (date);
141 
142  frame = gtk_frame_new (NULL);
143  gtk_container_add (GTK_CONTAINER (popup->popup_window), frame);
144  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
145 
146  vbox = gtk_vbox_new (FALSE, 6);
147  gtk_container_add (GTK_CONTAINER (frame), vbox);
148  gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
149 
150  date->calendar = gtk_calendar_new ();
151  popup->focus_window = date->calendar;
152  gtk_box_pack_start (GTK_BOX (vbox), date->calendar, TRUE, TRUE, 0);
153 
154  date->button_box = gtk_hbutton_box_new ();
155  gtk_box_set_spacing (GTK_BOX (date->button_box), 6);
156  gtk_box_pack_start (GTK_BOX (vbox), date->button_box, FALSE, FALSE, 0);
157 
158  button = gtk_button_new_with_label (_("Cancel"));
159  gtk_container_add (GTK_CONTAINER (date->button_box), button);
160  g_signal_connect (button, "clicked",
161  G_CALLBACK (gcrd_cancel_clicked),
162  date);
163 
164  date->today_button = gtk_button_new_with_label (_("Today"));
165  gtk_container_add (GTK_CONTAINER (date->button_box), date->today_button);
166  g_signal_connect (date->today_button, "clicked",
167  G_CALLBACK (gcrd_today_clicked),
168  date);
169 
170  button = gtk_button_new_with_label (_("Select"));
171  gtk_container_add (GTK_CONTAINER (date->button_box), button);
172  g_signal_connect (button, "clicked",
173  G_CALLBACK (gcrd_ok_clicked),
174  date);
175 
176  g_signal_connect (date->calendar, "day-selected",
177  G_CALLBACK (gcrd_day_selected),
178  date);
179  g_signal_connect (date->calendar, "day-selected-double-click",
180  G_CALLBACK (gcrd_selected_double_click),
181  date);
182 
183  //Set calendar to show current date when displayed
184  date->time = gnc_time (NULL);
185 
186  gtk_widget_show_all (frame);
187 }
188 
189 static void
190 gcrd_class_init (GncCellRendererDateClass *klass)
191 {
192  GncCellRendererPopupClass *popup_class;
193  GtkCellRendererClass *cell_class;
194  GObjectClass *gobject_class;
195 
196  popup_class = GNC_CELL_RENDERER_POPUP_CLASS (klass);
197  cell_class = GTK_CELL_RENDERER_CLASS (klass);
198  parent_class = GNC_CELL_RENDERER_POPUP_CLASS (g_type_class_peek_parent (klass));
199  gobject_class = G_OBJECT_CLASS (klass);
200 
201  gobject_class->set_property = gcrd_set_property;
202  gobject_class->get_property = gcrd_get_property;
203 
204  cell_class->start_editing = gcrd_start_editing;
205 
206  popup_class->show_popup = gcrd_show;
207  popup_class->hide_popup = gcrd_hide;
208 
209  g_object_class_install_property (
210  gobject_class,
211  PROP_USE_BUTTONS,
212  g_param_spec_boolean ("use-buttons",
213  NULL,
214  NULL,
215  TRUE,
216  G_PARAM_READWRITE));
217 
218 }
219 
220 static void
221 gcrd_set_property (GObject *object,
222  guint param_id,
223  const GValue *value,
224  GParamSpec *pspec)
225 {
226  GncCellRendererDate *date;
227 
228  date = GNC_CELL_RENDERER_DATE (object);
229 
230  switch (param_id) {
231  case PROP_USE_BUTTONS:
232  date->use_buttons = g_value_get_boolean (value);
233 
234  if (date->use_buttons)
235  gtk_widget_show (date->button_box);
236  else
237  gtk_widget_hide (date->button_box);
238  break;
239 
240  default:
241  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
242  break;
243  }
244 }
245 
246 static void
247 gcrd_get_property (GObject *object,
248  guint param_id,
249  GValue *value,
250  GParamSpec *pspec)
251 {
252  GncCellRendererDate *date;
253 
254  date = GNC_CELL_RENDERER_DATE (object);
255 
256  switch (param_id) {
257  case PROP_USE_BUTTONS:
258  g_value_set_boolean (value, date->use_buttons);
259  break;
260 
261  default:
262  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
263  break;
264  }
265 }
266 
267 GtkCellEditable *
268 gcrd_start_editing (GtkCellRenderer *cell,
269  GdkEvent *event,
270  GtkWidget *widget,
271  const gchar *path,
272  GdkRectangle *background_area,
273  GdkRectangle *cell_area,
274  GtkCellRendererState flags)
275 {
276  GNC_CELL_RENDERER_POPUP (cell)->editing_canceled = FALSE;
277 
278  if (GTK_CELL_RENDERER_CLASS (parent_class)->start_editing) {
279  return GTK_CELL_RENDERER_CLASS (parent_class)->start_editing (
280  cell,
281  event,
282  widget,
283  path,
284  background_area,
285  cell_area,
286  flags);
287  }
288 
289  return NULL;
290 }
291 
292 
293 static void
294 gcrd_hide (GncCellRendererPopup *cell)
295 {
296  if (parent_class->hide_popup) {
297  parent_class->hide_popup (cell);
298  }
299 }
300 
301 static void
302 gcrd_show (GncCellRendererPopup *cell,
303  const gchar *path,
304  gint x1,
305  gint y1,
306  gint x2,
307  gint y2)
308 {
309  GncCellRendererDate *date;
310  gint year;
311  gint month;
312  gint day;
313  gint index;
314  const gchar *text;
315 
316  if (parent_class->show_popup) {
317  parent_class->show_popup (cell,
318  path,
319  x1, y1,
320  x2, y2);
321  }
322 
323  date = GNC_CELL_RENDERER_DATE (cell);
324 
325  text = gnc_popup_entry_get_text (GNC_POPUP_ENTRY (GNC_CELL_RENDERER_POPUP (cell)->editable));
326 
327  if (!(g_strcmp0(text, "")))
328  {
329  date->time = gnc_time (NULL);
330  gcrd_time2dmy ( date->time, &day, &month, &year);
331  }
332  else
333  {
334  date->time = gcrd_string_dmy2time (text);
335  gcrd_time2dmy ( date->time, &day, &month, &year);
336  }
337 
338  gtk_calendar_clear_marks (GTK_CALENDAR (date->calendar));
339  gtk_calendar_select_month (GTK_CALENDAR (date->calendar), month - 1, year);
340 
341  gtk_calendar_select_day (GTK_CALENDAR (date->calendar), day);
342  gtk_calendar_mark_day (GTK_CALENDAR (date->calendar), day);
343 
344 }
345 
346 GtkCellRenderer *
347 gnc_cell_renderer_date_new (gboolean use_buttons)
348 {
349  GObject *cell;
350 
351  cell = g_object_new (GNC_TYPE_CELL_RENDERER_DATE,
352  "use-buttons", use_buttons,
353  NULL);
354 
355  return GTK_CELL_RENDERER (cell);
356 }
357 
358 static void
359 gcrd_today_clicked (GtkWidget *button, GncCellRendererDate *cell)
360 {
361  time64 today;
362  gint year, month, day;
363 
364  today = gnc_time (NULL);
365 
366  gcrd_time2dmy ( today, &day, &month, &year);
367 
368  gtk_calendar_clear_marks (GTK_CALENDAR (cell->calendar));
369  gtk_calendar_select_month (GTK_CALENDAR (cell->calendar), month - 1, year);
370  gtk_calendar_select_day (GTK_CALENDAR (cell->calendar), day);
371  gtk_calendar_mark_day (GTK_CALENDAR (cell->calendar), day);
372 }
373 
374 static void
375 gcrd_selected_double_click (GtkWidget *calendar, GncCellRendererDate *cell)
376 {
377  GncCellRendererPopup *popup;
378 
379  popup = GNC_CELL_RENDERER_POPUP (cell);
380 
381  gcrd_ok_clicked (popup->popup_window, cell);
382 }
383 
384 static void
385 gcrd_cancel_clicked (GtkWidget *popup_window, GncCellRendererDate *cell)
386 {
387  GncCellRendererPopup *popup;
388 
389  popup = GNC_CELL_RENDERER_POPUP (cell);
390 
391  popup->editing_canceled = TRUE;
392  gnc_cell_renderer_popup_hide (popup);
393 }
394 
395 static void
396 gcrd_ok_clicked (GtkWidget *popup_window, GncCellRendererDate *cell)
397 {
398  GncCellRendererPopup *popup;
399 
400  popup = GNC_CELL_RENDERER_POPUP (cell);
401 
402  gcrd_day_selected (popup_window, cell);
403 
404  popup->editing_canceled = FALSE;
405  gnc_cell_renderer_popup_hide (popup);
406 }
407 
408 static void
409 gcrd_day_selected (GtkWidget *popup_window, GncCellRendererDate *cell)
410 {
411  guint year;
412  guint month;
413  guint day;
414  time64 t;
415  gchar *str;
416 
417  gtk_calendar_get_date (GTK_CALENDAR (cell->calendar),
418  &year,
419  &month,
420  &day);
421 
422  t = gcrd_dmy2time ( day, month + 1, year);
423 
424  cell->time = t;
425 
426  str = gcrd_time2dmy_string (t);
427 
428  gnc_popup_entry_set_text (
429  GNC_POPUP_ENTRY (GNC_CELL_RENDERER_POPUP (cell)->editable), str);
430  g_free (str);
431 
432 }
433 
434 static gboolean
435 gcrd_grab_on_window (GdkWindow *window,
436  guint32 activate_time)
437 {
438  if ((gdk_pointer_grab (window, TRUE,
439  GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
440  GDK_POINTER_MOTION_MASK,
441  NULL, NULL, activate_time) == 0)) {
442  if (gdk_keyboard_grab (window, TRUE,
443  activate_time) == 0)
444  return TRUE;
445  else {
446  gdk_pointer_ungrab (activate_time);
447  return FALSE;
448  }
449  }
450 
451  return FALSE;
452 }
453 
454 
455 /* This function converts a time64 value date to separate entities */
456 gboolean
457 gcrd_time2dmy (time64 raw_time, gint *day, gint *month, gint *year)
458 {
459  struct tm * timeinfo;
460 
461  timeinfo = gnc_localtime (&raw_time);
462 
463  *day = timeinfo->tm_mday;
464  *month = timeinfo->tm_mon + 1;
465  *year = timeinfo->tm_year + 1900;
466  gnc_tm_free (timeinfo);
467  return TRUE;
468 }
469 
470 /* This function converts separate entities to a time64 value */
471 static time64
472 gcrd_dmy2time (gint day, gint month, gint year)
473 {
474  struct tm when;
475 
476  memset (&when, 0, sizeof (when));
477  when.tm_year = year - 1900;
478  when.tm_mon = month - 1 ;
479  when.tm_mday = day;
480 
481  return gnc_mktime (&when);
482 }
483 
484 
485 /* This function converts a time64 value date to a string */
486 static gchar *
487 gcrd_time2dmy_string (time64 raw_time)
488 {
489  return qof_print_date (raw_time);
490 }
491 
492 
493 /* This function converts a string date to a time64 value */
494 static time64
495 gcrd_string_dmy2time (const gchar *date_string)
496 {
497  gint year = 0, month = 0, day = 0;
498 
499  if(qof_scan_date (date_string, &day, &month, &year))
500  {
501  struct tm when;
502  memset (&when, 0, sizeof (when));
503  when.tm_year = year - 1900;
504  when.tm_mon = month - 1 ;
505  when.tm_mday = day;
506 
507  return gnc_mktime (&when);
508  }
509  else
510  {
511  return gnc_time (NULL);
512  }
513 }
514 
515 
516 
517 
518 
Date and Time handling routines.
void gnc_tm_free(struct tm *time)
free a struct tm* created with gnc_localtime() or gnc_gmtime()
char * qof_print_date(time64 secs)
time64 gnc_mktime(struct tm *time)
calculate seconds from the epoch given a time struct
struct tm * gnc_localtime(const time64 *secs)
fill out a time struct from a 64-bit time value.
gboolean qof_scan_date(const char *buff, int *day, int *month, int *year)
time64 gnc_time(time64 *tbuf)
get the current local time
gint64 time64
Definition: gnc-date.h:83