From 67b79526154f8dc9c895baa0ff4d90f213961c26 Mon Sep 17 00:00:00 2001 From: Dave Peticolas Date: Mon, 24 Apr 2000 23:20:36 +0000 Subject: [PATCH] Added a date entry widget specific to GnuCash. It uses the date format set in the preferences menu. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@2205 57a11ea4-9604-0410-9ed3-97b8803252fd --- ChangeLog | 12 + src/engine/date.c | 6 +- src/engine/util.c | 4 +- src/gnome/Makefile.in | 5 +- src/gnome/dialog-options.c | 11 +- src/gnome/dialog-transfer.c | 5 +- src/gnome/gnc-dateedit.c | 745 ++++++++++++++++++++++++++++++++++++ src/gnome/gnc-dateedit.h | 101 +++++ src/gnome/gnc-dialogs.glade | 65 +++- src/gnome/window-adjust.c | 5 +- src/gnome/window-register.c | 29 +- 11 files changed, 937 insertions(+), 51 deletions(-) create mode 100644 src/gnome/gnc-dateedit.c create mode 100644 src/gnome/gnc-dateedit.h diff --git a/ChangeLog b/ChangeLog index 9cf5c338da..b4f3738d37 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,17 @@ 2000-04-24 Dave Peticolas + * src/gnome/dialog-options.c: modified to use gnc-dateedit. + + * src/gnome/window-adjust.c: modified to use gnc-dateedit. + + * src/gnome/window-register.c: modified to use gnc-dateedit. + + * src/gnome/dialog-transfer.c: modified to use gnc-dateedit. + + * src/gnome/gnc-dateedit.c: new file. gnome date editor modified + to use gnucash date printing and parsing routines. I plan on + extending this with additional features, too. + * src/engine/Group.c (xaccMallocAccountGroup): loop until we get a unique id. This is just paranoia code. Ditto for Account.c and Transaction.c. diff --git a/src/engine/date.c b/src/engine/date.c index 798a3b9cf5..9d4b304268 100644 --- a/src/engine/date.c +++ b/src/engine/date.c @@ -100,8 +100,7 @@ printDate (char * buff, int day, int month, int year) * right. */ switch(dateFormat) - { - + { case DATE_FORMAT_UK: sprintf (buff, "%2d/%2d/%-4d", day, month, year); break; @@ -127,8 +126,7 @@ printDate (char * buff, int day, int month, int year) default: sprintf (buff, "%2d/%2d/%-4d", month, day, year); break; - } - return; + } } void diff --git a/src/engine/util.c b/src/engine/util.c index 9298ece7ff..25846a0143 100644 --- a/src/engine/util.c +++ b/src/engine/util.c @@ -424,8 +424,8 @@ xaccSPrintAmountGeneral (char * bufp, double val, short shrs, int precision, struct lconv *lc; char *orig_bufp = bufp; - char *currency_symbol; - char *sign; + const char *currency_symbol; + const char *sign; char cs_precedes; char sep_by_space; diff --git a/src/gnome/Makefile.in b/src/gnome/Makefile.in index 5ea121b712..b700d40de5 100644 --- a/src/gnome/Makefile.in +++ b/src/gnome/Makefile.in @@ -69,7 +69,7 @@ GNOME_SRCS := top-level.c window-main.c window-register.c window-adjust.c \ dialog-options.c dialog-filebox.c dialog-transfer.c \ dialog-add.c dialog-edit.c dialog-utils.c \ extensions.c query-user.c reconcile-list.c \ - window-report.c global-options.c \ + window-report.c global-options.c gnc-dateedit.c \ dialog-qif-import.c glade-gnc-dialogs.c \ dialog-account-picker.c print-session.c \ dialog-print-check.c dialog-find-transactions.c @@ -88,6 +88,3 @@ gnome: @top_srcdir@/gnucash.gnome gnome.static: @top_srcdir@/gnucash.gnome.static @top_srcdir@/gnucash.gnome.static: ${GNOME_OBJS} ${OTHER_OBJS} $(CC) -static $(LDFLAGS) -o $@ $^ $(LIBS) - - - diff --git a/src/gnome/dialog-options.c b/src/gnome/dialog-options.c index 89de452cd3..acb0a5ce1d 100644 --- a/src/gnome/dialog-options.c +++ b/src/gnome/dialog-options.c @@ -27,6 +27,7 @@ #include "query-user.h" #include "gnc-helpers.h" #include "account-tree.h" +#include "gnc-dateedit.h" #include "global-options.h" #include "messages.h" #include "util.h" @@ -105,7 +106,7 @@ gnc_option_set_ui_value(GNCOption *option, gboolean use_default) if (gnc_timepair_p(value)) { ts = gnc_timepair2timespec(value); - gnome_date_edit_set_time(GNOME_DATE_EDIT(option->widget), ts.tv_sec); + gnc_date_edit_set_time(GNC_DATE_EDIT(option->widget), ts.tv_sec); } else bad_value = TRUE; @@ -249,7 +250,7 @@ gnc_option_get_ui_value(GNCOption *option) { Timespec ts; - ts.tv_sec = gnome_date_edit_get_date(GNOME_DATE_EDIT(option->widget)); + ts.tv_sec = gnc_date_edit_get_date(GNC_DATE_EDIT(option->widget)); ts.tv_nsec = 0; result = gnc_timespec2timepair(ts); @@ -830,19 +831,19 @@ gnc_option_set_ui_widget(GNCOption *option, use24 = gnc_lookup_boolean_option("International", "Use 24-hour time format", FALSE); - value = gnome_date_edit_new(time(NULL), show_time, use24); + value = gnc_date_edit_new(time(NULL), show_time, use24); option->widget = value; gnc_option_set_ui_value(option, FALSE); - entry = GNOME_DATE_EDIT(value)->date_entry; + entry = GNC_DATE_EDIT(value)->date_entry; gtk_tooltips_set_tip(tooltips, entry, documentation, NULL); gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(gnc_option_changed_cb), option); if (show_time) { - entry = GNOME_DATE_EDIT(value)->time_entry; + entry = GNC_DATE_EDIT(value)->time_entry; gtk_tooltips_set_tip(tooltips, entry, documentation, NULL); gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(gnc_option_changed_cb), option); diff --git a/src/gnome/dialog-transfer.c b/src/gnome/dialog-transfer.c index fa54c74790..cec88f49fa 100644 --- a/src/gnome/dialog-transfer.c +++ b/src/gnome/dialog-transfer.c @@ -29,6 +29,7 @@ #include "window-reconcile.h" #include "query-user.h" #include "account-tree.h" +#include "gnc-dateedit.h" #include "enriched-messages.h" #include "ui-callbacks.h" #include "util.h" @@ -226,7 +227,7 @@ gnc_xfer_dialog_create(GtkWidget * parent, Account * initial, gtk_misc_set_alignment(GTK_MISC(label), 0.95, 0.5); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - date = gnome_date_edit_new(time(NULL), FALSE, FALSE); + date = gnc_date_edit_new(time(NULL), FALSE, FALSE); gtk_box_pack_start(GTK_BOX(hbox), date, TRUE, TRUE, 0); xferData->date_entry = date; } @@ -365,7 +366,7 @@ gnc_xfer_dialog(GtkWidget * parent, Account * initial) string = gtk_entry_get_text(GTK_ENTRY(xferData.amount_entry)); amount = xaccParseAmount(string, GNC_T); - time = gnome_date_edit_get_date(GNOME_DATE_EDIT(xferData.date_entry)); + time = gnc_date_edit_get_date(GNC_DATE_EDIT(xferData.date_entry)); { Transaction *trans; diff --git a/src/gnome/gnc-dateedit.c b/src/gnome/gnc-dateedit.c new file mode 100644 index 0000000000..769d1f486d --- /dev/null +++ b/src/gnome/gnc-dateedit.c @@ -0,0 +1,745 @@ +/* + * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation + * All rights reserved. + * + * This file is part of the Gnome Library. + * + * The Gnome Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License + * as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The Gnome Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact: + * + * Free Software Foundation Voice: +1-617-542-5942 + * 59 Temple Place - Suite 330 Fax: +1-617-542-2652 + * Boston, MA 02111-1307, USA gnu@gnu.org + * + */ +/* + @NOTATION@ + */ + +/* + * Date editor widget + * + * Authors: Miguel de Icaza + * Dave Peticolas + */ + +#include +#include +#include /* atoi */ +#include /* isdigit */ +#include +#include + +#include "gnc-dateedit.h" +#include "date.h" + + +enum { + DATE_CHANGED, + TIME_CHANGED, + LAST_SIGNAL +}; + +static gint date_edit_signals [LAST_SIGNAL] = { 0 }; + + +static void gnc_date_edit_init (GNCDateEdit *gde); +static void gnc_date_edit_class_init (GNCDateEditClass *class); +static void gnc_date_edit_destroy (GtkObject *object); +static void gnc_date_edit_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callbabck_data); + +static GtkHBoxClass *parent_class; + +/** + * gnc_date_edit_get_type: + * + * Returns the GtkType for the GNCDateEdit widget + */ +guint +gnc_date_edit_get_type (void) +{ + static guint date_edit_type = 0; + + if (!date_edit_type){ + GtkTypeInfo date_edit_info = { + "GNCDateEdit", + sizeof (GNCDateEdit), + sizeof (GNCDateEditClass), + (GtkClassInitFunc) gnc_date_edit_class_init, + (GtkObjectInitFunc) gnc_date_edit_init, + NULL, + NULL, + }; + + date_edit_type = gtk_type_unique (gtk_hbox_get_type (), + &date_edit_info); + } + + return date_edit_type; +} + +static void +hide_popup (GNCDateEdit *gde) +{ + gtk_widget_hide (gde->cal_popup); + gtk_grab_remove (gde->cal_popup); + gdk_pointer_ungrab (GDK_CURRENT_TIME); +} + +static void +day_selected (GtkCalendar *calendar, GNCDateEdit *gde) +{ + char buffer [40]; + gint year, month, day; + + gtk_calendar_get_date (calendar, &year, &month, &day); + + printDate (buffer, day, month + 1, year); + gtk_entry_set_text (GTK_ENTRY (gde->date_entry), buffer); + gtk_signal_emit (GTK_OBJECT (gde), date_edit_signals [DATE_CHANGED]); +} + +static void +day_selected_double_click (GtkCalendar *calendar, GNCDateEdit *gde) +{ + hide_popup (gde); +} + +static gint +delete_popup (GtkWidget *widget, gpointer data) +{ + GNCDateEdit *gde; + + gde = data; + hide_popup (gde); + + return TRUE; +} + +static gint +key_press_popup (GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + GNCDateEdit *gde; + + if (event->keyval != GDK_Escape) + return FALSE; + + gde = data; + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + hide_popup (gde); + + return TRUE; +} + +/* This function is yanked from gtkcombo.c */ +static gint +button_press_popup (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + GNCDateEdit *gde; + GtkWidget *child; + + gde = data; + + child = gtk_get_event_widget ((GdkEvent *) event); + + /* We don't ask for button press events on the grab widget, so + * if an event is reported directly to the grab widget, it must + * be on a window outside the application (and thus we remove + * the popup window). Otherwise, we check if the widget is a child + * of the grab widget, and only remove the popup window if it + * is not. + */ + if (child != widget) { + while (child) { + if (child == widget) + return FALSE; + child = child->parent; + } + } + + hide_popup (gde); + + return TRUE; +} + +static void +position_popup (GNCDateEdit *gde) +{ + gint x, y; + gint bwidth, bheight; + + gtk_widget_size_request (gde->cal_popup, &gde->cal_popup->requisition); + + gdk_window_get_origin (gde->date_button->window, &x, &y); + gdk_window_get_size (gde->date_button->window, &bwidth, &bheight); + + x += bwidth - gde->cal_popup->requisition.width; + y += bheight; + + if (x < 0) + x = 0; + + if (y < 0) + y = 0; + + gtk_widget_set_uposition (gde->cal_popup, x, y); +} + +static void +select_clicked (GtkWidget *widget, GNCDateEdit *gde) +{ + struct tm mtm; + /* GdkCursor *cursor; */ + + /* This code is pretty much just copied from gtk_date_edit_get_date */ + scanDate (gtk_entry_get_text (GTK_ENTRY (gde->date_entry)), + &mtm.tm_mday, &mtm.tm_mon, &mtm.tm_year); + + mtm.tm_mon--; + + /* Hope the user does not actually mean years early in the A.D. days... + * This date widget will obviously not work for a history program :-) + */ + if (mtm.tm_year >= 1900) + mtm.tm_year -= 1900; + + mtm.tm_sec = 0; + mtm.tm_min = 0; + mtm.tm_hour = 0; + mtm.tm_isdst = -1; + + mktime(&mtm); /* normalize */ + + gtk_calendar_select_month (GTK_CALENDAR (gde->calendar), mtm.tm_mon, + 1900 + mtm.tm_year); + gtk_calendar_select_day (GTK_CALENDAR (gde->calendar), mtm.tm_mday); + + position_popup (gde); + + gtk_widget_show (gde->cal_popup); + gtk_widget_grab_focus (gde->cal_popup); + gtk_grab_add (gde->cal_popup); + +#if 0 + cursor = gnome_stock_cursor_new (GNOME_STOCK_CURSOR_DEFAULT); + + gdk_pointer_grab (gde->cal_popup->window, TRUE, + (GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_POINTER_MOTION_MASK), + NULL, cursor, GDK_CURRENT_TIME); + + gdk_cursor_destroy (cursor); +#endif +} + +typedef struct { + char *hour; + GNCDateEdit *gde; +} hour_info_t; + +static void +set_time (GtkWidget *widget, hour_info_t *hit) +{ + gtk_entry_set_text (GTK_ENTRY (hit->gde->time_entry), hit->hour); + gtk_signal_emit (GTK_OBJECT (hit->gde), + date_edit_signals [TIME_CHANGED]); +} + +static void +free_resources (GtkWidget *widget, hour_info_t *hit) +{ + g_free (hit->hour); + g_free (hit); +} + +static void +fill_time_popup (GtkWidget *widget, GNCDateEdit *gde) +{ + GtkWidget *menu; + struct tm *mtm; + time_t current_time; + int i, j; + + if (gde->lower_hour > gde->upper_hour) + return; + + menu = gtk_menu_new (); + gtk_option_menu_set_menu (GTK_OPTION_MENU (gde->time_popup), menu); + + time (¤t_time); + mtm = localtime (¤t_time); + + for (i = gde->lower_hour; i <= gde->upper_hour; i++){ + GtkWidget *item, *submenu; + hour_info_t *hit; + char buffer [40]; + + mtm->tm_hour = i; + mtm->tm_min = 0; + hit = g_new (hour_info_t, 1); + + if (gde->flags & GNC_DATE_EDIT_24_HR) + strftime (buffer, sizeof (buffer), "%H:00", mtm); + else + strftime (buffer, sizeof (buffer), "%I:00 %p ", mtm); + hit->hour = g_strdup (buffer); + hit->gde = gde; + + item = gtk_menu_item_new_with_label (buffer); + gtk_menu_append (GTK_MENU (menu), item); +#if 0 + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (set_time), hit); +#endif + gtk_signal_connect (GTK_OBJECT (item), "destroy", + GTK_SIGNAL_FUNC (free_resources), hit); + gtk_widget_show (item); + + submenu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu); + for (j = 0; j < 60; j += 15){ + GtkWidget *mins; + + mtm->tm_min = j; + hit = g_new (hour_info_t, 1); + if (gde->flags & GNC_DATE_EDIT_24_HR) + strftime (buffer, sizeof (buffer), + "%H:%M", mtm); + else + strftime (buffer, sizeof (buffer), + "%I:%M %p", mtm); + hit->hour = g_strdup (buffer); + hit->gde = gde; + + mins = gtk_menu_item_new_with_label (buffer); + gtk_menu_append (GTK_MENU (submenu), mins); + gtk_signal_connect (GTK_OBJECT (mins), "activate", + GTK_SIGNAL_FUNC (set_time), hit); + gtk_signal_connect (GTK_OBJECT (item), "destroy", + GTK_SIGNAL_FUNC (free_resources), + hit); + gtk_widget_show (mins); + } + } +} + +static void +gnc_date_edit_class_init (GNCDateEditClass *class) +{ + GtkObjectClass *object_class = (GtkObjectClass *) class; + GtkContainerClass *container_class = (GtkContainerClass *) class; + + object_class = (GtkObjectClass*) class; + + parent_class = gtk_type_class (gtk_hbox_get_type ()); + + date_edit_signals [TIME_CHANGED] = + gtk_signal_new ("time_changed", + GTK_RUN_FIRST, object_class->type, + GTK_SIGNAL_OFFSET (GNCDateEditClass, + time_changed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + date_edit_signals [DATE_CHANGED] = + gtk_signal_new ("date_changed", + GTK_RUN_FIRST, object_class->type, + GTK_SIGNAL_OFFSET (GNCDateEditClass, + date_changed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, date_edit_signals, + LAST_SIGNAL); + + container_class->forall = gnc_date_edit_forall; + + object_class->destroy = gnc_date_edit_destroy; + + class->date_changed = NULL; + class->time_changed = NULL; +} + +static void +gnc_date_edit_init (GNCDateEdit *gde) +{ + gde->lower_hour = 7; + gde->upper_hour = 19; + gde->flags = GNC_DATE_EDIT_SHOW_TIME; +} + +static void +gnc_date_edit_destroy (GtkObject *object) +{ + GNCDateEdit *gde; + + g_return_if_fail (object != NULL); + g_return_if_fail (GNC_IS_DATE_EDIT (object)); + + gde = GNC_DATE_EDIT (object); + + gtk_widget_destroy (gde->cal_popup); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gnc_date_edit_forall (GtkContainer *container, gboolean include_internals, + GtkCallback callback, gpointer callback_data) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GNC_IS_DATE_EDIT (container)); + g_return_if_fail (callback != NULL); + + /* Let GtkBox handle things only if the internal widgets need to be + * poked. + */ + if (include_internals) + if (GTK_CONTAINER_CLASS (parent_class)->forall) + (* GTK_CONTAINER_CLASS (parent_class)->forall) + (container, + include_internals, + callback, + callback_data); +} + +/** + * gnc_date_edit_set_time: + * @gde: the GNCDateEdit widget + * @the_time: The time and date that should be set on the widget + * + * Changes the displayed date and time in the GNCDateEdit widget + * to be the one represented by @the_time. + */ +void +gnc_date_edit_set_time (GNCDateEdit *gde, time_t the_time) +{ + struct tm *mytm; + char buffer [40]; + + g_return_if_fail(gde != NULL); + + if (the_time == 0) + the_time = time (NULL); + gde->initial_time = the_time; + + mytm = localtime (&the_time); + + /* Set the date */ + printDate (buffer, + mytm->tm_mday, + mytm->tm_mon + 1, + 1900 + mytm->tm_year); + gtk_entry_set_text (GTK_ENTRY (gde->date_entry), buffer); + + /* Set the time */ + if (gde->flags & GNC_DATE_EDIT_24_HR) + strftime (buffer, sizeof (buffer), "%H:%M", mytm); + else + strftime (buffer, sizeof (buffer), "%I:%M %p", mytm); + gtk_entry_set_text (GTK_ENTRY (gde->time_entry), buffer); +} + +/** + * gnc_date_edit_set_popup_range: + * @gde: The GNCDateEdit widget + * @low_hour: low boundary for the time-range display popup. + * @up_hour: upper boundary for the time-range display popup. + * + * Sets the range of times that will be provide by the time popup + * selectors. + */ +void +gnc_date_edit_set_popup_range (GNCDateEdit *gde, int low_hour, int up_hour) +{ + g_return_if_fail(gde != NULL); + + gde->lower_hour = low_hour; + gde->upper_hour = up_hour; + + fill_time_popup(NULL, gde); +} + +static void +create_children (GNCDateEdit *gde) +{ + GtkWidget *frame; + GtkWidget *hbox; + GtkWidget *arrow; + + gde->date_entry = gtk_entry_new (); + gtk_widget_set_usize (gde->date_entry, 90, 0); + gtk_box_pack_start (GTK_BOX (gde), gde->date_entry, TRUE, TRUE, 0); + gtk_widget_show (gde->date_entry); + + gde->date_button = gtk_button_new (); + gtk_signal_connect (GTK_OBJECT (gde->date_button), "clicked", + GTK_SIGNAL_FUNC (select_clicked), gde); + gtk_box_pack_start (GTK_BOX (gde), gde->date_button, FALSE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 3); + gtk_container_add (GTK_CONTAINER (gde->date_button), hbox); + gtk_widget_show (hbox); + + /* Calendar label, only shown if the date editor has a time field */ + + gde->cal_label = gtk_label_new (_("Calendar")); + gtk_misc_set_alignment (GTK_MISC (gde->cal_label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (hbox), gde->cal_label, TRUE, TRUE, 0); + if (gde->flags & GNC_DATE_EDIT_SHOW_TIME) + gtk_widget_show (gde->cal_label); + + arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT); + gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0); + gtk_widget_show (arrow); + + gtk_widget_show (gde->date_button); + + gde->time_entry = gtk_entry_new_with_max_length (12); + gtk_widget_set_usize (gde->time_entry, 88, 0); + gtk_box_pack_start (GTK_BOX (gde), gde->time_entry, TRUE, TRUE, 0); + + gde->time_popup = gtk_option_menu_new (); + gtk_box_pack_start (GTK_BOX (gde), gde->time_popup, FALSE, FALSE, 0); + + /* We do not create the popup menu with the hour range until we are + * realized, so that it uses the values that the user might supply in a + * future call to gnc_date_edit_set_popup_range + */ + gtk_signal_connect (GTK_OBJECT (gde), "realize", + GTK_SIGNAL_FUNC (fill_time_popup), gde); + + if (gde->flags & GNC_DATE_EDIT_SHOW_TIME) { + gtk_widget_show (gde->time_entry); + gtk_widget_show (gde->time_popup); + } + + gde->cal_popup = gtk_window_new (GTK_WINDOW_POPUP); + gtk_widget_set_events (gde->cal_popup, + gtk_widget_get_events (gde->cal_popup) | + GDK_KEY_PRESS_MASK); + gtk_signal_connect (GTK_OBJECT (gde->cal_popup), "delete_event", + (GtkSignalFunc) delete_popup, + gde); + gtk_signal_connect (GTK_OBJECT (gde->cal_popup), "key_press_event", + (GtkSignalFunc) key_press_popup, + gde); + gtk_signal_connect (GTK_OBJECT (gde->cal_popup), "button_press_event", + (GtkSignalFunc) button_press_popup, + gde); + gtk_window_set_policy (GTK_WINDOW (gde->cal_popup), + FALSE, FALSE, TRUE); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_container_add (GTK_CONTAINER (gde->cal_popup), frame); + gtk_widget_show (frame); + + gde->calendar = gtk_calendar_new (); + gtk_calendar_display_options + (GTK_CALENDAR (gde->calendar), + (GTK_CALENDAR_SHOW_DAY_NAMES + | GTK_CALENDAR_SHOW_HEADING + | ((gde->flags & GNC_DATE_EDIT_WEEK_STARTS_ON_MONDAY) + ? GTK_CALENDAR_WEEK_START_MONDAY : 0))); + gtk_signal_connect (GTK_OBJECT (gde->calendar), "day_selected", + GTK_SIGNAL_FUNC (day_selected), gde); + gtk_signal_connect (GTK_OBJECT (gde->calendar), + "day_selected_double_click", + GTK_SIGNAL_FUNC (day_selected_double_click), gde); + gtk_container_add (GTK_CONTAINER (frame), gde->calendar); + gtk_widget_show (gde->calendar); +} + +/** + * gnc_date_edit_new: + * @the_time: date and time to be displayed on the widget + * @show_time: whether time should be displayed + * @use_24_format: whether 24-hour format is desired for the time display. + * + * Creates a new GNCDateEdit widget which can be used to provide + * an easy to use way for entering dates and times. + * + * Returns a GNCDateEdit widget. + */ +GtkWidget * +gnc_date_edit_new (time_t the_time, int show_time, int use_24_format) +{ + return gnc_date_edit_new_flags + (the_time, + ((show_time ? GNC_DATE_EDIT_SHOW_TIME : 0) + | (use_24_format ? GNC_DATE_EDIT_24_HR : 0))); +} + +/** + * gnc_date_edit_new_flags: + * @the_time: The initial time for the date editor. + * @flags: A bitmask of GNCDateEditFlags values. + * + * Creates a new GNCDateEdit widget with the specified flags. + * + * Return value: the newly-created date editor widget. + **/ +GtkWidget * +gnc_date_edit_new_flags (time_t the_time, GNCDateEditFlags flags) +{ + GNCDateEdit *gde; + + gde = gtk_type_new (gnc_date_edit_get_type ()); + + gde->flags = flags; + create_children (gde); + gnc_date_edit_set_time (gde, the_time); + + return GTK_WIDGET (gde); +} + +/** + * gnc_date_edit_get_date: + * @gde: The GNCDateEdit widget + * + * Returns the time entered in the GNCDateEdit widget + */ +time_t +gnc_date_edit_get_date (GNCDateEdit *gde) +{ + struct tm tm = {0}; + char *str, *flags = NULL; + + /* Assert, because we're just hosed if it's NULL */ + g_assert(gde != NULL); + g_assert(GNC_IS_DATE_EDIT(gde)); + + scanDate (gtk_entry_get_text (GTK_ENTRY (gde->date_entry)), + &tm.tm_mday, &tm.tm_mon, &tm.tm_year); + + tm.tm_mon--; + + /* Hope the user does not actually mean years early in the A.D. days... + * This date widget will obviously not work for a history program :-) + */ + if (tm.tm_year >= 1900) + tm.tm_year -= 1900; + + if (gde->flags & GNC_DATE_EDIT_SHOW_TIME) { + char *tokp, *temp; + + str = g_strdup (gtk_entry_get_text + (GTK_ENTRY (gde->time_entry))); + temp = strtok_r (str, ": ", &tokp); + if (temp) { + tm.tm_hour = atoi (temp); + temp = strtok_r (NULL, ": ", &tokp); + if (temp) { + if (isdigit (*temp)) { + tm.tm_min = atoi (temp); + flags = strtok_r (NULL, ": ", &tokp); + if (flags && isdigit (*flags)) { + tm.tm_sec = atoi (flags); + flags = strtok_r (NULL, ": ", + &tokp); + } + } else + flags = temp; + } + } + + if (flags && (strcasecmp (flags, "PM") == 0)){ + if (tm.tm_hour < 12) + tm.tm_hour += 12; + } + g_free (str); + } + + tm.tm_isdst = -1; + + return mktime (&tm); +} + +/** + * gnc_date_edit_set_flags: + * @gde: The date editor widget whose flags should be changed. + * @flags: The new bitmask of GNCDateEditFlags values. + * + * Changes the display flags on an existing date editor widget. + **/ +void +gnc_date_edit_set_flags (GNCDateEdit *gde, GNCDateEditFlags flags) +{ + GNCDateEditFlags old_flags; + + g_return_if_fail (gde != NULL); + g_return_if_fail (GNC_IS_DATE_EDIT (gde)); + + old_flags = gde->flags; + gde->flags = flags; + + if ((flags & GNC_DATE_EDIT_SHOW_TIME) != + (old_flags & GNC_DATE_EDIT_SHOW_TIME)) { + if (flags & GNC_DATE_EDIT_SHOW_TIME) { + gtk_widget_show (gde->cal_label); + gtk_widget_show (gde->time_entry); + gtk_widget_show (gde->time_popup); + } else { + gtk_widget_hide (gde->cal_label); + gtk_widget_hide (gde->time_entry); + gtk_widget_hide (gde->time_popup); + } + } + + if ((flags & GNC_DATE_EDIT_24_HR) != (old_flags & GNC_DATE_EDIT_24_HR)) + /* This will destroy the old menu properly */ + fill_time_popup (GTK_WIDGET (gde), gde); + + if ((flags & GNC_DATE_EDIT_WEEK_STARTS_ON_MONDAY) + != (old_flags & GNC_DATE_EDIT_WEEK_STARTS_ON_MONDAY)) { + if (flags & GNC_DATE_EDIT_WEEK_STARTS_ON_MONDAY) + gtk_calendar_display_options + (GTK_CALENDAR (gde->calendar), + (GTK_CALENDAR (gde->calendar)->display_flags + | GTK_CALENDAR_WEEK_START_MONDAY)); + else + gtk_calendar_display_options + (GTK_CALENDAR (gde->calendar), + (GTK_CALENDAR (gde->calendar)->display_flags + & ~GTK_CALENDAR_WEEK_START_MONDAY)); + } +} + +/** + * gnc_date_edit_get_flags: + * @gde: The date editor whose flags should be queried. + * + * Queries the display flags on a date editor widget. + * + * Return value: The current display flags for the given date editor widget. + **/ +int +gnc_date_edit_get_flags (GNCDateEdit *gde) +{ + g_return_val_if_fail (gde != NULL, 0); + g_return_val_if_fail (GNC_IS_DATE_EDIT (gde), 0); + + return gde->flags; +} + +/* + Local Variables: + c-basic-offset: 8 + End: +*/ diff --git a/src/gnome/gnc-dateedit.h b/src/gnome/gnc-dateedit.h new file mode 100644 index 0000000000..f37fa5cbb6 --- /dev/null +++ b/src/gnome/gnc-dateedit.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation + * All rights reserved. + * + * This file was part of the Gnome Library. It was modifed by + * Dave Peticolas for use in GnuCash. + * + * GnuCash is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * The Gnome Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact: + * + * Free Software Foundation Voice: +1-617-542-5942 + * 59 Temple Place - Suite 330 Fax: +1-617-542-2652 + * Boston, MA 02111-1307, USA gnu@gnu.org + * + */ +/* + @NOTATION@ + */ + +#ifndef __GNC_DATE_EDIT_H_ +#define __GNC_DATE_EDIT_H_ + +#include + +BEGIN_GNOME_DECLS + + +typedef enum { + GNC_DATE_EDIT_SHOW_TIME = 1 << 0, + GNC_DATE_EDIT_24_HR = 1 << 1, + GNC_DATE_EDIT_WEEK_STARTS_ON_MONDAY = 1 << 2, +#if 0 + GNC_DATE_EDIT_SHOW_DATE = 1 << 3, + GNC_DATE_EDIT_SHOW_DELTA = 1 << 4 +#endif +} GNCDateEditFlags; + + +#define GNC_DATE_EDIT(obj) GTK_CHECK_CAST (obj, gnc_date_edit_get_type(), GNCDateEdit) +#define GNC_DATE_EDIT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gnc_date_edit_get_type(), GNCDateEditClass) +#define GNC_IS_DATE_EDIT(obj) GTK_CHECK_TYPE (obj, gnc_date_edit_get_type ()) + +typedef struct { + GtkHBox hbox; + + GtkWidget *date_entry; + GtkWidget *date_button; + + GtkWidget *time_entry; + GtkWidget *time_popup; + + GtkWidget *cal_label; + GtkWidget *cal_popup; + GtkWidget *calendar; + + time_t initial_time; + + int lower_hour; + int upper_hour; + + int flags; +} GNCDateEdit; + +typedef struct { + GtkHBoxClass parent_class; + void (*date_changed) (GNCDateEdit *gde); + void (*time_changed) (GNCDateEdit *gde); +} GNCDateEditClass; + +guint gnc_date_edit_get_type (void); + +GtkWidget *gnc_date_edit_new (time_t the_time, + int show_time, int use_24_format); +GtkWidget *gnc_date_edit_new_flags (time_t the_time, + GNCDateEditFlags flags); + +void gnc_date_edit_set_time (GNCDateEdit *gde, time_t the_time); + +void gnc_date_edit_set_popup_range (GNCDateEdit *gde, + int low_hour, int up_hour); + +time_t gnc_date_edit_get_date (GNCDateEdit *gde); + +void gnc_date_edit_set_flags (GNCDateEdit *gde, + GNCDateEditFlags flags); +int gnc_date_edit_get_flags (GNCDateEdit *gde); + + +END_GNOME_DECLS + +#endif diff --git a/src/gnome/gnc-dialogs.glade b/src/gnome/gnc-dialogs.glade index 5a5a4cf744..d081e71c16 100644 --- a/src/gnome/gnc-dialogs.glade +++ b/src/gnome/gnc-dialogs.glade @@ -4449,7 +4449,7 @@ No Total GtkLabel label781 - + GTK_JUSTIFY_RIGHT False 1 @@ -4466,7 +4466,7 @@ No Total GtkLabel label782 - + GTK_JUSTIFY_RIGHT False 1 @@ -4558,7 +4558,7 @@ No Total GtkOptionMenu - optionmenu2 + optionmenu4 True Days Weeks @@ -4684,26 +4684,55 @@ Contingency - GtkSpinButton - spinbutton3 - True - 1 - 0 - True - GTK_UPDATE_ALWAYS - False - False - 1 - -365 - 365 - 1 - 10 - 10 + GtkHBox + hbox41 + False + 0 0 False False + + + GtkSpinButton + spinbutton3 + True + 1 + 0 + True + GTK_UPDATE_ALWAYS + False + False + 1 + -365 + 365 + 1 + 10 + 10 + + 0 + True + True + + + + + GtkOptionMenu + optionmenu2 + True + Days +Weeks +Months +Years + + 0 + + 0 + False + False + + diff --git a/src/gnome/window-adjust.c b/src/gnome/window-adjust.c index 72e9e22aac..2e2ab5cbeb 100644 --- a/src/gnome/window-adjust.c +++ b/src/gnome/window-adjust.c @@ -35,6 +35,7 @@ #include "window-reconcile.h" #include "dialog-utils.h" #include "query-user.h" +#include "gnc-dateedit.h" #include "messages.h" #include "util.h" @@ -119,7 +120,7 @@ gnc_ui_AdjBWindow_ok_cb(GtkWidget * widget, gpointer data) if (gnc_reverse_balance(adjBData->account)) new_balance = -new_balance; - time = gnome_date_edit_get_date(GNOME_DATE_EDIT(adjBData->date_entry)); + time = gnc_date_edit_get_date(GNC_DATE_EDIT(adjBData->date_entry)); trans = xaccMallocTransaction(); @@ -273,7 +274,7 @@ adjBWindow(Account *account) /* Edit widget box */ vbox = gtk_vbox_new(TRUE, 3); - date = gnome_date_edit_new(time(NULL), FALSE, FALSE); + date = gnc_date_edit_new(time(NULL), FALSE, FALSE); gtk_box_pack_start(GTK_BOX(vbox), date, TRUE, TRUE, 0); adjBData->date_entry = date; diff --git a/src/gnome/window-register.c b/src/gnome/window-register.c index f04067e5b7..010c88741d 100644 --- a/src/gnome/window-register.c +++ b/src/gnome/window-register.c @@ -51,6 +51,7 @@ #include "gnucash-sheet.h" #include "global-options.h" #include "dialog-find-transactions.h" +#include "gnc-dateedit.h" #include "util.h" @@ -485,7 +486,7 @@ gnc_register_set_date_range(RegWindow *regData) if (!gtk_toggle_button_get_active(toggle)) { time_t start; - start = gnome_date_edit_get_date(GNOME_DATE_EDIT(regDateData->start_date)); + start = gnc_date_edit_get_date(GNC_DATE_EDIT(regDateData->start_date)); start = gnc_register_min_day_time(start); xaccQueryAddDateMatchTT(regData->ledger->query, @@ -497,7 +498,7 @@ gnc_register_set_date_range(RegWindow *regData) if (!gtk_toggle_button_get_active(toggle)) { time_t end; - end = gnome_date_edit_get_date(GNOME_DATE_EDIT(regDateData->end_date)); + end = gnc_date_edit_get_date(GNC_DATE_EDIT(regDateData->end_date)); end = gnc_register_max_day_time(end); xaccQueryAddDateMatchTT(regData->ledger->query, @@ -551,7 +552,7 @@ gnc_register_today_cb(GtkWidget *widget, gpointer data) assert(regData != NULL); regDateData = regData->date_window; - gnome_date_edit_set_time(GNOME_DATE_EDIT(regDateData->end_date), time(NULL)); + gnc_date_edit_set_time(GNC_DATE_EDIT(regDateData->end_date), time(NULL)); gtk_widget_set_sensitive(regData->date_window->set_button, TRUE); } @@ -666,22 +667,22 @@ gnc_register_date_window(RegWindow *regData) gtk_signal_connect(GTK_OBJECT(radio), "toggled", GTK_SIGNAL_FUNC(gnc_register_date_toggle_cb), regData); - date = gnome_date_edit_new(time(NULL), FALSE, FALSE); + date = gnc_date_edit_new(time(NULL), FALSE, FALSE); gtk_box_pack_start(GTK_BOX(hbox), date, FALSE, FALSE, 0); regDateData->start_date = date; time_val = xaccQueryGetEarliestDateFound(regData->ledger->query); if (time_val < time(NULL)) - gnome_date_edit_set_time(GNOME_DATE_EDIT(date), time_val); + gnc_date_edit_set_time(GNC_DATE_EDIT(date), time_val); gtk_signal_connect(GTK_OBJECT(date), "date-changed", GTK_SIGNAL_FUNC(gnc_register_date_changed_cb), regData); - calendar = GNOME_DATE_EDIT(date)->calendar; + calendar = GNC_DATE_EDIT(date)->calendar; gtk_signal_connect(GTK_OBJECT(calendar), "day_selected_double_click", GTK_SIGNAL_FUNC(gnc_register_date_changed_cb), regData); - entry = GNOME_DATE_EDIT(date)->date_entry; + entry = GNC_DATE_EDIT(date)->date_entry; gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(gnc_register_date_changed_cb), regData); gtk_signal_connect(GTK_OBJECT(entry), "changed", @@ -715,18 +716,18 @@ gnc_register_date_window(RegWindow *regData) gtk_signal_connect(GTK_OBJECT(radio), "toggled", GTK_SIGNAL_FUNC(gnc_register_date_toggle_cb), regData); - date = gnome_date_edit_new(time(NULL), FALSE, FALSE); + date = gnc_date_edit_new(time(NULL), FALSE, FALSE); gtk_box_pack_start(GTK_BOX(hbox), date, FALSE, FALSE, 0); regDateData->end_date = date; gtk_signal_connect(GTK_OBJECT(date), "date-changed", GTK_SIGNAL_FUNC(gnc_register_date_changed_cb), regData); - calendar = GNOME_DATE_EDIT(date)->calendar; + calendar = GNC_DATE_EDIT(date)->calendar; gtk_signal_connect(GTK_OBJECT(calendar), "day_selected_double_click", GTK_SIGNAL_FUNC(gnc_register_date_changed_cb), regData); - entry = GNOME_DATE_EDIT(date)->date_entry; + entry = GNC_DATE_EDIT(date)->date_entry; gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(gnc_register_date_changed_cb), regData); gtk_signal_connect(GTK_OBJECT(entry), "changed", @@ -1946,18 +1947,18 @@ gnc_register_include_date(RegWindow *regData, time_t date) regDateData = regData->date_window; - start = gnome_date_edit_get_date(GNOME_DATE_EDIT(regDateData->start_date)); - end = gnome_date_edit_get_date(GNOME_DATE_EDIT(regDateData->end_date)); + start = gnc_date_edit_get_date(GNC_DATE_EDIT(regDateData->start_date)); + end = gnc_date_edit_get_date(GNC_DATE_EDIT(regDateData->end_date)); if (date < start) { - gnome_date_edit_set_time(GNOME_DATE_EDIT(regDateData->start_date), date); + gnc_date_edit_set_time(GNC_DATE_EDIT(regDateData->start_date), date); changed = TRUE; } if (date > end) { - gnome_date_edit_set_time(GNOME_DATE_EDIT(regDateData->end_date), date); + gnc_date_edit_set_time(GNC_DATE_EDIT(regDateData->end_date), date); changed = TRUE; }