*
*/
-/* HILDON DOC
- * @shortdesc: DateEditor is a widget for setting, getting and showing a
- * date.
- * @longdesc: The date editor consists of a GtkLabel that shows the current
- * date in localized form and an icon. Clicking on either the label or the
- * icon opens the #HildonCalendarPopup used for selecting the date.
- * Similarly, if the editor has the focus, and space or enter key is
- * pressed, the #HildonCalendarPopup will open.
+/**
+ * SECTION:hildon-date-editor
+ * @short_description: A widget which queries a date from user or opens
+ * a HildonCalendarPopup
+ * @see_also: #HildonCalendarPopup, #HildonTimeEditor
*
- * @seealso: #HildonTimeEditor, #HildonCalendarPopup
+ * HildonDateEditor is a widget with three entry fields (day, month,
+ * year) and an icon (eventbox): clicking on the icon opens up a
+ * HildonCalendarPopup.
*/
#include <glib.h>
#include <gtk/gtk.h>
-#include <gtk/gtkmarshal.h>
#include <gdk/gdkkeysyms.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <langinfo.h>
#include <hildon-widgets/hildon-date-editor.h>
#include <hildon-widgets/hildon-calendar-popup.h>
#include<libintl.h>
#define _(string) dgettext(PACKAGE, string)
-#define MAX_DATE_LEN 256
#define ENTRY_BORDERS 11
#define DATE_EDITOR_HEIGHT 30
-#define BUTTON_SPACING 6
#define DAY_ENTRY_WIDTH 2
#define MONTH_ENTRY_WIDTH 2
#define YEAR_ENTRY_WIDTH 4
+#define DEFAULT_MIN_YEAR 1970
+#define DEFAULT_MAX_YEAR 2037
+
#define HILDON_DATE_EDITOR_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE((obj),\
HILDON_DATE_EDITOR_TYPE, HildonDateEditorPrivate));
typedef struct _HildonDateEditorPrivate HildonDateEditorPrivate;
-static int hildon_date_editor_get_font_width(GtkWidget * widget);
-
static void
hildon_date_editor_class_init(HildonDateEditorClass * editor_class);
hildon_date_editor_keyrelease(GtkWidget * widget, GdkEventKey * event,
gpointer data);
static void
-hildon_date_editor_entry_validate(GtkEditable *widget, gpointer data);
+hildon_date_editor_entry_validate(GtkWidget *widget, gpointer data);
+
+static void
+hildon_date_editor_entry_changed(GtkEditable *widget, gpointer data);
static gboolean
hildon_date_editor_entry_focus_out(GtkWidget * widget, GdkEventFocus * event,
GValue *value, GParamSpec *pspec );
static void hildon_date_editor_set_property (GObject *object, guint param_id,
const GValue *value, GParamSpec *pspec);
-static gboolean
-hildon_date_editor_mnemonic_activate(GtkWidget *widget, gboolean group_cycling);
-
static void
hildon_child_forall(GtkContainer * container,
gboolean include_internals,
GtkCallback callback, gpointer callback_data);
+
static void hildon_date_editor_destroy(GtkObject * self);
+
static void
hildon_date_editor_size_allocate(GtkWidget * widget,
GtkAllocation * allocation);
hildon_date_editor_size_request(GtkWidget * widget,
GtkRequisition * requisition);
-static guint
-hildon_date_editor_check_locale_settings(HildonDateEditor * editor);
-
-static void hildon_date_editor_finalize(GObject * object);
-
static gboolean
_hildon_date_editor_entry_select_all(GtkWidget *widget);
+/* Property indices */
enum
{
PROP_DAY = 1,
PROP_MONTH,
- PROP_YEAR
+ PROP_YEAR,
+ PROP_MIN_YEAR,
+ PROP_MAX_YEAR
};
struct _HildonDateEditorPrivate {
- guint year; /* current year in the entry */
- guint month; /* current month in the entry */
- guint day; /* current day in the entry */
-
- guint y_orig; /* roll back value for year (if entry has illegal
- value) */
- guint m_orig; /* roll back value for month */
- guint d_orig; /* roll back value for day */
+ /* Cache of values in the entries, used in setting only parts of the date */
+ guint year; /* current year in the entry */
+ guint month; /* current month in the entry */
+ guint day; /* current day in the entry */
- gint button_press; /* wheter to show pressed image */
+ gboolean calendar_icon_pressed;
- gboolean editor_pressed;
- gboolean valid_value;
-
- GtkWidget *frame; /* borders around the date */
- GtkWidget *d_event_box_image; /* icon */
- GtkWidget *d_box_date; /* hbox for date */
+ GtkWidget *frame; /* borders around the date */
+ GtkWidget *d_event_box_image; /* icon */
+ GtkWidget *d_box_date; /* hbox for date */
GtkWidget *d_entry; /* GtkEntry for day */
GtkWidget *m_entry; /* GtkEntry for month */
GtkWidget *y_entry; /* GtkEntry for year */
- GtkWidget *dm_delim; /* Delimeter between day and month entries */
- GtkWidget *my_delim; /* Delimeter between month and year entries */
-
- GtkWidget *d_image; /* normal icon image */
- GtkWidget *d_image_pressed;
- guint locale_type;
+ GList *delims; /* List of delimeters between the fields (and possible at the ends) */
+ GtkWidget *calendar_icon;
- gboolean skip_validation;
-};
+ gboolean skip_validation; /* don't validate date at all */
-enum {
- MONTH_DAY_YEAR,
- DAY_MONTH_YEAR,
- YEAR_MONTH_DAY
+ gint min_year; /* minimum year allowed */
+ gint max_year; /* maximum year allowed */
};
enum {
gobject_class->set_property = hildon_date_editor_set_property;
gobject_class->get_property = hildon_date_editor_get_property;
- widget_class->mnemonic_activate = hildon_date_editor_mnemonic_activate;
widget_class->size_request = hildon_date_editor_size_request;
widget_class->size_allocate = hildon_date_editor_size_allocate;
widget_class->focus = hildon_composite_widget_focus;
container_class->forall = hildon_child_forall;
GTK_OBJECT_CLASS(editor_class)->destroy = hildon_date_editor_destroy;
- gobject_class->finalize = hildon_date_editor_finalize;
editor_class->date_error = hildon_date_editor_date_error;
G_PARAM_READABLE | G_PARAM_WRITABLE) );
/**
- * HildonControlbar:month:
+ * HildonDateEditor:month:
*
* Current month.
*/
G_PARAM_READABLE | G_PARAM_WRITABLE) );
/**
- * HildonControlbar:day:
+ * HildonDateEditor:day:
*
* Current day.
*/
1, 31,
1,
G_PARAM_READABLE | G_PARAM_WRITABLE) );
+
+ /**
+ * HildonDateEditor:min-year:
+ *
+ * Minimum valid year.
+ */
+ g_object_class_install_property( gobject_class, PROP_MIN_YEAR,
+ g_param_spec_uint("min-year",
+ "Minimum valid year",
+ "Minimum valid year",
+ 1, 2100,
+ DEFAULT_MIN_YEAR,
+ G_PARAM_READWRITE) );
+
+ /**
+ * HildonDateEditor:max-year:
+ *
+ * Maximum valid year.
+ */
+ g_object_class_install_property( gobject_class, PROP_MAX_YEAR,
+ g_param_spec_uint("max-year",
+ "Maximum valid year",
+ "Maximum valid year",
+ 1, 2100,
+ DEFAULT_MAX_YEAR,
+ G_PARAM_READWRITE) );
+}
+
+/* Forces setting of the icon to certain state. Used initially
+ and from the actual setter function */
+static void
+real_set_calendar_icon_state(HildonDateEditorPrivate *priv,
+ gboolean pressed)
+{
+ gtk_image_set_from_icon_name(GTK_IMAGE(priv->calendar_icon),
+ pressed ? "qgn_widg_datedit_pr" : "qgn_widg_datedit",
+ HILDON_ICON_SIZE_WIDG);
+
+ priv->calendar_icon_pressed = pressed;
+}
+
+/* Sets the icon to given state (normal/pressed). Returns
+ info if the state actually changed. */
+static gboolean
+hildon_date_editor_set_calendar_icon_state(HildonDateEditor *editor,
+ gboolean pressed)
+{
+ HildonDateEditorPrivate *priv;
+
+ g_assert(HILDON_IS_DATE_EDITOR(editor));
+
+ priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
+ if (pressed != priv->calendar_icon_pressed) {
+ real_set_calendar_icon_state(priv, pressed);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Packing day, month and year entries depend on locale settings
+ We find out the order and all separators by converting a known
+ date to default format and inspecting the result string */
+static void apply_locale_field_order(HildonDateEditorPrivate *priv)
+{
+ GDate locale_test_date;
+ GtkWidget *delim;
+ gchar buffer[256];
+ gchar *iter, *delim_text;
+
+ g_date_set_dmy(&locale_test_date, 1, 2, 1970);
+ (void) g_date_strftime(buffer, sizeof(buffer), "%x", &locale_test_date);
+ iter = buffer;
+
+ while (*iter)
+ {
+ gchar *endp;
+ unsigned long value;
+
+ /* Try to convert the current location into number. */
+ value = strtoul(iter, &endp, 10);
+
+ /* If the conversion didn't progress or the detected value was
+ unknown (we used a fixed date, you remember), we treat
+ current position as a literal */
+ switch (value)
+ {
+ case 1:
+ gtk_box_pack_start(GTK_BOX(priv->d_box_date),
+ priv->d_entry, FALSE, FALSE, 0);
+ break;
+ case 2:
+ gtk_box_pack_start(GTK_BOX(priv->d_box_date),
+ priv->m_entry, FALSE, FALSE, 0);
+ break;
+ case 70: /* %x format uses only 2 numbers for some locales */
+ case 1970:
+ gtk_box_pack_start(GTK_BOX(priv->d_box_date),
+ priv->y_entry, FALSE, FALSE, 0);
+ break;
+ default:
+ /* All non-number characters starting from current position
+ form the delimeter */
+ for (endp = iter; *endp; endp++)
+ if (g_ascii_isdigit(*endp))
+ break;
+
+ /* Now endp points one place past the delimeter text */
+ delim_text = g_strndup(iter, endp - iter);
+ delim = gtk_label_new(delim_text);
+ gtk_box_pack_start(GTK_BOX(priv->d_box_date),
+ delim, FALSE, FALSE, 0);
+ priv->delims = g_list_append(priv->delims, delim);
+ g_free(delim_text);
+
+ break;
+ };
+
+ iter = endp;
+ }
}
static void hildon_date_editor_init(HildonDateEditor * editor)
{
HildonDateEditorPrivate *priv;
GDate cur_date;
- guint locale_type;
priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
priv->day = g_date_get_day(&cur_date);
priv->month = g_date_get_month(&cur_date);
priv->year = g_date_get_year(&cur_date);
-
- priv->y_orig = 0;
- priv->m_orig = 0;
- priv->d_orig = 0;
- priv->button_press = FALSE;
- priv->valid_value = TRUE;
+ priv->min_year = DEFAULT_MIN_YEAR;
+ priv->max_year = DEFAULT_MAX_YEAR;
/* make widgets */
priv->frame = gtk_frame_new(NULL);
priv->d_entry = gtk_entry_new();
priv->m_entry = gtk_entry_new();
priv->y_entry = gtk_entry_new();
- priv->editor_pressed = FALSE;
g_object_set (G_OBJECT(priv->d_entry), "input-mode",
HILDON_INPUT_MODE_HINT_NUMERIC, NULL);
gtk_entry_set_has_frame(GTK_ENTRY(priv->m_entry), FALSE);
gtk_entry_set_has_frame(GTK_ENTRY(priv->y_entry), FALSE);
- priv->dm_delim = gtk_label_new(_("Ecdg_ti_date_editor_separator"));
- priv->my_delim = gtk_label_new(_("Ecdg_ti_date_editor_separator"));
+ gtk_widget_set_composite_name(priv->d_entry, "day_entry");
+ gtk_widget_set_composite_name(priv->m_entry, "month_entry");
+ gtk_widget_set_composite_name(priv->y_entry, "year_entry");
priv->d_box_date = gtk_hbox_new(FALSE, 0);
priv->d_event_box_image = gtk_event_box_new();
+ priv->calendar_icon = gtk_image_new();
+ real_set_calendar_icon_state(priv, FALSE);
- priv->d_image = gtk_image_new_from_icon_name("qgn_widg_datedit",
- HILDON_ICON_SIZE_WIDG);
- priv->d_image_pressed = gtk_image_new_from_icon_name("qgn_widg_datedit_pr",
- HILDON_ICON_SIZE_WIDG);
- g_object_ref(G_OBJECT(priv->d_image));
- g_object_ref(G_OBJECT(priv->d_image_pressed));
- gtk_object_sink(GTK_OBJECT(priv->d_image));
- gtk_object_sink(GTK_OBJECT(priv->d_image_pressed));
- /* packing */
- /* Packing day, month and year entries depend on locale settings */
- priv->locale_type = locale_type =
- hildon_date_editor_check_locale_settings(editor);
-
- if (locale_type == DAY_MONTH_YEAR)
- gtk_box_pack_start(GTK_BOX(priv->d_box_date),
- priv->d_entry, FALSE, FALSE, 0);
- else if (locale_type == MONTH_DAY_YEAR)
- gtk_box_pack_start(GTK_BOX(priv->d_box_date),
- priv->m_entry, FALSE, FALSE, 0);
- else
- gtk_box_pack_start(GTK_BOX(priv->d_box_date),
- priv->y_entry, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(priv->d_box_date),
- priv->dm_delim, FALSE, FALSE, 0);
- if (locale_type == DAY_MONTH_YEAR)
- gtk_box_pack_start(GTK_BOX(priv->d_box_date),
- priv->m_entry, FALSE, FALSE, 0);
- else if (locale_type == MONTH_DAY_YEAR)
- gtk_box_pack_start(GTK_BOX(priv->d_box_date),
- priv->d_entry, FALSE, FALSE, 0);
- else
- gtk_box_pack_start(GTK_BOX(priv->d_box_date),
- priv->m_entry, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(priv->d_box_date),
- priv->my_delim, FALSE, FALSE, 0);
- if (locale_type == DAY_MONTH_YEAR)
- gtk_box_pack_start(GTK_BOX(priv->d_box_date),
- priv->y_entry, FALSE, FALSE, 0);
- else if (locale_type == MONTH_DAY_YEAR)
- gtk_box_pack_start(GTK_BOX(priv->d_box_date),
- priv->y_entry, FALSE, FALSE, 0);
- else
- gtk_box_pack_start(GTK_BOX(priv->d_box_date),
- priv->d_entry, FALSE, FALSE, 0);
+ apply_locale_field_order(priv);
gtk_container_add(GTK_CONTAINER(priv->frame), priv->d_box_date);
- gtk_container_add(GTK_CONTAINER(priv->d_event_box_image), priv->d_image);
+ gtk_container_add(GTK_CONTAINER(priv->d_event_box_image), priv->calendar_icon);
gtk_widget_set_parent(priv->frame, GTK_WIDGET(editor));
gtk_widget_set_parent(priv->d_event_box_image, GTK_WIDGET(editor));
gtk_widget_show_all(priv->frame);
gtk_widget_show_all(priv->d_event_box_image);
-
-
/* image signal connects */
g_signal_connect(GTK_OBJECT(priv->d_event_box_image), "button_press_event",
G_CALLBACK(hildon_date_editor_icon_press), editor);
-
g_signal_connect(GTK_OBJECT(priv->d_event_box_image),
"button_release_event",
G_CALLBACK(hildon_date_editor_released), editor);
-
g_signal_connect(GTK_OBJECT(priv->d_event_box_image), "key-press-event",
G_CALLBACK(hildon_date_editor_keypress), editor);
-
- g_signal_connect(GTK_OBJECT(priv->d_image), "key-press-event",
+ g_signal_connect(GTK_OBJECT(priv->calendar_icon), "key-press-event",
G_CALLBACK(hildon_date_editor_keypress), editor);
g_signal_connect(GTK_OBJECT(priv->y_entry), "key-release-event",
G_CALLBACK(hildon_date_editor_keyrelease), editor);
+ hildon_date_editor_set_date(editor, priv->year, priv->month, priv->day);
+
g_signal_connect(GTK_OBJECT(priv->d_entry), "changed",
- G_CALLBACK(hildon_date_editor_entry_validate), editor);
+ G_CALLBACK(hildon_date_editor_entry_changed), editor);
g_signal_connect(GTK_OBJECT(priv->m_entry), "changed",
- G_CALLBACK(hildon_date_editor_entry_validate), editor);
+ G_CALLBACK(hildon_date_editor_entry_changed), editor);
g_signal_connect(GTK_OBJECT(priv->y_entry), "changed",
- G_CALLBACK(hildon_date_editor_entry_validate), editor);
-
- hildon_date_editor_set_date(editor, priv->year, priv->month, priv->day);
+ G_CALLBACK(hildon_date_editor_entry_changed), editor);
gtk_widget_pop_composite_child();
}
const GValue *value, GParamSpec *pspec)
{
HildonDateEditor *editor = HILDON_DATE_EDITOR(object);
+ HildonDateEditorPrivate *priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
+ gint val;
+
switch (param_id)
{
case PROP_YEAR:
hildon_date_editor_set_day (editor, g_value_get_uint(value));
break;
+ case PROP_MIN_YEAR:
+ val = g_value_get_uint(value);
+ if (val <= priv->max_year)
+ {
+ priv->min_year = val;
+ /* Clamp current year */
+ if (hildon_date_editor_get_year (editor) < priv->min_year)
+ hildon_date_editor_set_year (editor, priv->min_year);
+ }
+ else
+ g_warning("min-year cannot be greater than max-year");
+ break;
+
+ case PROP_MAX_YEAR:
+ val = g_value_get_uint(value);
+ if (val >= priv->min_year)
+ {
+ priv->max_year = val;
+ /* Clamp current year */
+ if (hildon_date_editor_get_year (editor) > priv->max_year)
+ hildon_date_editor_set_year (editor, priv->max_year);
+ }
+ else
+ g_warning("max-year cannot be less than min-year");
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
break;
GValue *value, GParamSpec *pspec )
{
HildonDateEditor *editor = HILDON_DATE_EDITOR(object);
+ HildonDateEditorPrivate *priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
+
switch (param_id)
{
case PROP_YEAR:
g_value_set_uint (value, hildon_date_editor_get_day (editor));
break;
+ case PROP_MIN_YEAR:
+ g_value_set_uint (value, priv->min_year);
+ break;
+
+ case PROP_MAX_YEAR:
+ g_value_set_uint (value, priv->max_year);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
break;
}
}
-static gboolean
-hildon_date_editor_mnemonic_activate(GtkWidget *widget, gboolean group_cycling)
-
-{
- GtkWidget *entry;
- HildonDateEditorPrivate *priv = HILDON_DATE_EDITOR_GET_PRIVATE(widget);
-
- if( priv->locale_type == MONTH_DAY_YEAR )
- entry = priv->m_entry;
- else
- entry = priv->d_entry;
-
- gtk_widget_grab_focus( entry );
- g_idle_add((GSourceFunc)_hildon_date_editor_entry_select_all, entry);
- return TRUE;
-}
-
-static void hildon_date_editor_finalize(GObject * object)
-{
- HildonDateEditorPrivate *priv = HILDON_DATE_EDITOR_GET_PRIVATE(object);
-
- g_object_unref(G_OBJECT(priv->d_image));
- g_object_unref(G_OBJECT(priv->d_image_pressed));
- if( G_OBJECT_CLASS(parent_class)->finalize )
- G_OBJECT_CLASS(parent_class)->finalize(object);
-}
-
-static guint
-hildon_date_editor_check_locale_settings(HildonDateEditor * editor)
-{
- gchar *dfmt;
-
- dfmt = nl_langinfo(D_FMT);
-
- if (!strncmp(dfmt, "%d", 2))
- return DAY_MONTH_YEAR;
- else if (!strncmp(dfmt, "%m", 2))
- return MONTH_DAY_YEAR;
- else
- return YEAR_MONTH_DAY;
-}
-
static void hildon_child_forall(GtkContainer * container,
gboolean include_internals,
GtkCallback callback,
HildonDateEditor *editor;
HildonDateEditorPrivate *priv;
- g_return_if_fail(container);
- g_return_if_fail(callback);
+ g_assert(HILDON_IS_DATE_EDITOR(container));
+ g_assert(callback);
editor = HILDON_DATE_EDITOR(container);
priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
gtk_widget_unparent(priv->d_event_box_image);
priv->d_event_box_image = NULL;
}
+ if (priv->delims) {
+ g_list_free(priv->delims);
+ priv->delims = NULL;
+ }
if (GTK_OBJECT_CLASS(parent_class)->destroy)
GTK_OBJECT_CLASS(parent_class)->destroy(self);
/**
* hildon_date_editor_new:
*
- * This function creates a new time editor. The current system date
+ * Creates a new date editor. The current system date
* is shown in the editor.
*
- * Return value: Pointer to a new @HildonDateEditor widget.
- **/
+ * Returns: pointer to a new @HildonDateEditor widget.
+ */
GtkWidget *hildon_date_editor_new(void)
{
return GTK_WIDGET(g_object_new(HILDON_DATE_EDITOR_TYPE, NULL));
* @month: month
* @day: day
*
- * This function sets the date shown in the editor. The function returns
- * if the date specified by the arguments is not valid, the
- * function returns.
- **/
-void hildon_date_editor_set_date(HildonDateEditor * date,
+ * Sets the date shown in the editor.
+ */
+void hildon_date_editor_set_date(HildonDateEditor * editor,
guint year, guint month, guint day)
{
- g_return_if_fail(date);
- g_return_if_fail(HILDON_IS_DATE_EDITOR(date));
+ HildonDateEditorPrivate *priv;
+
+ g_return_if_fail(HILDON_IS_DATE_EDITOR(editor));
+
+ /* This function cannot be implemented by calling
+ component setters, since applying the individual
+ values one by one can make the date temporarily
+ invalid (depending on what the previous values were),
+ which in turn causes that the desired date
+ is not set (even though it's valid). We must set all the
+ components at one go and not try to do any validation etc
+ there in between. */
- hildon_date_editor_set_year(date, year);
- hildon_date_editor_set_month(date, month);
- hildon_date_editor_set_day(date, day);
+ g_return_if_fail(HILDON_IS_DATE_EDITOR(editor));
+ priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
+
+ if (g_date_valid_dmy(day, month, year))
+ {
+ GDate date;
+ gchar buffer[256];
+
+ priv->year = year;
+ priv->month = month;
+ priv->day = day;
+
+ g_date_set_dmy(&date, day, month, year);
+
+ /* We apply the new values, but do not want automatic focus move
+ etc to take place */
+ g_snprintf(buffer, sizeof(buffer), "%04d", year);
+ g_signal_handlers_block_by_func(priv->y_entry,
+ (gpointer) hildon_date_editor_entry_changed, editor);
+ gtk_entry_set_text(GTK_ENTRY(priv->y_entry), buffer);
+ g_signal_handlers_unblock_by_func(priv->y_entry,
+ (gpointer) hildon_date_editor_entry_changed, editor);
+
+ g_date_strftime(buffer, sizeof(buffer), "%m", &date);
+ g_signal_handlers_block_by_func(priv->m_entry,
+ (gpointer) hildon_date_editor_entry_changed, editor);
+ gtk_entry_set_text(GTK_ENTRY(priv->m_entry), buffer);
+ g_signal_handlers_unblock_by_func(priv->m_entry,
+ (gpointer) hildon_date_editor_entry_changed, editor);
+
+ g_date_strftime(buffer, sizeof(buffer), "%d", &date);
+ g_signal_handlers_block_by_func(priv->d_entry,
+ (gpointer) hildon_date_editor_entry_changed, editor);
+ gtk_entry_set_text(GTK_ENTRY(priv->d_entry), buffer);
+ g_signal_handlers_unblock_by_func(priv->d_entry,
+ (gpointer) hildon_date_editor_entry_changed, editor);
+
+ g_object_notify(G_OBJECT(editor), "year");
+ g_object_notify(G_OBJECT(editor), "month");
+ g_object_notify(G_OBJECT(editor), "day");
+ }
}
/**
* @month: month
* @day: day
*
- * This function returns the year, month, and day currently on the
+ * Returns: the year, month, and day currently on the
* date editor.
- **/
+ */
void hildon_date_editor_get_date(HildonDateEditor * date,
guint * year, guint * month, guint * day)
{
HildonDateEditorPrivate *priv;
- g_return_if_fail(date);
g_return_if_fail(HILDON_IS_DATE_EDITOR(date));
g_return_if_fail(year);
g_return_if_fail(month);
priv = HILDON_DATE_EDITOR_GET_PRIVATE(date);
- /*dont know why these variable are used, i think it makes more
- * sense to directly get the content from the current text entry field*/
+ /* FIXME: The role of priv->{day,month,year} members vs. entry contents
+ is unclear. They do not neccesarily match and still the texts are
+ used as return values and members for some internal validation!!
+ At least a partly reason is to allow empty text to become
+ 0 return value, while members are restricted to valid ranges?!
+ However, if we change the current way, we are likely to break
+ some applications if they rely on some specific way how this
+ widget currently handles empty values and temporarily invalid values.
+
+ The key issue is this: What should the _get methods return while
+ user is editing a field and the result is incomplete. The
+ partial result? The last good result? If we return partial result
+ we also need a way to inform if the date is not valid. Current
+ implementation is some kind of hybrid of these two...
+
+ for example:
+ hildon_date_editor_set_day(editor, hildon_date_editor_get_day(editor));
+
+ easily fails, since set_day tries to force validity while get_day
+ doesn't do that.
+
+ Proposal: Always return the same values that are shown in the
+ fields. We add a separate flag (Or use GDate) to
+ indicate if the current date is valid. This would allow
+ setters to make the date invalid as well.
+ */
*year = /*priv->year;*/
(guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->y_entry)));
*month = /*priv->month;*/
GdkEventButton * event,
gpointer data)
{
- HildonDateEditor *ed;
- HildonDateEditorPrivate *priv;
+ g_assert(GTK_IS_WIDGET(widget));
+ g_assert(event != NULL);
+ g_assert(HILDON_IS_DATE_EDITOR(data));
- g_return_val_if_fail(widget, FALSE);
- g_return_val_if_fail(event, FALSE);
- g_return_val_if_fail(data, FALSE);
-
- ed = HILDON_DATE_EDITOR(data);
- priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
+ if (event->button == 1)
+ hildon_date_editor_set_calendar_icon_state(HILDON_DATE_EDITOR(data), TRUE);
- if (event->button == 1 && !priv->button_press) {
- gtk_container_remove(GTK_CONTAINER(priv->d_event_box_image),
- priv->d_image);
- gtk_container_add(GTK_CONTAINER(priv->d_event_box_image),
- priv->d_image_pressed);
- gtk_widget_show_all(priv->d_event_box_image);
- priv->button_press = TRUE;
- }
return FALSE;
}
ed = HILDON_DATE_EDITOR(data);
priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
- if (priv->valid_value && event->button == 1) {
-
- /* We might not get focus because unvalid values in entries */
+ if (event->button == 1) {
+ /* We might not get focus because of invalid values in entries */
if (GTK_WIDGET_HAS_FOCUS(widget))
g_idle_add((GSourceFunc)
_hildon_date_editor_entry_select_all, GTK_ENTRY(widget));
- } else
- priv->valid_value = TRUE;
+ }
+
return FALSE;
}
}
-/* This handler is called from mainloop
- after button exposes are processed */
-static gboolean idle_popup(gpointer data)
+static void popup_calendar_dialog(HildonDateEditor *ed)
{
guint y = 0, m = 0, d = 0;
- HildonDateEditor *ed;
GtkWidget *popup;
GtkWidget *parent;
guint result;
-
- ed = HILDON_DATE_EDITOR(data);
+ GValue val = {0, };
hildon_date_editor_get_date(ed, &y, &m, &d);
parent = gtk_widget_get_ancestor(GTK_WIDGET(ed), GTK_TYPE_WINDOW);
popup = hildon_calendar_popup_new(GTK_WINDOW(parent), y, m, d);
+ g_value_init(&val, G_TYPE_INT);
+ /* Set max/min year in calendar popup to date editor values */
+ g_object_get_property(G_OBJECT(ed), "min-year", &val);
+ g_object_set_property(G_OBJECT(popup), "min-year", &val);
+ g_object_get_property(G_OBJECT(ed), "max-year", &val);
+ g_object_set_property(G_OBJECT(popup), "max-year", &val);
+
+ /* Pop up calendar */
result = gtk_dialog_run(GTK_DIALOG(popup));
switch (result) {
case GTK_RESPONSE_OK:
}
gtk_widget_destroy(popup);
-
- return FALSE;
}
/* button released */
gpointer data)
{
HildonDateEditor *ed;
- HildonDateEditorPrivate *priv;
- g_return_val_if_fail(widget, FALSE);
- g_return_val_if_fail(event, FALSE);
- g_return_val_if_fail(data, FALSE);
+ g_assert(GTK_IS_WIDGET(widget));
+ g_assert(event != NULL);
+ g_assert(HILDON_IS_DATE_EDITOR(data));
ed = HILDON_DATE_EDITOR(data);
- priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
-
- if (!priv->button_press)
- return FALSE;
-
- /* change the icon image back to normal */
- gtk_container_remove(GTK_CONTAINER(priv->d_event_box_image),
- priv->d_image_pressed);
- gtk_container_add(GTK_CONTAINER(priv->d_event_box_image),
- priv->d_image);
- gtk_widget_show_all(priv->d_event_box_image);
-
- /* Wait until exposes are ready */
- g_idle_add(idle_popup, ed);
- priv->button_press = FALSE;
+ if (hildon_date_editor_set_calendar_icon_state(ed, FALSE))
+ popup_calendar_dialog(ed);
return FALSE;
}
+/* This is called whenever some editor filed loses the focus and
+ when the all of the fields are filled.
+ Earlier this was called whenever an entry changed */
+/* FIXME: Validation on focus_out is broken by concept */
static void
-hildon_date_editor_entry_validate(GtkEditable *widget, gpointer data)
+hildon_date_editor_entry_validate(GtkWidget *widget, gpointer data)
{
HildonDateEditor *ed;
HildonDateEditorPrivate *priv;
+ gint d, m, y, max_days;
+ gboolean r; /* temp return values for signals */
+ const gchar *text;
+ gint error_code = NO_ERROR;
- gint d, m, y;
- gboolean r; /*return value storage needed, but no real use*/
-
- g_return_if_fail(data);
- g_return_if_fail(widget);
+ g_assert(HILDON_IS_DATE_EDITOR(data));
+ g_assert(GTK_IS_ENTRY(widget));
ed = HILDON_DATE_EDITOR(data);
priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
- /*if the field is empty, we skip the checking*/
- if(gtk_entry_get_text(GTK_ENTRY(widget)) == NULL ||
- *gtk_entry_get_text(GTK_ENTRY(widget)) == '\0')
- return;
-
- if(!priv->skip_validation) {
- d = atoi(gtk_entry_get_text(GTK_ENTRY(priv->d_entry)));
- m = atoi(gtk_entry_get_text(GTK_ENTRY(priv->m_entry)));
- y = atoi(gtk_entry_get_text(GTK_ENTRY(priv->y_entry)));
-
- /*NOTICE we could/should use hildon_date_editor_set_year and such functions
- * to set the date, instead of use gtk_entry_set_text, and then change the priv member
- * but hildon_date_editor_set_year and such functions check if the date is valid,
- * we do want to do date validation check here according to spec*/
- if(GTK_WIDGET(widget) == priv->d_entry)
- {
- if(d > 0 && d < 32) {
- priv->day = d;
- return;
- }
- else if(d < 1) {
- g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0,
- MIN_DAY, &r);
- gtk_entry_set_text(GTK_ENTRY(priv->d_entry), "01");
- priv->day = priv->d_orig = 1;
+ if (priv->skip_validation)
+ return;
+
+ /*check if the calling entry is empty*/
+ text = gtk_entry_get_text(GTK_ENTRY(widget));
+ if(text == NULL || text[0] == 0)
+ {
+ if (widget == priv->d_entry)
+ g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0, EMPTY_DAY, &r);
+ else if(widget == priv->m_entry)
+ g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0, EMPTY_MONTH, &r);
+ else
+ g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0, EMPTY_YEAR, &r);
+
+ return;
+ }
+
+ /* Ok, we now check validity. Some fields can be empty */
+ text = gtk_entry_get_text(GTK_ENTRY(priv->d_entry));
+ if (text == NULL || text[0] == 0) return;
+ d = atoi(text);
+ text = gtk_entry_get_text(GTK_ENTRY(priv->m_entry));
+ if (text == NULL || text[0] == 0) return;
+ m = atoi(text);
+ text = gtk_entry_get_text(GTK_ENTRY(priv->y_entry));
+ if (text == NULL || text[0] == 0) return;
+ y = atoi(text);
+
+ /* Did it actually change? */
+ if (d != priv->day || m != priv->month || y != priv->year)
+ {
+ /* We could/should use hildon_date_editor_set_year and such functions
+ * to set the date, instead of use gtk_entry_set_text, and then change
+ * the priv member but hildon_date_editor_set_year and such functions
+ * check if the date is valid, we do want to do date validation check
+ * here according to spec */
+
+ /* Validate month */
+ if(widget == priv->m_entry) {
+ if(m < 1) {
+ error_code = MIN_MONTH;
+ m = 1;
}
- else {
- g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0,
- MAX_DAY, &r);
- gtk_entry_set_text(GTK_ENTRY(priv->d_entry), "31");
- priv->day = priv->d_orig = 31;
+ else if (m > 12) {
+ error_code = MAX_MONTH;
+ m = 12;
}
- g_idle_add ((GSourceFunc)
- _hildon_date_editor_entry_select_all,
- priv->d_entry);
- return;
}
- if(GTK_WIDGET(widget) == priv->m_entry)
- {
- if(m > 0 && m < 13)
- {
- priv->month = m;
- return;
- }
- else if(m < 1)
- {
- g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0,
- MIN_MONTH, &r);
- gtk_entry_set_text(GTK_ENTRY(priv->m_entry), "01");
- priv->month = priv->m_orig = 1;
-
+ /* Validate year */
+ if(widget == priv->y_entry) {
+ if (y < priv->min_year) {
+ error_code = MIN_YEAR;
+ y = priv->min_year;
}
- else
- {
- g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0,
- MAX_MONTH, &r);
- gtk_entry_set_text(GTK_ENTRY(priv->m_entry), "12");
- priv->month = priv->m_orig = 12;
+ else if (y > priv->max_year) {
+ error_code = MAX_YEAR;
+ y = priv->max_year;
}
+ }
- g_idle_add ((GSourceFunc)
- _hildon_date_editor_entry_select_all,
- priv->m_entry);
- return;
+ /* Validate day. We have to do this in every case, since
+ changing month or year can make the day number to be invalid */
+ max_days = g_date_get_days_in_month(m,y);
+ if(d < 1) {
+ error_code = MIN_DAY;
+ d = 1;
+ }
+ else if (d > max_days) {
+ if (d > 31) {
+ error_code = MAX_DAY;
+ d = max_days;
+ }
+ else { /* the date does not exist (is invalid) */
+ error_code = INVALID_DATE;
+ /* check what was changed and restore previous value */
+ if ( widget == priv->y_entry )
+ y = priv->year;
+ else if ( widget == priv->m_entry )
+ m = priv->month;
+ else
+ d = priv->day;
+ }
}
- if(GTK_WIDGET(widget) == priv->y_entry)
+ if (error_code != NO_ERROR)
{
- if(y >= 1 && y <= 2100) {
- priv->year = y;
- return;
- }
- else if(y < 1) {
- g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0,
- MIN_YEAR, &r);
- gtk_entry_set_text(GTK_ENTRY(priv->y_entry), "0001");
- priv->year = priv->y_orig = 1;
- }
- /* y > 2100 */
- else {
- g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0,
- MAX_YEAR, &r);
- gtk_entry_set_text(GTK_ENTRY(priv->y_entry), "2100");
- priv->year = priv->y_orig = 2100;
- }
+ g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0, error_code, &r);
+
g_idle_add ((GSourceFunc)
_hildon_date_editor_entry_select_all,
- priv->y_entry);
- return;
+ widget);
+
+ /* Set focus back to invalid entry */
+ gtk_widget_grab_focus(widget);
}
}
+
+ /* Fix and reformat the date after error signal is processed.
+ reformatting can be needed even in a such case that numerical
+ values of the date components are the same as earlier. */
+ hildon_date_editor_set_date(ed, y, m, d);
+}
+
+/* When entry becomes full, we move the focus to the next field.
+ If we are on the last field, the whole contents are validated. */
+static void
+hildon_date_editor_entry_changed(GtkEditable *ed, gpointer data)
+{
+ GtkEntry *entry;
+
+ g_assert(GTK_IS_ENTRY(ed));
+ g_assert(HILDON_IS_DATE_EDITOR(data));
+
+ entry = GTK_ENTRY(ed);
+
+ /* If day entry is full, move to next entry or validate */
+ if (g_utf8_strlen(gtk_entry_get_text(entry), -1) == gtk_entry_get_max_length(entry))
+ {
+ if (!gtk_widget_child_focus(GTK_WIDGET(data), GTK_DIR_RIGHT))
+ hildon_date_editor_entry_validate(GTK_WIDGET(entry), data);
+ }
}
static gboolean hildon_date_editor_keyrelease(GtkWidget * widget,
if (event->keyval == GDK_KP_Enter || event->keyval == GDK_Return ||
event->keyval == GDK_ISO_Enter) {
- if (priv->editor_pressed) {
- gtk_container_remove(GTK_CONTAINER(priv->d_event_box_image),
- priv->d_image_pressed);
- gtk_container_add(GTK_CONTAINER(priv->d_event_box_image),
- priv->d_image);
- gtk_widget_show_all(priv->d_event_box_image);
- g_idle_add(idle_popup, ed);
- priv->editor_pressed = FALSE;
+ if (hildon_date_editor_set_calendar_icon_state(ed, FALSE))
+ {
+ popup_calendar_dialog(ed);
return TRUE;
}
} else if (event->keyval == GDK_Escape)
GdkEventKey * event,
gpointer data)
{
-
HildonDateEditor *ed;
HildonDateEditorPrivate *priv;
gint pos;
- g_return_val_if_fail(data, FALSE);
- g_return_val_if_fail(widget, FALSE);
+ g_assert(HILDON_IS_DATE_EDITOR(data));
+ g_assert(GTK_IS_ENTRY(widget));
ed = HILDON_DATE_EDITOR(data);
priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
pos = gtk_editable_get_position(GTK_EDITABLE(widget));
-
- if (event->keyval == GDK_Return || event->keyval == GDK_ISO_Enter) {
- if (!priv->editor_pressed) {
- gtk_container_remove(GTK_CONTAINER(priv->d_event_box_image),
- priv->d_image);
- gtk_container_add(GTK_CONTAINER(priv->d_event_box_image),
- priv->d_image_pressed);
- gtk_widget_show_all(priv->d_event_box_image);
- priv->editor_pressed = TRUE;
- return TRUE;
- }
- return FALSE;
- }
-
- if (event->keyval == GDK_KP_Enter)
- return FALSE;
-
-
- /* We don't want wrap */
- if (event->keyval == GDK_KP_Left || event->keyval == GDK_Left)
- if (pos == 0) {
- if (priv->locale_type == DAY_MONTH_YEAR) {
- if (widget == priv->d_entry)
- return TRUE;
- } else {
- if (widget == priv->m_entry)
- return TRUE;
- }
- }
-
- if (event->keyval == GDK_KP_Right || event->keyval == GDK_Right)
- if (widget == priv->y_entry
- && pos >= strlen(GTK_ENTRY(widget)->text))
- return TRUE;
-
switch (event->keyval) {
case GDK_Left:
- /* left on day entry */
- if (widget == priv->d_entry) {
- gint pos =
- gtk_editable_get_position(GTK_EDITABLE(priv->d_entry));
- if (pos == 0) {
- gtk_editable_select_region(GTK_EDITABLE(priv->d_entry), 0,
- 0);
- if (priv->locale_type == DAY_MONTH_YEAR) {
- gtk_widget_grab_focus(priv->y_entry);
- gtk_editable_set_position(GTK_EDITABLE(priv->y_entry),
- -1);
- } else {
- gtk_widget_grab_focus(priv->m_entry);
- gtk_editable_set_position(GTK_EDITABLE(priv->m_entry),
- -1);
- }
- return TRUE;
- }
- }
- /* left on month entry */
- else if (widget == priv->m_entry) {
- gint pos =
- gtk_editable_get_position(GTK_EDITABLE(priv->m_entry));
-
- /* switch to day entry */
- if (pos == 0) {
- gtk_editable_select_region(GTK_EDITABLE(priv->m_entry), 0,
- 0);
- if (priv->locale_type == DAY_MONTH_YEAR) {
- gtk_widget_grab_focus(priv->d_entry);
- gtk_editable_set_position(GTK_EDITABLE(priv->d_entry),
- -1);
- } else {
- gtk_widget_grab_focus(priv->y_entry);
- }
- gtk_editable_set_position(GTK_EDITABLE(priv->y_entry), -1);
- return TRUE;
- }
- }
- /* left on year entry */
- else if (widget == priv->y_entry) {
- gint pos =
- gtk_editable_get_position(GTK_EDITABLE(priv->y_entry));
-
- /* switch to month entry */
- if (pos == 0) {
- gtk_editable_select_region(GTK_EDITABLE(priv->y_entry), 0,
- 0);
- if (priv->locale_type == DAY_MONTH_YEAR) {
- gtk_widget_grab_focus(priv->m_entry);
- gtk_editable_set_position(GTK_EDITABLE(priv->m_entry),
- -1);
- } else {
- gtk_widget_grab_focus(priv->d_entry);
- gtk_editable_set_position(GTK_EDITABLE(priv->d_entry),
- -1);
- }
- return TRUE;
- }
- }
- return FALSE;
-
+ (void) gtk_widget_child_focus(GTK_WIDGET(data), GTK_DIR_LEFT);
+ return TRUE;
+ break;
case GDK_Right:
- /* right on day entry */
- if (widget == priv->d_entry) {
- gint pos =
- gtk_editable_get_position(GTK_EDITABLE(priv->d_entry));
- gint len = gtk_entry_get_max_length(GTK_ENTRY(priv->d_entry));
- gint chars =
- g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(priv->d_entry)),
- len);
-
- /* switch to month entry */
- if ((pos == len) || (pos > chars)) {
- gtk_editable_select_region(GTK_EDITABLE(priv->d_entry), 0,
- 0);
- if (priv->locale_type == DAY_MONTH_YEAR) {
- gtk_widget_grab_focus(priv->m_entry);
- gtk_editable_set_position(GTK_EDITABLE(priv->m_entry),
- 0);
- } else {
- gtk_widget_grab_focus(priv->y_entry);
- gtk_editable_set_position(GTK_EDITABLE(priv->y_entry),
- 0);
- }
- return TRUE;
- }
- }
- /* right on month entry */
- else if (widget == priv->m_entry) {
- gint pos =
- gtk_editable_get_position(GTK_EDITABLE(priv->m_entry));
- gint len = gtk_entry_get_max_length(GTK_ENTRY(priv->m_entry));
- gint chars =
- g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(priv->m_entry)),
- len);
-
- /* switch to year entry */
- if ((pos == len) || (pos > chars)) {
- gtk_editable_select_region(GTK_EDITABLE(priv->m_entry), 0,
- 0);
- if (priv->locale_type == DAY_MONTH_YEAR) {
- gtk_widget_grab_focus(priv->y_entry);
- gtk_editable_set_position(GTK_EDITABLE(priv->y_entry),
- 0);
- } else {
- gtk_widget_grab_focus(priv->d_entry);
- gtk_editable_set_position(GTK_EDITABLE(priv->d_entry),
- 0);
- }
- return TRUE;
- }
- }
- /* right on year entry */
- else if (widget == priv->y_entry) {
- gint pos =
- gtk_editable_get_position(GTK_EDITABLE(priv->y_entry));
- gint len = gtk_entry_get_max_length(GTK_ENTRY(priv->y_entry));
- gint chars =
- g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(priv->y_entry)),
- len);
-
- /* switch to day entry */
- if ((pos == len) || (pos > chars)) {
- gtk_editable_select_region(GTK_EDITABLE(priv->y_entry), 0,
- 0);
- if (priv->locale_type == DAY_MONTH_YEAR) {
- gtk_widget_grab_focus(priv->d_entry);
- gtk_editable_set_position(GTK_EDITABLE(priv->d_entry),
- 0);
- } else {
- gtk_widget_grab_focus(priv->y_entry);
- gtk_editable_set_position(GTK_EDITABLE(priv->y_entry),
- 0);
- }
- return TRUE;
- }
- }
- return FALSE;
-
- /* all digit keys */
- case GDK_0:
- case GDK_1:
- case GDK_2:
- case GDK_3:
- case GDK_4:
- case GDK_5:
- case GDK_6:
- case GDK_7:
- case GDK_8:
- case GDK_9:
- {
- if ((widget == priv->d_entry) || (widget == priv->m_entry) ||
- (widget == priv->y_entry)) {
- GtkWidgetClass *cl = GTK_WIDGET_GET_CLASS(widget);
-
- cl->key_press_event(widget, event);
- } else
- return TRUE;
- }
- return TRUE;
-
- /* accepts these as is */
- case GDK_Tab:
- case GDK_Shift_L:
- case GDK_Shift_R:
- case GDK_BackSpace:
- case GDK_Delete:
- case GDK_Up:
- case GDK_Down:
- return FALSE;
+ (void) gtk_widget_child_focus(GTK_WIDGET(data), GTK_DIR_RIGHT);
+ return TRUE;
+ break;
+ case GDK_Return:
+ case GDK_ISO_Enter:
+ /* Ignore return value, since we want to handle event at all times.
+ otherwise vkb would popup when the keyrepeat starts. */
+ (void) hildon_date_editor_set_calendar_icon_state(ed, TRUE);
+ return TRUE;
case GDK_Escape:
priv->skip_validation = TRUE;
- return FALSE;
-
- /* select date */
+ break;
default:
- return TRUE;
+ break;
}
+
+ return FALSE;
}
static gboolean hildon_date_editor_entry_focus_out(GtkWidget * widget,
GdkEventFocus * event,
gpointer data)
{
- HildonDateEditor *ed;
- HildonDateEditorPrivate *priv;
- gint d, m, y;
- gboolean r; /*for the sake of signal emission*/
- GDate gd;
-
- ed = HILDON_DATE_EDITOR(data);
- priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
-
- if (priv->skip_validation)
- return FALSE;
-
- /*check if the calling entry is empty*/
- if(gtk_entry_get_text(GTK_ENTRY(widget)) == NULL ||
- *(gtk_entry_get_text(GTK_ENTRY(widget))) == '\0')
- {
- if(widget == priv->d_entry)
- g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0,
- EMPTY_DAY, &r);
- else if(widget == priv->m_entry)
- g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0,
- EMPTY_MONTH, &r);
- else
- g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0,
- EMPTY_YEAR, &r);
-
- return FALSE;
- }
-
- /*date validation starts*/
- d = atoi(gtk_entry_get_text(GTK_ENTRY(priv->d_entry)));
- m = atoi(gtk_entry_get_text(GTK_ENTRY(priv->m_entry)));
- y = atoi(gtk_entry_get_text(GTK_ENTRY(priv->y_entry)));
-
- /*the only reason why a date is not valid is because that
- * some months dont have 31st 30th or even 29th(since we
- * have done max and min range checking for each field), for
- * now we will only fix day field, if trying to fix day
- * field fails to make the date valid, we will set the
- * date to be current date, if any value is 0, that means
- * this entry is empty, therefore skip validation*/
-
- if(d != 0 && m != 0 && y != 0 && !g_date_valid_dmy(d, m, y))
- {
- gint new_d;
- gint max_d;
- gchar day_str[3];
-
- g_signal_emit(ed, date_editor_signals[DATE_ERROR], 0,
- INVALID_DATE, &r);
-
- max_d = g_date_get_days_in_month(m,y);
-
- if(priv->d_orig <= max_d && priv->d_orig > 0)
- new_d = priv->d_orig;
- else
- new_d = priv->d_orig = max_d;
-
- if(g_date_valid_dmy(new_d, m, y))
- {
- d = priv->day = new_d;
- sprintf(day_str, "%02d", new_d);
- gtk_entry_set_text(GTK_ENTRY(priv->d_entry), day_str);
- }
- else
- {
- g_date_clear(&gd, 1);
- g_date_set_time(&gd, time(NULL));
- d = g_date_get_year(&gd);
- m = g_date_get_month(&gd);
- y = g_date_get_day(&gd);
- }
-
- gtk_widget_grab_focus(priv->d_entry);
- g_idle_add((GSourceFunc)
- _hildon_date_editor_entry_select_all, priv->d_entry);
- }
- /*make sure to have 0 in front single digits*/
- hildon_date_editor_set_date(ed, (guint) y, (guint) m, (guint) d);
+ hildon_date_editor_entry_validate(widget, data);
return FALSE;
}
hildon_date_editor_date_error(HildonDateEditor *editor,
HildonDateEditorErrorType type)
{
+ HildonDateEditorPrivate *priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
+
switch(type)
{
case MAX_DAY:
gtk_infoprintf(NULL, _("Ckct_ib_maximum_value"), 12);
break;
case MAX_YEAR:
- gtk_infoprintf(NULL, _("Ckct_ib_maximum_value"), 2100);
+ gtk_infoprintf(NULL, _("Ckct_ib_maximum_value"), priv->max_year);
break;
case MIN_DAY:
case MIN_MONTH:
- case MIN_YEAR:
gtk_infoprintf(NULL, _("Ckct_ib_minimum_value"), 1);
break;
+ case MIN_YEAR:
+ gtk_infoprintf(NULL, _("Ckct_ib_minimum_value"), priv->min_year);
+ break;
case EMPTY_DAY:
gtk_infoprintf(NULL, _("Ckct_ib_set_a_value_within_range"), 1, 31);
break;
gtk_infoprintf(NULL, _("Ckct_ib_set_a_value_within_range"), 1, 12);
break;
case EMPTY_YEAR:
- gtk_infoprintf(NULL, _("Ckct_ib_set_a_value_within_range"), 1, 2100);
+ gtk_infoprintf(NULL, _("Ckct_ib_set_a_value_within_range"),
+ priv->min_year, priv->max_year);
break;
case INVALID_DATE:
gtk_infoprint(NULL, _("Ckct_ib_date_does_not_exist"));
{
HildonDateEditor *ed;
HildonDateEditorPrivate *priv;
- GtkRequisition d_req, m_req, y_req, f_req, img_req;
+ GtkRequisition f_req, img_req;
- g_return_if_fail(widget);
- g_return_if_fail(requisition);
+ g_assert(GTK_IS_WIDGET(widget));
+ g_assert(requisition != NULL);
ed = HILDON_DATE_EDITOR(widget);
priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
- /* call size request for entries */
- gtk_widget_size_request(priv->d_entry, &d_req);
- gtk_widget_size_request(priv->m_entry, &m_req);
- gtk_widget_size_request(priv->y_entry, &y_req);
-
- /* set entry widths to width_of_digit * 2 + border */
- d_req.width = (hildon_date_editor_get_font_width(priv->d_entry) << 1)
- + ENTRY_BORDERS;
- m_req.width = (hildon_date_editor_get_font_width(priv->m_entry) << 1)
- + ENTRY_BORDERS;
- y_req.width = (hildon_date_editor_get_font_width(priv->y_entry) << 2)
- + ENTRY_BORDERS;
-
- gtk_widget_set_size_request(priv->d_entry, d_req.width, d_req.height);
- gtk_widget_set_size_request(priv->m_entry, m_req.width, m_req.height);
- gtk_widget_set_size_request(priv->y_entry, y_req.width, y_req.height);
-
-
+ /* Our own children affect our size */
gtk_widget_size_request(priv->frame, &f_req);
gtk_widget_size_request(priv->d_event_box_image, &img_req);
/* calculate our size */
- requisition->width = f_req.width + img_req.width + BUTTON_SPACING;
+ requisition->width = f_req.width + img_req.width + HILDON_MARGIN_DEFAULT;
+
+ /* FIXME: Fixed size is bad! We should use the maximum of our children, but
+ doing so would break current pixel specifications, since
+ the text entry by itself is already 30px tall + then frame takes
+ something */
requisition->height = DATE_EDITOR_HEIGHT;
}
GtkAllocation f_alloc, img_alloc;
GtkRequisition req;
GtkRequisition max_req;
+ GList *iter;
- g_return_if_fail(widget);
- g_return_if_fail(allocation);
+ g_assert(GTK_IS_WIDGET(widget));
+ g_assert(allocation != NULL);
ed = HILDON_DATE_EDITOR(widget);
priv = HILDON_DATE_EDITOR_GET_PRIVATE(ed);
gtk_widget_get_child_requisition(widget, &max_req);
+ /* Center vertically */
f_alloc.y = img_alloc.y = allocation->y +
MAX(allocation->height - max_req.height, 0) / 2;
+ /* Center horizontally */
f_alloc.x = img_alloc.x = allocation->x +
MAX(allocation->width - max_req.width, 0) / 2;
/* allocate frame */
- if (priv->frame)
if (GTK_WIDGET_VISIBLE(priv->frame)) {
gtk_widget_get_child_requisition(priv->frame, &req);
gtk_widget_size_allocate(priv->frame, &f_alloc);
}
- /* allocate entry box */
- if (priv->d_event_box_image)
+ /* allocate icon */
if (GTK_WIDGET_VISIBLE(priv->d_event_box_image)) {
gtk_widget_get_child_requisition(priv->d_event_box_image,
&req);
- img_alloc.x += f_alloc.width + BUTTON_SPACING;
+ img_alloc.x += f_alloc.width + HILDON_MARGIN_DEFAULT;
img_alloc.width = req.width;
img_alloc.height = max_req.height;
gtk_widget_size_allocate(priv->d_event_box_image, &img_alloc);
}
- priv->dm_delim->allocation.height = max_req.height;
- priv->my_delim->allocation.height = max_req.height;
- priv->my_delim->allocation.y = priv->d_entry->allocation.y-5;
- priv->dm_delim->allocation.y = priv->d_entry->allocation.y-5;
- gtk_widget_size_allocate(priv->dm_delim, &priv->dm_delim->allocation);
- gtk_widget_size_allocate(priv->my_delim, &priv->my_delim->allocation);
-}
-
-/* calculate approximate width of a digit */
-static int hildon_date_editor_get_font_width(GtkWidget * widget)
-{
- PangoContext *context;
- PangoFontMetrics *metrics;
- gint digit_width;
-
- context = gtk_widget_get_pango_context(widget);
- metrics = pango_context_get_metrics(context, widget->style->font_desc,
- pango_context_get_language
- (context));
-
- digit_width = pango_font_metrics_get_approximate_digit_width(metrics);
- digit_width = PANGO_PIXELS(digit_width);
+ /* FIXME: We really should not alloc delimeters by hand (since they
+ are not our own children, but we need to force to appear
+ higher. This ugly hack is needed to compensate the forced
+ height in size_request. */
+ for (iter = priv->delims; iter; iter = iter->next)
+ {
+ GtkWidget *delim;
+ GtkAllocation alloc;
- pango_font_metrics_unref(metrics);
+ delim = GTK_WIDGET(iter->data);
+ alloc = delim->allocation;
+ alloc.height = max_req.height;
+ alloc.y = priv->d_entry->allocation.y - 2;
- return digit_width;
+ gtk_widget_size_allocate(delim, &alloc);
+ }
}
/**
* @editor: the @HildonDateEditor widget
* @year: year
*
- * This function sets the year shown in the editor.
+ * Sets the year shown in the editor.
*
- * Return: Returns TRUE if the year is valid.
- **/
+ * Returns: TRUE if the year is valid
+ */
gboolean hildon_date_editor_set_year(HildonDateEditor *editor, guint year)
{
HildonDateEditorPrivate *priv;
if (g_date_valid_dmy(priv->day, priv->month, year))
{
- gchar str[MAX_DATE_LEN + 1];
+ gchar buffer[256];
priv->year = year;
- sprintf(str, "%04d", year);
- gtk_entry_set_text(GTK_ENTRY(priv->y_entry), str);
+ g_snprintf(buffer, sizeof(buffer), "%04d", year);
+
+ /* We apply the new day, but do not want automatic focus move
+ etc to take place */
+ g_signal_handlers_block_by_func(priv->y_entry,
+ (gpointer) hildon_date_editor_entry_changed, editor);
+ gtk_entry_set_text(GTK_ENTRY(priv->y_entry), buffer);
+ g_signal_handlers_unblock_by_func(priv->y_entry,
+ (gpointer) hildon_date_editor_entry_changed, editor);
g_object_notify(G_OBJECT(editor), "year");
return TRUE;
* @editor: the @HildonDateEditor widget
* @month: month
*
- * This function sets the month shown in the editor.
+ * Sets the month shown in the editor.
*
- * Return: Returns TRUE if the month is valid.
- **/
+ * Returns: TRUE if the month is valid
+ */
gboolean hildon_date_editor_set_month(HildonDateEditor *editor, guint month)
{
HildonDateEditorPrivate *priv;
if (g_date_valid_dmy(priv->day, month, priv->year))
{
GDate date;
- gchar str[MAX_DATE_LEN + 1];
+ gchar buffer[256];
+
priv->month = month;
g_date_set_dmy(&date, priv->day, month, priv->year);
+ g_date_strftime(buffer, sizeof(buffer), "%m", &date);
- g_date_strftime(str, MAX_DATE_LEN, "%m", &date);
- gtk_entry_set_text(GTK_ENTRY(priv->m_entry), str);
+ /* We apply the new day, but do not want automatic focus move
+ etc to take place */
+ g_signal_handlers_block_by_func(priv->m_entry,
+ (gpointer) hildon_date_editor_entry_changed, editor);
+ gtk_entry_set_text(GTK_ENTRY(priv->m_entry), buffer);
+ g_signal_handlers_unblock_by_func(priv->m_entry,
+ (gpointer) hildon_date_editor_entry_changed, editor);
g_object_notify(G_OBJECT(editor), "month");
return TRUE;
* @editor: the @HildonDateEditor widget
* @day: day
*
- * This function sets the day shown in the editor.
+ * Sets the day shown in the editor.
*
- * Return: Returns TRUE if the day is valid.
- **/
+ * Returns: TRUE if the day is valid
+ */
gboolean hildon_date_editor_set_day(HildonDateEditor *editor, guint day)
{
HildonDateEditorPrivate *priv;
if (g_date_valid_dmy(day, priv->month, priv->year))
{
GDate date;
- gchar str[MAX_DATE_LEN + 1];
+ gchar buffer[256];
+
priv->day = day;
g_date_set_dmy(&date, day, priv->month, priv->year);
+ g_date_strftime(buffer, sizeof(buffer), "%d", &date);
- g_date_strftime(str, MAX_DATE_LEN, "%d", &date);
- gtk_entry_set_text(GTK_ENTRY(priv->d_entry), str);
+ /* We apply the new day, but do not want automatic focus move
+ etc to take place */
+ g_signal_handlers_block_by_func(priv->d_entry,
+ (gpointer) hildon_date_editor_entry_changed, editor);
+ gtk_entry_set_text(GTK_ENTRY(priv->d_entry), buffer);
+ g_signal_handlers_unblock_by_func(priv->d_entry,
+ (gpointer) hildon_date_editor_entry_changed, editor);
g_object_notify(G_OBJECT(editor), "day");
return TRUE;
* hildon_date_editor_get_year:
* @editor: the @HildonDateEditor widget
*
- * This function gets the year shown in the editor.
- *
- * Return: Returns the current year shown in the editor.
- **/
+ * Returns: the current year shown in the editor.
+ */
guint hildon_date_editor_get_year(HildonDateEditor *editor)
{
HildonDateEditorPrivate *priv;
g_return_val_if_fail( HILDON_IS_DATE_EDITOR(editor), 0 );
priv = HILDON_DATE_EDITOR_GET_PRIVATE(editor);
- /*change to have the content in the entry*/
return (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->y_entry)));
}
* hildon_date_editor_get_month:
* @editor: the @HildonDateEditor widget
*
- * This function gets the month shown in the editor.
+ * Gets the month shown in the editor.
*
- * Return: Returns the current month shown in the editor.
- **/
+ * Returns: the current month shown in the editor.
+ */
guint hildon_date_editor_get_month(HildonDateEditor *editor)
{
* hildon_date_editor_get_day:
* @editor: the @HildonDateEditor widget
*
- * This function gets the day shown in the editor.
+ * Gets the day shown in the editor.
*
- * Return: Returns the current day shown in the editor.
- **/
+ * Returns: the current day shown in the editor
+ */
guint hildon_date_editor_get_day(HildonDateEditor *editor)
{
return (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->d_entry)));
}
+/* Idle callback */
static gboolean
_hildon_date_editor_entry_select_all (GtkWidget *widget)
{