* hildon-widgets/hildon-scroll-area.c (hildon_scroll_area_destroy): one-instruction...
[hildon] / hildon-widgets / hildon-time-editor.c
1 /*
2  * This file is part of hildon-libs
3  *
4  * Copyright (C) 2005 Nokia Corporation.
5  *
6  * Contact: Luc Pionchon <luc.pionchon@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 /* HILDON DOC
26  * @shortdesc: TimeEditor is a widget for setting, getting and showing a
27  * time.
28  * @longdesc: The Time Editor widget is used to enter the system time
29  * (hours and minutes) in the Date/Time system plugin. It is a composite
30  * widget consisting of two GtkEntry widgets that are placed next to each
31  * other. The leftmost GtkEntry is used to enter the hours, and it accepts
32  * the values 0--23, while the rightmost GtkEntry accepts values 0--59
33  * and is used to set the minutes. Between the two GtkEntries there
34  * is a label displaying a colon.
35  * </para><para>
36  * From the usability point of view, the GtkSpinbutton widget would
37  * have been a better choice than the GtkEntry widgets, but it uses
38  * floating point operations and is thus not acceptable in this
39  * project.
40  *
41  * @seealso: #HildonDateEditor
42  */
43
44 #ifdef HAVE_CONFIG_H
45 #include <config.h>
46 #endif
47
48 #include <pango/pango.h>
49 #include <gtk/gtkbox.h>
50 #include <gtk/gtkentry.h>
51 #include <gtk/gtk.h>
52 #include <gdk/gdkkeysyms.h>
53 #include <gtk/gtkwidget.h>
54
55 #include <string.h>
56 #include <time.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <ctype.h>
60 #include <langinfo.h>
61 #include <libintl.h>
62
63 #include <hildon-widgets/hildon-defines.h>
64 #include <hildon-widgets/hildon-time-editor.h>
65 #include <hildon-widgets/hildon-time-picker.h>
66 #include <hildon-widgets/gtk-infoprint.h>
67 #include <hildon-widgets/hildon-input-mode-hint.h>
68 #include "hildon-composite-widget.h"
69 #include "hildon-date-editor.h"
70
71 #define _(String) dgettext(PACKAGE, String)
72
73 /* empty space on left and right side of a GtkEntry. Space needed
74 is 12, we add 4 extra pixels so that the arabic locale works
75 correctly. (With 12 only one digit would be shown in the entries).
76 */
77 #define TIME_EDITOR_LBORDER         2
78 #define TIME_EDITOR_RBORDER         1
79 #define TIME_EDITOR_HEIGHT         28
80 #define TIME_EDITOR_CLOCK_BORDER    6
81 #define ENTRY_BORDER               2
82 #define ICON_WIDTH                 26
83 #define ICON_HEIGHT                26
84 #define ICON_PRESSED                4
85 #define ICON_NAME                  "qgn_widg_timedit"
86 #define ICON_SIZE                  "timepicker-size"
87 #define HILDON_TIME_EDITOR_GET_PRIVATE(obj) \
88     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
89      HILDON_TYPE_TIME_EDITOR, HildonTimeEditorPrivate));
90 #define MIN_DURATION 0
91 #define MAX_DURATION (3600 * 99) + (60 * 59) + 59
92
93 #define HILDON_TIME_EDITOR_TICKS_VALUE           0
94 #define HILDON_TIME_EDITOR_SHOW_SECONDS          TRUE
95 #define HILDON_TIME_EDITOR_DURATION_MODE         FALSE
96 #define HILDON_TIME_EDITOR_DURATION_LOWER_VALUE  0
97 #define HILDON_TIME_EDITOR_TIME_LOWER_VALUE      0
98 #define HILDON_TIME_EDITOR_TIME_UPPER_VALUE      (3600 * 23) + (60 * 59) + 59
99 #define HILDON_TIME_EDITOR_DURATION_UPPER_VALUE  (3600 * 99) + (60 * 59) + 59
100
101 #define HOURS_MAX_24   23
102 #define HOURS_MAX_12   12
103 #define HOURS_MIN_24   0
104 #define HOURS_MIN_12   1
105 #define MINUTES_MAX 59
106 #define SECONDS_MAX 59
107 #define MINUTES_MIN 0
108 #define SECONDS_MIN 0
109
110 static GtkContainerClass *parent_class;
111
112 typedef struct _HildonTimeEditorPrivate HildonTimeEditorPrivate;
113
114 enum
115 {
116         PROP_TICKS = 1,
117         PROP_DURATION_MODE,
118         PROP_DURATION_MIN,
119         PROP_DURATION_MAX,
120         PROP_SHOW_SECONDS
121 };
122
123 typedef enum
124 {
125   VALIDATION_ERROR, /* should never be returned, translates as system error */
126   VALIDATION_OK,
127   VALIDATION_DURATION_MAX,
128   VALIDATION_DURATION_MIN,
129   VALIDATION_TIME_HOURS,
130   VALIDATION_TIME_MINUTES,
131   VALIDATION_TIME_SECONDS,
132   VALIDATION_LAST
133 } HildonValidation;
134
135 /***
136  * Widget functions
137  */
138
139 static void
140 hildon_time_editor_class_init(HildonTimeEditorClass * editor_class);
141
142 static void hildon_time_editor_init(HildonTimeEditor * editor);
143
144 static void hildon_time_editor_finalize(GObject * obj_self);
145
146 static void hildon_time_editor_set_property( GObject *object, guint param_id,
147                                        const GValue *value, GParamSpec *pspec );
148 static void hildon_time_editor_get_property( GObject *object, guint param_id,
149                                          GValue *value, GParamSpec *pspec );
150
151 static void
152 hildon_time_editor_forall(GtkContainer * container,
153                           gboolean include_internals, GtkCallback callback,
154                           gpointer callback_data);
155                           
156 static void hildon_time_editor_destroy(GtkObject * self);
157
158 static void hildon_time_editor_add_style(void);
159
160 static void
161 set_widget_allocation(GtkWidget * widget, GtkAllocation * alloc,
162                       GtkAllocation * allocation);
163
164 /***
165  * Signal handlers
166  */
167
168 static gboolean
169 hildon_time_editor_entry_focusout(GtkWidget * widget,
170                                   GdkEventFocus * event, gpointer data);
171
172 static gboolean hildon_time_editor_entry_focusin(GtkWidget * widget,
173                                                  GdkEventFocus * event, 
174                                                  gpointer data);
175 static gboolean
176 hildon_time_editor_mnemonic_activate(GtkWidget * widget,
177                                      gboolean group_cycling);
178
179 static gboolean
180 hildon_time_editor_ampm_clicked(GtkWidget * widget, GdkEventButton * event,
181                                 gpointer data);
182 static gboolean
183 hildon_time_editor_icon_clicked(GtkWidget * widget, gpointer data);
184
185 static gboolean
186 hildon_time_editor_entry_clicked(GtkWidget * widget,
187                                  GdkEventButton * event, gpointer data);
188
189 static void
190 hildon_time_editor_entry_changed(GtkWidget * widget, gpointer user_data);
191
192
193 static void
194 hildon_time_editor_size_request(GtkWidget * widget,
195                                 GtkRequisition * requisition);
196
197 static void
198 hildon_time_editor_size_allocate(GtkWidget * widget,
199                                  GtkAllocation * allocation);
200
201 static gboolean
202 hildon_time_editor_entry_keypress(GtkWidget * widget, GdkEventKey * event,
203                                   gpointer data);
204
205 /***
206  * Internal functions
207  */
208
209 static gboolean hildon_time_editor_check_locale(HildonTimeEditor * editor);
210
211 static
212 void hildon_time_editor_tap_and_hold_setup(GtkWidget * widget,
213                                            GtkWidget * menu,
214                                            GtkCallback func,
215                                            GtkWidgetTapAndHoldFlags flags);
216
217 static void
218 hildon_time_editor_get_max_values(HildonTimeEditor *editor,
219         guint * max_hours, guint * min_hours,
220         guint * max_minutes, guint * min_minutes,
221         guint * max_seconds, guint * min_seconds);
222         
223 static void
224 hildon_time_editor_validate (HildonTimeEditor *editor);
225
226 static HildonValidation
227 hildon_time_editor_validate_duration (HildonTimeEditor * editor, guint ticks);
228
229 static HildonValidation
230 hildon_time_editor_validate_time (HildonTimeEditor * editor,
231                                   guint hours,
232                                   guint minutes,
233                                   guint seconds,
234                                   gboolean mode_24h);
235
236 /***
237  * Utility functions
238  */
239  
240 static void
241 convert_to_12h (guint *h, guint *m, guint *s, gboolean *am);
242 static void
243 convert_to_24h (guint *h, guint *m, guint *s, gboolean am);
244
245 static void ticks_to_time (guint ticks,
246                            guint *hours,
247                            guint *minutes,
248                     guint *seconds);
249
250
251 struct _HildonTimeEditorPrivate {
252     guint ticks;        /* Current duration in seconds */
253     gchar *am_symbol;
254     gchar *pm_symbol;
255
256     GtkWidget *eventbox;        /* hold entries */
257     GtkWidget *iconbutton;      /* button for icon */
258
259     GtkWidget *h_entry;
260     GtkWidget *m_entry;
261     GtkWidget *s_entry;
262     GtkWidget *label;   /* between h and m */
263     GtkWidget *label2;  /* between m and s */
264     GtkWidget *ampm;    /* label for showing am or pm */
265     GtkWidget *icon;    /* label for showing am or pm */
266     GtkWidget *frame;   /* frame around the entries */
267
268     gboolean duration_mode;     /* In HildonDurationEditor mode */
269     gboolean show_s;    /* show seconds */
270     gboolean ampm_pos_after;    /* is the am/pm shown after others */
271     gboolean clock_24h; /* whether to show a 24h clock */
272     gboolean am;        /* TRUE == showing am, FALSE == pm */
273     gboolean valid_value; /* If entry has an valid value */
274     
275     gboolean validated; /* If the current value has been validated */
276
277     /* Duration editor ranges */
278     guint duration_min;
279     guint duration_max;
280 };
281
282 GType hildon_time_editor_get_type(void)
283 {
284     static GType editor_type = 0;
285
286     if (!editor_type) {
287         static const GTypeInfo editor_info = {
288             sizeof(HildonTimeEditorClass),
289             NULL,       /* base_init */
290             NULL,       /* base_finalize */
291             (GClassInitFunc) hildon_time_editor_class_init,
292             NULL,       /* class_finalize */
293             NULL,       /* class_data */
294             sizeof(HildonTimeEditor),
295             0,  /* n_preallocs */
296             (GInstanceInitFunc) hildon_time_editor_init,
297         };
298         editor_type = g_type_register_static(GTK_TYPE_CONTAINER,
299                                              "HildonTimeEditor",
300                                              &editor_info, 0);
301     }
302     return editor_type;
303 }
304
305 static void hildon_time_editor_forall(GtkContainer * container,
306                                       gboolean include_internals,
307                                       GtkCallback callback,
308                                       gpointer callback_data)
309 {
310     HildonTimeEditor *editor;
311     HildonTimeEditorPrivate *priv;
312
313     editor = HILDON_TIME_EDITOR(container);
314     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
315
316     g_return_if_fail(container);
317     g_return_if_fail(callback);
318
319     if (!include_internals)
320         return;
321
322
323     /* widget that are always shown */
324     (*callback) (priv->h_entry, callback_data);
325     (*callback) (priv->m_entry, callback_data);
326     (*callback) (priv->iconbutton, callback_data);
327     (*callback) (priv->frame, callback_data);
328     (*callback) (priv->label, callback_data);
329     (*callback) (priv->label2, callback_data);
330     (*callback) (priv->s_entry, callback_data);
331     (*callback) (priv->eventbox, callback_data);
332 }
333
334 static void hildon_time_editor_destroy(GtkObject * self)
335 {
336     HildonTimeEditorPrivate *priv;
337
338     priv = HILDON_TIME_EDITOR_GET_PRIVATE(self);
339
340     if (priv->h_entry) {
341         gtk_widget_unparent(priv->h_entry);
342         priv->h_entry = NULL;
343     }
344     if (priv->m_entry) {
345         gtk_widget_unparent(priv->m_entry);
346         priv->m_entry = NULL;
347     }
348     if (priv->label) {
349         gtk_widget_unparent(priv->label);
350         priv->label = NULL;
351     }
352     if (priv->iconbutton) {
353         gtk_widget_unparent(priv->iconbutton);
354         priv->iconbutton = NULL;
355     }
356     if (priv->frame) {
357         gtk_widget_unparent(priv->frame);
358         priv->frame = NULL;
359     }
360     if (priv->eventbox) {
361         gtk_widget_unparent(priv->eventbox);
362         priv->eventbox = NULL;
363         priv->ampm = NULL;
364     }
365     if (priv->label2) {
366         gtk_widget_unparent(priv->label2);
367         priv->label2 = NULL;
368     }
369     if (priv->s_entry) {
370         gtk_widget_unparent(priv->s_entry);
371         priv->s_entry = NULL;
372     }
373   
374     if (GTK_OBJECT_CLASS(parent_class)->destroy)
375         GTK_OBJECT_CLASS(parent_class)->destroy(self);
376
377 }
378
379 static void
380 hildon_time_editor_class_init(HildonTimeEditorClass * editor_class)
381 {
382     GObjectClass *object_class = G_OBJECT_CLASS(editor_class);
383     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(editor_class);
384     GtkContainerClass *container_class = GTK_CONTAINER_CLASS(editor_class);
385
386     parent_class = g_type_class_peek_parent(editor_class);
387
388     g_type_class_add_private(editor_class,
389                              sizeof(HildonTimeEditorPrivate));
390
391     object_class->get_property = hildon_time_editor_get_property;
392     object_class->set_property = hildon_time_editor_set_property;
393
394
395     widget_class->mnemonic_activate = hildon_time_editor_mnemonic_activate;
396     widget_class->size_request = hildon_time_editor_size_request;
397     widget_class->size_allocate = hildon_time_editor_size_allocate;
398     widget_class->tap_and_hold_setup =
399         hildon_time_editor_tap_and_hold_setup;
400     widget_class->focus = hildon_composite_widget_focus;
401
402     container_class->forall = hildon_time_editor_forall;
403     GTK_OBJECT_CLASS(editor_class)->destroy = hildon_time_editor_destroy;
404
405     object_class->finalize = hildon_time_editor_finalize;
406
407   /**
408    * HildonTimeEditor:ticks:
409    *
410    * TimeEditor current duration (or time since midnight) value.
411    */
412   g_object_class_install_property( object_class, PROP_TICKS,
413                                    g_param_spec_uint("ticks",
414                                    "Duration value",
415                                    "Current value of duration",
416                                    0, G_MAXUINT,
417                                    HILDON_TIME_EDITOR_TICKS_VALUE,
418                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
419
420   /**
421    * HildonTimeEditor:show_seconds:
422    *
423    * TimeEditor show_seconds property.
424    */
425   g_object_class_install_property( object_class, PROP_SHOW_SECONDS,
426                                    g_param_spec_boolean("show_seconds",
427                                    "Show seconds property",
428                                    "Controls whether the seconds are shown in the editor",
429                                    HILDON_TIME_EDITOR_SHOW_SECONDS,
430                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
431
432   /**
433    * HildonTimeEditor:duration_mode:
434    *
435    * TimeEditor duration mode indicator.
436    */
437   g_object_class_install_property( object_class, PROP_DURATION_MODE,
438                                    g_param_spec_boolean("duration_mode",
439                                    "Duration mode",
440                                    "Controls whether the TimeEditor is in duration mode",
441                                    HILDON_TIME_EDITOR_DURATION_MODE,
442                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
443
444   /**
445    * HildonTimeEditor:duration_min:
446    *
447    * TimeEditor minimum duration value.
448    */
449   g_object_class_install_property( object_class, PROP_DURATION_MIN,
450                                    g_param_spec_uint("duration_min",
451                                    "Minumum duration value",
452                                    "Smallest possible duration value",
453                                    0, G_MAXUINT,
454                                    HILDON_TIME_EDITOR_DURATION_LOWER_VALUE,
455                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
456
457   /**
458    * HildonTimeEditor:duration_max:
459    *
460    * TimeEditor maximum duration value.
461    */
462   g_object_class_install_property( object_class, PROP_DURATION_MAX,
463                                    g_param_spec_uint("duration_max",
464                                    "Maximum duration value",
465                                    "Largest possible duration value",
466                                    0, G_MAXUINT,
467                                    HILDON_TIME_EDITOR_DURATION_UPPER_VALUE,
468                                    G_PARAM_READABLE | G_PARAM_WRITABLE) );
469
470 }
471
472 static
473 void hildon_time_editor_tap_and_hold_setup(GtkWidget * widget,
474                                            GtkWidget * menu,
475                                            GtkCallback func,
476                                            GtkWidgetTapAndHoldFlags flags)
477 {
478     HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(widget);
479
480     gtk_widget_tap_and_hold_setup(priv->h_entry, menu, func,
481                                   GTK_TAP_AND_HOLD_NO_SIGNALS);
482     gtk_widget_tap_and_hold_setup(priv->m_entry, menu, func,
483                                   GTK_TAP_AND_HOLD_NO_SIGNALS);
484     gtk_widget_tap_and_hold_setup(priv->s_entry, menu, func,
485                                   GTK_TAP_AND_HOLD_NO_SIGNALS);
486     gtk_widget_tap_and_hold_setup(priv->eventbox, menu, func,
487                                   GTK_TAP_AND_HOLD_NO_SIGNALS);
488     gtk_widget_tap_and_hold_setup(priv->iconbutton, menu, func,
489                                   GTK_TAP_AND_HOLD_NONE);
490 }
491
492 static void hildon_time_editor_init(HildonTimeEditor * editor)
493 {
494     HildonTimeEditorPrivate *priv;
495     guint ticks = 0;
496
497     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
498
499     gtk_widget_push_composite_child();
500     
501     priv->ticks = 0;
502     priv->show_s = FALSE;
503     priv->ampm_pos_after = TRUE;
504     priv->clock_24h = TRUE;
505     priv->duration_mode = FALSE;
506     priv->iconbutton = gtk_button_new();
507     priv->h_entry = gtk_entry_new();
508     priv->m_entry = gtk_entry_new();
509     priv->s_entry = gtk_entry_new();
510     priv->ampm = gtk_label_new(NULL);
511     priv->label = gtk_label_new(_("Ecdg_ti_time_editor_separator"));
512     priv->label2 = gtk_label_new(_("Ecdg_ti_time_editor_separator"));
513     priv->icon = gtk_image_new_from_icon_name(ICON_NAME, HILDON_ICON_SIZE_26);
514     priv->frame = gtk_frame_new(NULL);
515     priv->eventbox = gtk_event_box_new();
516     priv->valid_value = TRUE;
517     priv->validated = FALSE;
518     
519     GTK_WIDGET_SET_FLAGS(editor, GTK_NO_WINDOW);
520     GTK_WIDGET_UNSET_FLAGS(priv->iconbutton, GTK_CAN_FOCUS);
521     
522     gtk_event_box_set_visible_window(GTK_EVENT_BOX(priv->eventbox), FALSE);
523
524     gtk_container_set_border_width(GTK_CONTAINER(priv->frame), 0);
525
526     gtk_container_add(GTK_CONTAINER(priv->iconbutton), priv->icon);
527     gtk_container_add(GTK_CONTAINER(priv->eventbox), priv->ampm);
528
529     gtk_entry_set_has_frame(GTK_ENTRY(priv->h_entry), FALSE);
530     gtk_entry_set_has_frame(GTK_ENTRY(priv->m_entry), FALSE);
531     gtk_entry_set_has_frame(GTK_ENTRY(priv->s_entry), FALSE);
532     
533     g_object_set (G_OBJECT(priv->h_entry), "input-mode",
534                   HILDON_INPUT_MODE_HINT_NUMERIC, NULL);
535     g_object_set (G_OBJECT(priv->m_entry), "input-mode", 
536                   HILDON_INPUT_MODE_HINT_NUMERIC, NULL);
537     g_object_set (G_OBJECT(priv->s_entry), "input-mode",
538                   HILDON_INPUT_MODE_HINT_NUMERIC, NULL);
539
540     
541     /* clicked signal for am/pm label */
542     g_signal_connect(G_OBJECT(priv->eventbox), "button_press_event",
543                      G_CALLBACK(hildon_time_editor_ampm_clicked), editor);
544
545     /* clicked signal for icon */
546     g_signal_connect(G_OBJECT(priv->iconbutton), "clicked",
547                      G_CALLBACK(hildon_time_editor_icon_clicked), editor);
548
549     /* clicked signal for hour entry */
550     g_signal_connect(G_OBJECT(priv->h_entry), "button-release-event",
551                      G_CALLBACK(hildon_time_editor_entry_clicked), editor);
552     g_signal_connect(G_OBJECT(priv->h_entry), "focus-in-event",
553                      G_CALLBACK(hildon_time_editor_entry_focusin), editor);
554
555     /* clicked signal for minute entry */
556     g_signal_connect(G_OBJECT(priv->m_entry), "button-release-event",
557                      G_CALLBACK(hildon_time_editor_entry_clicked), editor);
558     g_signal_connect(G_OBJECT(priv->m_entry), "focus-in-event",
559                      G_CALLBACK(hildon_time_editor_entry_focusin), editor);
560
561     /* clicked signal for second entry */
562     g_signal_connect(G_OBJECT(priv->s_entry), "button-release-event",
563                      G_CALLBACK(hildon_time_editor_entry_clicked), editor);
564     g_signal_connect(G_OBJECT(priv->s_entry), "focus-in-event",
565                      G_CALLBACK(hildon_time_editor_entry_focusin), editor);
566
567     /* focus out events */
568     g_signal_connect(G_OBJECT(priv->h_entry), "focus-out-event",
569                      G_CALLBACK(hildon_time_editor_entry_focusout),
570                      editor);
571     g_signal_connect(G_OBJECT(priv->m_entry), "focus-out-event",
572                      G_CALLBACK(hildon_time_editor_entry_focusout),
573                      editor);
574     g_signal_connect(G_OBJECT(priv->s_entry), "focus-out-event",
575                      G_CALLBACK(hildon_time_editor_entry_focusout),
576                      editor);
577
578     /* key press events */
579     g_signal_connect(G_OBJECT(priv->h_entry), "key-press-event",
580                      G_CALLBACK(hildon_time_editor_entry_keypress),
581                      editor);
582     g_signal_connect(G_OBJECT(priv->m_entry), "key-press-event",
583                      G_CALLBACK(hildon_time_editor_entry_keypress),
584                      editor);
585     g_signal_connect(G_OBJECT(priv->s_entry), "key-press-event",
586                      G_CALLBACK(hildon_time_editor_entry_keypress),
587                      editor);
588
589     /* changed signal sets time */
590     g_signal_connect_after (G_OBJECT(priv->h_entry), "changed",
591                       G_CALLBACK (hildon_time_editor_entry_changed), 
592                       editor);
593     g_signal_connect_after (G_OBJECT(priv->m_entry), "changed",
594                       G_CALLBACK (hildon_time_editor_entry_changed), 
595                       editor);
596     g_signal_connect_after (G_OBJECT(priv->s_entry), "changed",
597                       G_CALLBACK (hildon_time_editor_entry_changed), 
598                       editor);
599                       
600     gtk_widget_set_parent(priv->iconbutton, GTK_WIDGET(editor));
601     gtk_widget_set_parent(priv->label, GTK_WIDGET(editor));
602
603     gtk_widget_set_parent(priv->label2, GTK_WIDGET(editor));
604     gtk_widget_set_parent(priv->s_entry, GTK_WIDGET(editor));
605     gtk_widget_set_parent(priv->eventbox, GTK_WIDGET(editor));
606     gtk_widget_set_parent(priv->m_entry, GTK_WIDGET(editor));
607     gtk_widget_set_parent(priv->h_entry, GTK_WIDGET(editor));
608
609     gtk_widget_show(priv->h_entry);
610     gtk_widget_show(priv->m_entry);
611     gtk_widget_show_all(priv->iconbutton);
612     gtk_widget_show(priv->label);
613
614     gtk_widget_set_parent(priv->frame, GTK_WIDGET(editor));
615     gtk_widget_show_all(priv->frame);
616
617     /* Check if we are in am/pm time locale */
618     if (!hildon_time_editor_check_locale(editor)) {
619         priv->clock_24h = FALSE;
620         gtk_widget_show_all(priv->eventbox);
621     }
622
623     {   /* get current time */
624         time_t tm;
625         struct tm *stm;
626
627         tm = time(NULL);
628         stm = localtime(&tm);
629
630         if (stm) {
631             ticks = stm->tm_hour * 3600;
632             ticks = ticks + stm->tm_min * 60;
633             ticks = ticks + stm->tm_sec;
634         }
635     }
636
637     hildon_time_editor_set_ticks (editor, ticks);
638     
639     gtk_entry_set_max_length(GTK_ENTRY(priv->h_entry), 2);
640     gtk_entry_set_width_chars(GTK_ENTRY(priv->h_entry), 2);
641     gtk_entry_set_max_length(GTK_ENTRY(priv->m_entry), 2);
642     gtk_entry_set_width_chars(GTK_ENTRY(priv->m_entry), 2);
643     gtk_entry_set_max_length(GTK_ENTRY(priv->s_entry), 2);
644     gtk_entry_set_width_chars(GTK_ENTRY(priv->s_entry), 2);
645
646     hildon_time_editor_add_style();
647     gtk_widget_set_name(GTK_WIDGET(priv->iconbutton),
648                         "hildon-time-editor-icon");
649     
650     gtk_widget_pop_composite_child();
651 }
652
653 static void hildon_time_editor_set_property (GObject *object, guint param_id,
654                                       const GValue *value, GParamSpec *pspec)
655 {
656   HildonTimeEditor *time_editor = HILDON_TIME_EDITOR(object);
657   switch (param_id)
658   {
659     case PROP_TICKS:
660       hildon_time_editor_set_ticks (time_editor, g_value_get_uint(value));
661       break;
662       
663     case PROP_SHOW_SECONDS:
664       hildon_time_editor_set_show_seconds (time_editor, g_value_get_boolean(value));
665       break;
666
667     case PROP_DURATION_MODE:
668       hildon_time_editor_set_duration_mode (time_editor, g_value_get_boolean(value));
669       break;
670
671     case PROP_DURATION_MIN:
672       hildon_time_editor_set_duration_min (time_editor, g_value_get_uint(value));
673       break;
674       
675     case PROP_DURATION_MAX:
676       hildon_time_editor_set_duration_max (time_editor, g_value_get_uint(value));
677       break;
678       
679     default:
680       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
681       break;
682   }
683 }
684
685 static void hildon_time_editor_get_property (GObject *object, guint param_id,
686                                             GValue *value, GParamSpec *pspec)
687 {
688   HildonTimeEditor *time_editor = HILDON_TIME_EDITOR(object);
689   switch (param_id)
690   {
691
692     case PROP_TICKS:
693       g_value_set_uint (value, hildon_time_editor_get_ticks (time_editor));
694       break;
695
696     case PROP_SHOW_SECONDS:
697       g_value_set_boolean (value, hildon_time_editor_get_show_seconds (time_editor));
698       break;
699
700     case PROP_DURATION_MODE:
701       g_value_set_boolean (value, hildon_time_editor_get_duration_mode (time_editor));
702       break;
703
704     case PROP_DURATION_MIN:
705       g_value_set_uint (value, hildon_time_editor_get_duration_min (time_editor));
706       break;
707
708     case PROP_DURATION_MAX:
709       g_value_set_uint (value, hildon_time_editor_get_duration_max (time_editor));
710       break;
711       
712     default:
713       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
714       break;
715   }
716 }
717
718
719 static gboolean
720 hildon_time_editor_mnemonic_activate( GtkWidget *widget,
721                                       gboolean group_cycling)
722 {
723   HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(widget);
724   gtk_widget_grab_focus( priv->h_entry );
725   gtk_editable_select_region(GTK_EDITABLE(priv->h_entry), 0, 2);
726   return TRUE;
727 }
728
729 /**
730  * hildon_time_editor_new:
731  *
732  * This function creates a new time editor. 
733  *
734  * Return value: pointer to a new #HildonTimeEditor widget.
735  **/
736
737 GtkWidget *hildon_time_editor_new(void)
738 {
739     return GTK_WIDGET(g_object_new(HILDON_TYPE_TIME_EDITOR, NULL));
740 }
741
742 static void hildon_time_editor_finalize(GObject * obj_self)
743 {
744     HildonTimeEditorPrivate *priv = HILDON_TIME_EDITOR_GET_PRIVATE(obj_self);
745
746     if (priv->am_symbol)
747         g_free(priv->am_symbol);
748     if (priv->pm_symbol)
749         g_free(priv->pm_symbol);
750
751     if (G_OBJECT_CLASS(parent_class)->finalize)
752         G_OBJECT_CLASS(parent_class)->finalize(obj_self);
753 }
754
755 static void hildon_time_editor_add_style(void)
756 {
757     gtk_rc_parse_string("  style \"hildon-time-editor-icon\" {"
758                         "    GtkButton::default_border = { 0, 0, 0, 0 }"
759                         "    xthickness = 0"
760                         "    ythickness = 0"
761                         "    engine \"pixmap\" {"
762                         "      image {"
763                         "        function = BOX"
764                         "      }"
765                         "    }"
766                         "  }"
767                         "  widget \"*.hildon-time-editor-icon\""
768                         "    style \"hildon-time-editor-icon\"");
769 }
770
771 static void ticks_to_time (guint ticks,
772                            guint *hours,
773                            guint *minutes,
774                            guint *seconds)
775 {
776   guint h,m,s;
777
778   h = ticks / 3600;
779   m = (ticks - h*3600) / 60;
780   s = ticks - h*3600 - m*60;
781
782   *hours = h;
783   *minutes = m;
784   *seconds = s;
785
786 }
787
788 /**
789  * hildon_time_editor_set_ticks:
790  * @self: the @HildonTimeEditor widget.
791  * @ticks: The duration to set, in seconds.
792  *
793  * Sets the current duration in seconds. This means seconds from
794  * midnight, if not in duration mode. In case of any errors, it tries
795  * to fix it.
796  * 
797  **/
798
799 void hildon_time_editor_set_ticks (HildonTimeEditor * editor,
800                                    guint ticks)
801 {
802     HildonTimeEditorPrivate *priv;
803     HildonValidation validation;
804     guint h = 1;
805     guint m = 0;
806     guint s = 0;
807     gchar hours[3]   = "01";
808     gchar minutes[3] = "00";
809     gchar seconds[3] = "00";
810
811     g_return_if_fail(editor);
812     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
813
814     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
815
816     /* Validate the value if it is not already validated */
817     if (!priv->validated) {
818         if (priv->duration_mode) {
819             validation = hildon_time_editor_validate_duration (editor, ticks);
820             switch(validation) {
821                 case VALIDATION_DURATION_MIN:
822                     priv->ticks = priv->duration_min;
823                     break;
824                 case VALIDATION_DURATION_MAX:
825                     priv->ticks = priv->duration_max;
826                     break;
827                 default:
828                     priv->ticks = ticks;
829                     break;
830             }
831         } else {
832             ticks_to_time (ticks, &h, &m, &s);
833             validation = hildon_time_editor_validate_time (editor, h, m, s, TRUE);
834             switch (validation) {
835                 case VALIDATION_TIME_HOURS:
836                     if (priv->clock_24h) {
837                         if (h > HOURS_MAX_24) {
838                             h = HOURS_MAX_24;
839                         } else if (h < HOURS_MIN_24) {
840                             h = HOURS_MIN_24;
841                         }
842                     } else {
843                         if (h > HOURS_MAX_12) {
844                             h = HOURS_MAX_12;
845                         } else if (h < HOURS_MIN_12) {
846                             h = HOURS_MIN_12;
847                         }
848                     }
849                     priv->ticks = (3600 * h) + (60 * m) + s;
850                     break;
851                 case VALIDATION_TIME_MINUTES:
852                     if (m > MINUTES_MAX) {
853                         m = MINUTES_MAX;
854                     } else if (m < MINUTES_MIN) {
855                         m = MINUTES_MIN;
856                     }
857                     break;
858                 case VALIDATION_TIME_SECONDS:
859                     if (s > SECONDS_MAX) {
860                         s = SECONDS_MAX;
861                     } else if (s < SECONDS_MIN) {
862                         s = SECONDS_MIN;
863                     }
864                     priv->ticks = (3600 * h) + (60 * m) + s;
865                     break;
866                 default:
867                     priv->ticks = ticks;
868                     break;
869             }
870         }
871     } else {
872       priv->ticks = ticks;
873     }
874     
875     ticks_to_time (priv->ticks, &h, &m, &s);
876     
877     ticks_to_time (priv->ticks, &h, &m, &s);
878     
879     if (!priv->clock_24h && !priv->duration_mode)
880       {
881         convert_to_12h (&h, &m, &s, &priv->am);
882       }
883
884     g_snprintf(hours,   3, "%02u", h);
885     g_snprintf(minutes, 3, "%02u", m);
886     g_snprintf(seconds, 3, "%02u", s);
887     gtk_entry_set_text(GTK_ENTRY(priv->h_entry), hours);
888     gtk_entry_set_text(GTK_ENTRY(priv->m_entry), minutes);
889     gtk_entry_set_text(GTK_ENTRY(priv->s_entry), seconds);
890         
891     priv->valid_value = TRUE;
892     priv->validated = FALSE;
893
894     /* set current time (am/pm) */
895     gtk_label_set_label(GTK_LABEL(priv->ampm), priv->am ? priv->am_symbol :
896                         priv->pm_symbol);
897     
898     g_object_notify (G_OBJECT (editor), "ticks");
899 }
900
901 /**
902  * hildon_time_editor_get_ticks:
903  * @self: the @HildonTimeEditor widget.
904  *
905  * This function returns the current duration, in seconds.
906  * This means seconds from midnight, if not in duration mode.
907  * 
908  * Return value: Current duration in seconds. 
909  **/
910  
911 guint hildon_time_editor_get_ticks (HildonTimeEditor * editor)
912 {
913     HildonTimeEditorPrivate *priv;
914
915     g_return_val_if_fail(editor, 0);
916     g_return_val_if_fail(HILDON_IS_TIME_EDITOR(editor), 0);
917
918     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
919     
920     return (priv->ticks);
921 }
922
923 /**
924  * hildon_time_editor_set_show_seconds:
925  * @editor: The #HildonTimeEditor.
926  * @enable: Enable or disable showing of seconds.
927  *
928  * This function shows or hides the seconds field.
929  *
930  **/
931
932 void hildon_time_editor_set_show_seconds (HildonTimeEditor * editor,
933                                         gboolean show_seconds)
934 {
935     HildonTimeEditorPrivate *priv;
936
937     g_return_if_fail(editor);
938
939     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
940
941     if (!priv->show_s && show_seconds) {
942         priv->show_s = TRUE;
943
944         gtk_widget_show(priv->s_entry);
945         gtk_widget_show(priv->label2);
946         
947     } else if (priv->show_s && !show_seconds) {
948
949         gtk_widget_hide(priv->s_entry);
950         gtk_widget_hide(priv->label2);
951
952         priv->show_s = FALSE;
953     } else
954         return;
955
956     gtk_widget_queue_resize(GTK_WIDGET(editor));
957     
958     g_object_notify (G_OBJECT (editor), "show_seconds");
959 }
960
961 /**
962  * hildon_time_editor_get_show_seconds:
963  * @self: the @HildonTimeEditor widget.
964  *
965  * This function returns a boolean indicating the visibility of
966  * seconds in the @HildonTimeEditor
967  *
968  * Return value: TRUE if the seconds are visible. 
969  **/
970
971 gboolean hildon_time_editor_get_show_seconds (HildonTimeEditor * editor)
972 {
973     HildonTimeEditorPrivate *priv;
974
975     g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
976     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
977
978     return (priv->show_s);
979 }
980
981 /**
982  * hildon_time_editor_set_duration_mode:
983  * @editor: The #HildonTimeEditor.
984  * @enable: Enable or disable duration editor mode
985  *
986  * This function sets the duration editor mode in which the maximum hours
987  * is 99 and the #HildonTimePicker is disabled.
988  *
989  **/
990  
991 void hildon_time_editor_set_duration_mode (HildonTimeEditor * editor,
992                                          gboolean duration_mode)
993 {
994     HildonTimeEditorPrivate *priv;
995
996     g_return_if_fail(editor);
997
998     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
999
1000     /* switch to duration editor mode */
1001     if (duration_mode && !priv->duration_mode) {
1002         priv->duration_mode = duration_mode;
1003         hildon_time_editor_set_duration_range(editor, MIN_DURATION,
1004                                               MAX_DURATION);
1005
1006         if (!priv->clock_24h)
1007             gtk_widget_hide(GTK_WIDGET(priv->ampm));
1008
1009         gtk_widget_hide(GTK_WIDGET(priv->eventbox));
1010         gtk_widget_hide(GTK_WIDGET(priv->icon));
1011
1012         /* Show seconds for duration editor */
1013         hildon_time_editor_set_show_seconds(editor, TRUE);
1014     }
1015     /* switch to time editor mode */
1016     else if (!duration_mode && priv->duration_mode) {
1017         guint ticks;
1018         time_t tm;
1019         struct tm *stm;
1020             
1021         priv->duration_mode = duration_mode;
1022
1023         if (!priv->clock_24h)
1024             gtk_widget_show(GTK_WIDGET(priv->ampm));
1025
1026         gtk_widget_show(GTK_WIDGET(priv->eventbox));
1027         gtk_widget_show(GTK_WIDGET(priv->icon));
1028         
1029
1030         /* Put the ticks to match current time, anything set in the 
1031          * duration mode is bound to be invalid or useless in time mode
1032          */
1033         
1034         tm = time(NULL);
1035         stm = localtime(&tm);
1036
1037         ticks = HILDON_TIME_EDITOR_TIME_LOWER_VALUE;
1038         
1039         if (stm) {
1040             ticks = stm->tm_hour * 3600;
1041             ticks = ticks + stm->tm_min * 60;
1042             ticks = ticks + stm->tm_sec;
1043         }
1044         
1045         hildon_time_editor_set_ticks (editor, ticks);
1046         
1047     }
1048     gtk_widget_queue_resize(GTK_WIDGET(editor));
1049     
1050     g_object_notify (G_OBJECT (editor), "duration_mode");
1051 }
1052
1053 /**
1054  * hildon_time_editor_get_duration_mode:
1055  * @self: the @HildonTimeEditor widget.
1056  *
1057  * This function returns a boolean indicating whether the @HildonTimeEditor
1058  * is in the duration mode.
1059  * 
1060  * Return value: TRUE if the @HildonTimeEditor is in duration mode. 
1061  **/
1062
1063 gboolean hildon_time_editor_get_duration_mode (HildonTimeEditor * editor)
1064 {
1065     HildonTimeEditorPrivate *priv;
1066
1067     g_return_val_if_fail (HILDON_IS_TIME_EDITOR (editor), FALSE);
1068     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1069
1070     return (priv->duration_mode);
1071 }
1072
1073 /**
1074  * hildon_time_editor_set_duration_min:
1075  * @self: the @HildonTimeEditor widget.
1076  * @duration_min: Mimimum allowed duration.
1077  *
1078  * Sets the minimum allowed duration for the duration mode.
1079  * Note: Has no effect in time mode
1080  **/
1081
1082 void hildon_time_editor_set_duration_min (HildonTimeEditor * editor,
1083                                           guint duration_min)
1084 {
1085     HildonTimeEditorPrivate *priv;
1086
1087     g_return_if_fail(editor);
1088     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1089
1090     g_return_if_fail(duration_min >= MIN_DURATION);
1091
1092     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1093
1094     if( !priv->duration_mode )
1095       return;
1096
1097     priv->duration_min = duration_min;
1098     
1099     /* Clamp the current value to the minimum if necessary */
1100     if (priv->ticks < duration_min)
1101     {
1102         hildon_time_editor_set_ticks (editor, duration_min);
1103     }
1104     
1105     g_object_notify (G_OBJECT (editor), "duration_min");
1106 }
1107
1108 /**
1109  * hildon_time_editor_get_duration_min:
1110  * @self: the @HildonTimeEditor widget.
1111  *
1112  * This function returns the smallest duration the @HildonTimeEditor
1113  * allows in the duration mode.
1114  * 
1115  * Return value: Mimimum allowed duration in seconds. 
1116  **/
1117  
1118 guint hildon_time_editor_get_duration_min (HildonTimeEditor * editor)
1119 {
1120     HildonTimeEditorPrivate *priv;
1121
1122     g_return_val_if_fail(editor, 0);
1123     g_return_val_if_fail(HILDON_IS_TIME_EDITOR(editor), 0);
1124
1125     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1126
1127     if( !priv->duration_mode )
1128       return (0);
1129
1130     return (priv->duration_min);
1131 }
1132
1133 /**
1134  * hildon_time_editor_set_duration_max:
1135  * @self: the @HildonTimeEditor widget.
1136  * @duration_min: Maximum allowed duration in seconds.
1137  *
1138  * Sets the maximum allowed duration in seconds for the duration mode.
1139  * Note: Has no effect in time mode
1140  * 
1141  **/
1142  
1143 void hildon_time_editor_set_duration_max (HildonTimeEditor * editor,
1144                                           guint duration_max)
1145 {
1146     HildonTimeEditorPrivate *priv;
1147
1148     g_return_if_fail(editor);
1149     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1150
1151     g_return_if_fail(duration_max <= MAX_DURATION);
1152
1153     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1154
1155     if( !priv->duration_mode )
1156       return;
1157
1158     priv->duration_max = duration_max;
1159     
1160     /* Clamp the current value to the maximum if necessary */
1161     if (priv->ticks > duration_max)
1162     {
1163         hildon_time_editor_set_ticks (editor, duration_max);
1164     }
1165     
1166     g_object_notify (G_OBJECT (editor), "duration_max");
1167 }
1168
1169 /**
1170  * hildon_time_editor_get_duration_max:
1171  * @self: the @HildonTimeEditor widget.
1172  *
1173  * This function returns the longest duration the @HildonTimeEditor
1174  * allows in the duration mode.
1175  * 
1176  * Return value: Maximum allowed duration in seconds. 
1177  **/
1178  
1179 guint hildon_time_editor_get_duration_max (HildonTimeEditor * editor)
1180 {
1181     HildonTimeEditorPrivate *priv;
1182
1183     g_return_val_if_fail(editor, 0);
1184     g_return_val_if_fail(HILDON_IS_TIME_EDITOR(editor), 0);
1185
1186     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1187
1188     if( !priv->duration_mode )
1189       return (0);
1190
1191     return (priv->duration_max);
1192 }
1193
1194
1195 /**
1196  * hildon_time_editor_set_time:
1197  * @editor: the @HildonTimeEditor widget.
1198  * @hours: hours
1199  * @minutes: minutes
1200  * @seconds: seconds
1201  *
1202  * This function sets the time on an existing time editor. If the
1203  * time specified by the arguments is invalid, the function returns
1204  * without doing anything else. The time is assumed to be in 24h format.
1205  *  
1206  **/
1207
1208 void hildon_time_editor_set_time(HildonTimeEditor * editor, guint hours,
1209                                  guint minutes, guint seconds)
1210 {
1211     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1212
1213     hildon_time_editor_set_ticks (editor, hours * 3600 + minutes * 60 + seconds);
1214
1215 }
1216
1217 /**
1218  * hildon_time_editor_get_time:
1219  * @editor: the @HildonTimeEditor widget.
1220  * @hours: hours
1221  * @minutes: minutes
1222  * @seconds: seconds
1223  *
1224  * Gets the time of the @HildonTimeEditor widget. The time returned is
1225  * always in 24h format.
1226  **/
1227
1228 void hildon_time_editor_get_time(HildonTimeEditor * editor,
1229                                  guint * hours,
1230                                  guint * minutes, guint * seconds)
1231 {
1232     HildonTimeEditorPrivate *priv;
1233     
1234     g_return_if_fail(editor);
1235     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1236
1237     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1238
1239     ticks_to_time (hildon_time_editor_get_ticks (editor),
1240                    hours, minutes, seconds);
1241
1242 }
1243
1244 /**
1245  * hildon_time_editor_set_duration_range:
1246  * @editor: the @HildonTimeEditor widget.
1247  * @min_seconds: minimum allowed time in seconds
1248  * @max_seconds: maximum allowed time in seconds
1249  *
1250  * Sets the duration editor time range of the @HildonTimeEditor widget.
1251  **/
1252
1253 void hildon_time_editor_set_duration_range(HildonTimeEditor * editor,
1254                                            guint min_seconds,
1255                                            guint max_seconds)
1256 {
1257     HildonTimeEditorPrivate *priv;
1258     guint tmp;
1259     
1260     g_return_if_fail(editor);
1261     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1262
1263     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1264     /* Swap values if reversed */
1265     if (min_seconds > max_seconds)
1266       {
1267         tmp = max_seconds;
1268         max_seconds = min_seconds;
1269         min_seconds = tmp;
1270       }
1271     
1272     hildon_time_editor_set_duration_max (editor, max_seconds);
1273     hildon_time_editor_set_duration_min (editor, min_seconds);
1274
1275     if (priv->duration_mode) {
1276         /* Set minimum allowed value for duration editor */
1277         hildon_time_editor_set_ticks(editor, min_seconds);
1278     }
1279 }
1280
1281 /**
1282  * hildon_time_editor_get_duration_range:
1283  * @editor: the @HildonTimeEditor widget.
1284  * @min_seconds: pointer to guint
1285  * @max_seconds: pointer to guint
1286  *
1287  * Gets the duration editor time range of the @HildonTimeEditor widget.
1288  **/
1289
1290 void hildon_time_editor_get_duration_range(HildonTimeEditor * editor,
1291                                            guint * min_seconds,
1292                                            guint * max_seconds)
1293 {
1294     HildonTimeEditorPrivate *priv;
1295
1296     g_return_if_fail(editor);
1297     g_return_if_fail(HILDON_IS_TIME_EDITOR(editor));
1298
1299     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1300
1301     *min_seconds = priv->duration_min;
1302     *max_seconds = priv->duration_max;
1303 }
1304
1305 static gboolean hildon_time_editor_check_locale(HildonTimeEditor * editor)
1306 {
1307     HildonTimeEditorPrivate *priv;
1308     gchar *t_fm;
1309
1310     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1311
1312     priv->am_symbol = g_strdup(nl_langinfo(AM_STR));
1313     priv->pm_symbol = g_strdup(nl_langinfo(PM_STR));
1314
1315     if (!strcmp(priv->am_symbol, ""))
1316         return TRUE;
1317     else {
1318         t_fm = g_strdup(nl_langinfo(T_FMT_AMPM));
1319         /* Check what format am/pm time should be */
1320         if (!strncmp(t_fm, "%p", 2))
1321             priv->ampm_pos_after = FALSE;
1322         priv->am_symbol =
1323             g_ascii_strdown((const gchar *) priv->am_symbol, -1);
1324         priv->pm_symbol =
1325             g_ascii_strdown((const gchar *) priv->pm_symbol, -1);
1326         g_free(t_fm);
1327         return FALSE;
1328     }
1329 }
1330
1331 static gboolean hildon_time_editor_entry_focusin(GtkWidget * widget,
1332                                                  GdkEventFocus * event, 
1333                                                  gpointer data)
1334 {
1335     if (!GTK_ENTRY(widget)->button)
1336         gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
1337
1338     return FALSE;
1339 }
1340
1341
1342 void
1343 hildon_time_editor_validate (HildonTimeEditor *editor)
1344 {
1345     guint max_hours = 0;
1346     guint min_hours = 0;
1347     guint max_minutes = 0;
1348     guint min_minutes = 0;
1349     guint max_seconds = 0;
1350     guint min_seconds = 0;
1351
1352     HildonTimeEditorPrivate *priv;
1353     HildonValidation validation;
1354
1355     GtkWindow *window;
1356     guint h,m,s;
1357
1358     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1359
1360     window = GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (editor),
1361                                                   GTK_TYPE_WINDOW));
1362
1363     hildon_time_editor_get_max_values(editor, 
1364             &max_hours, &min_hours, 
1365             &max_minutes, &min_minutes, 
1366             &max_seconds, &min_seconds);
1367             
1368     /* No empty values thank you */
1369     if (strlen(GTK_ENTRY(priv->h_entry)->text) == 0)
1370       {
1371         if (!priv->duration_mode)
1372           {
1373             if (priv->clock_24h)
1374               {
1375                 gtk_infoprintf(window,
1376                                _("Ckct_ib_set_a_value_within_range"),
1377                                0, 23);
1378               }
1379             else
1380               {
1381                 gtk_infoprintf(window,
1382                                _("Ckct_ib_set_a_value_within_range"),
1383                                0, 12);
1384               }
1385           }
1386         else
1387           {
1388             gtk_infoprintf(window,
1389                            _("Ckct_ib_set_a_value_within_range"),
1390                            min_hours, max_hours);
1391           }
1392         hildon_time_editor_set_ticks (editor, priv->ticks);
1393         gtk_widget_grab_focus (priv->h_entry);
1394       }
1395     else if (strlen(GTK_ENTRY(priv->m_entry)->text) == 0)
1396       {
1397         if (!priv->duration_mode)
1398           {
1399             gtk_infoprintf(window,
1400                            _("Ckct_ib_set_a_value_within_range"),
1401                            0, 59);
1402           }
1403         else
1404           {
1405             gtk_infoprintf(window,
1406                            _("Ckct_ib_set_a_value_within_range"),
1407                            min_minutes, max_minutes);
1408           }
1409         hildon_time_editor_set_ticks (editor, priv->ticks);
1410         gtk_widget_grab_focus (priv->m_entry);
1411       }
1412     else if (strlen(GTK_ENTRY(priv->s_entry)->text) == 0)
1413       {
1414         if (!priv->duration_mode)
1415           {
1416             gtk_infoprintf(window,
1417                            _("Ckct_ib_set_a_value_within_range"),
1418                            0, 59);
1419           }
1420         else
1421           {
1422             gtk_infoprintf(window,
1423                            _("Ckct_ib_set_a_value_within_range"),
1424                            min_seconds, max_seconds);
1425           }
1426         hildon_time_editor_set_ticks (editor, priv->ticks);
1427         gtk_widget_grab_focus (priv->s_entry);
1428       }
1429     /* Do the validation dance! */
1430     else 
1431       {
1432
1433         h = (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->h_entry)));
1434         m = (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->m_entry)));
1435         s = (guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->s_entry)));
1436       
1437         if (priv->duration_mode)
1438           {
1439             validation = hildon_time_editor_validate_duration (editor,
1440                                                                h*3600 + m*60 + s);
1441           
1442             switch (validation)
1443               {
1444                 case VALIDATION_DURATION_MIN:
1445                   gtk_infoprintf(window,
1446                                  _("Ckct_ib_min_allowed_duration_hts"),
1447                                  min_hours, min_minutes, min_seconds);
1448                   hildon_time_editor_set_ticks (editor, priv->duration_min);
1449                   break;
1450                 case VALIDATION_DURATION_MAX:
1451                   gtk_infoprintf(window,
1452                                  _("Ckct_ib_max_allowed_duration_hts"),
1453                                  max_hours, max_minutes, max_seconds);
1454                   hildon_time_editor_set_ticks (editor, priv->duration_max);
1455                   break;
1456                 default:
1457                   hildon_time_editor_set_ticks (editor, h*3600 + m*60 + s);
1458                   break;
1459               }
1460           }
1461         else
1462           {
1463             validation = hildon_time_editor_validate_time (editor, h, m, s, priv->clock_24h);
1464             switch (validation)
1465               {
1466                 case VALIDATION_TIME_HOURS:
1467                   if (priv->clock_24h)
1468                     {
1469                       if (h > HOURS_MAX_24)
1470                         {
1471                           gtk_infoprintf(window,
1472                                          _("Ckct_ib_maximum_value"),
1473                                          HOURS_MAX_24);
1474                           h = HOURS_MAX_24;
1475                         }
1476                       else
1477                         {
1478                           gtk_infoprintf(window,
1479                                          _("Ckct_ib_minimum_value"),
1480                                          HOURS_MIN_24);
1481                           h = HOURS_MIN_24;
1482                         }
1483                     }
1484                   else
1485                     {
1486                       if (h > HOURS_MAX_12)
1487                         {
1488                           gtk_infoprintf(window,
1489                                          _("Ckct_ib_maximum_value"),
1490                                          HOURS_MAX_12);
1491                           h = HOURS_MAX_12;
1492                         }
1493                       else
1494                         {
1495                           gtk_infoprintf(window,
1496                                          _("Ckct_ib_minimum_value"),
1497                                          HOURS_MIN_12);
1498                           h = HOURS_MIN_12;
1499                         }
1500                     }
1501                   if (!priv->clock_24h)
1502                     convert_to_24h (&h, &m, &s, priv->am);
1503                   hildon_time_editor_set_time (editor, h, m, s);
1504                   gtk_widget_grab_focus (priv->h_entry);
1505                   gtk_editable_select_region(GTK_EDITABLE(priv->h_entry), 0, 2);
1506                   break;
1507                 case VALIDATION_TIME_MINUTES:
1508                   if (m > MINUTES_MAX)
1509                     {
1510                       gtk_infoprintf(window,
1511                                      _("Ckct_ib_maximum_value"),
1512                                      MINUTES_MAX);
1513                       m = MINUTES_MAX;
1514                     }
1515                   else
1516                     {
1517                       gtk_infoprintf(window,
1518                                      _("Ckct_ib_minimum_value"),
1519                                      MINUTES_MIN);
1520                       m = MINUTES_MIN;
1521                     }
1522                   if (!priv->clock_24h)
1523                     convert_to_24h (&h, &m, &s, priv->am);
1524                   hildon_time_editor_set_time (editor, h, m, s);
1525                   gtk_widget_grab_focus (priv->m_entry);
1526                   gtk_editable_select_region(GTK_EDITABLE(priv->m_entry), 0, 2);
1527                   break;
1528                 case VALIDATION_TIME_SECONDS:
1529                   if (s > SECONDS_MAX)
1530                     {
1531                       gtk_infoprintf(window,
1532                                      _("Ckct_ib_maximum_value"),
1533                                      SECONDS_MAX);
1534                       s = SECONDS_MAX;
1535                     }
1536                   else
1537                     {
1538                       gtk_infoprintf(window,
1539                                      _("Ckct_ib_minimum_value"),
1540                                      SECONDS_MIN);
1541                       s = SECONDS_MIN;
1542                     }
1543                   if (!priv->clock_24h)
1544                     convert_to_24h (&h, &m, &s, priv->am);
1545                   hildon_time_editor_set_time (editor, h, m, s);
1546                   gtk_widget_grab_focus (priv->s_entry);
1547                   gtk_editable_select_region(GTK_EDITABLE(priv->s_entry), 0, 2);
1548                   break;
1549                 default:
1550                   if (!priv->clock_24h)
1551                     {
1552                       convert_to_24h (&h, &m, &s, priv->am);
1553                     }
1554                   hildon_time_editor_set_time (editor, h, m, s);
1555                   break;
1556               }
1557           }
1558         
1559       }
1560 }
1561
1562 static gboolean hildon_time_editor_entry_focusout(GtkWidget * widget,
1563                                                   GdkEventFocus * event,
1564                                                   gpointer data)
1565 {
1566   HildonTimeEditor *editor;
1567
1568   editor = HILDON_TIME_EDITOR(data);
1569
1570   hildon_time_editor_validate (editor);
1571
1572   return FALSE;
1573 }
1574
1575 static gboolean
1576 hildon_time_editor_ampm_clicked(GtkWidget * widget,
1577                                 GdkEventButton * event, gpointer data)
1578 {
1579     HildonTimeEditor *editor;
1580     HildonTimeEditorPrivate *priv = NULL;
1581
1582     g_return_val_if_fail(widget, FALSE);
1583     g_return_val_if_fail(data, FALSE);
1584
1585
1586     editor = HILDON_TIME_EDITOR(data);
1587     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1588
1589     /* validate to set the time and get infoprints
1590      * if the user was editing the value
1591      */
1592     hildon_time_editor_validate (editor);
1593     if (priv->am) {
1594       if (priv->ticks >= (12*3600))
1595         {
1596           hildon_time_editor_set_ticks (editor, priv->ticks - 12*3600);
1597         } else 
1598         {
1599           hildon_time_editor_set_ticks (editor, priv->ticks + 12*3600);
1600         }
1601     } else {
1602         hildon_time_editor_set_ticks (editor, priv->ticks - 12*3600);
1603     }
1604     return FALSE;
1605 }
1606
1607 static gboolean
1608 hildon_time_editor_icon_clicked(GtkWidget * widget, gpointer data)
1609 {
1610     HildonTimeEditor *editor;
1611     HildonTimeEditorPrivate *priv;
1612     GtkWidget *picker;
1613     GtkWidget *parent;
1614     guint h, m, s, result;
1615
1616     g_return_val_if_fail(widget, FALSE);
1617     g_return_val_if_fail(data, FALSE);
1618
1619     editor = HILDON_TIME_EDITOR(data);
1620     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1621
1622     /* icon is passive in duration editor mode */
1623     if (priv->duration_mode)
1624         return FALSE;
1625
1626     parent = gtk_widget_get_ancestor(GTK_WIDGET(editor), GTK_TYPE_WINDOW);
1627     picker = hildon_time_picker_new(GTK_WINDOW(parent));
1628
1629     hildon_time_editor_get_time(editor, &h, &m, &s);
1630     hildon_time_picker_set_time(HILDON_TIME_PICKER(picker), h, m);
1631
1632     result = gtk_dialog_run(GTK_DIALOG(picker));
1633     switch (result) {
1634     case GTK_RESPONSE_OK:
1635     case GTK_RESPONSE_ACCEPT:
1636         hildon_time_picker_get_time(HILDON_TIME_PICKER(picker), &h, &m);
1637         hildon_time_editor_set_time(editor, h, m, 0);
1638         break;
1639     default:
1640         break;
1641     }
1642
1643     gtk_widget_destroy(picker);
1644     return FALSE;
1645 }
1646
1647 static gboolean hildon_time_editor_entry_clicked(GtkWidget * widget,
1648                                                  GdkEventButton * event,
1649                                                  gpointer data)
1650 {
1651     HildonTimeEditor *editor;
1652     HildonTimeEditorPrivate *priv;
1653
1654     editor = HILDON_TIME_EDITOR (data);
1655     priv = HILDON_TIME_EDITOR_GET_PRIVATE (editor);
1656
1657     /* If the focus has been grabbed back before the "clicked"
1658      * signal gets processed, don't highlight the text
1659      */
1660     if (gtk_widget_is_focus (widget))
1661         gtk_editable_select_region(GTK_EDITABLE(widget), 0, 2);
1662
1663     return FALSE;
1664 }
1665
1666 static void hildon_time_editor_size_request(GtkWidget * widget,
1667                                             GtkRequisition * requisition)
1668 {
1669     HildonTimeEditor *editor;
1670     HildonTimeEditorPrivate *priv;
1671     GtkRequisition req;
1672
1673     editor = HILDON_TIME_EDITOR(widget);
1674     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1675
1676     gtk_widget_size_request(priv->frame, &req);
1677     *requisition = req;
1678
1679     requisition->width = TIME_EDITOR_LBORDER + TIME_EDITOR_RBORDER;
1680
1681     gtk_widget_size_request(priv->h_entry, &req);
1682     requisition->width += req.width;
1683
1684     gtk_widget_size_request(priv->m_entry, &req);
1685     requisition->width += req.width;
1686
1687     gtk_widget_size_request(priv->label, &req);
1688     requisition->width += req.width;
1689
1690     if (priv->iconbutton && GTK_WIDGET_VISIBLE(priv->iconbutton))
1691     {
1692         gtk_widget_size_request(priv->iconbutton, &req);
1693         requisition->width += ICON_WIDTH + ICON_PRESSED + 
1694                               TIME_EDITOR_CLOCK_BORDER;
1695     }
1696
1697     if (priv->show_s) {
1698         gtk_widget_size_request(priv->s_entry, &req);
1699         requisition->width += req.width;
1700
1701         gtk_widget_size_request(priv->label2, &req);
1702         requisition->width += req.width;
1703     }
1704
1705     if (!priv->clock_24h && !priv->duration_mode) {
1706         gtk_widget_size_request(priv->eventbox, &req);
1707         requisition->width += req.width + 4;
1708     }
1709
1710     requisition->height = TIME_EDITOR_HEIGHT + widget->style->ythickness * 2;
1711 }
1712
1713 static void set_widget_allocation(GtkWidget * widget,
1714                                   GtkAllocation * alloc,
1715                                   GtkAllocation * allocation)
1716 {
1717     GtkRequisition child_requisition;
1718
1719     gtk_widget_get_child_requisition(widget, &child_requisition);
1720
1721     if (allocation->width + allocation->x >
1722         alloc->x + child_requisition.width)
1723         alloc->width = child_requisition.width;
1724     else {
1725         alloc->width = allocation->width - (alloc->x - allocation->x);
1726         if (alloc->width < 0)
1727             alloc->width = 0;
1728     }
1729     gtk_widget_size_allocate(widget, alloc);
1730     alloc->x += alloc->width;
1731 }
1732
1733 static void hildon_time_editor_size_allocate(GtkWidget * widget,
1734                                              GtkAllocation * allocation)
1735 {
1736     HildonTimeEditor *editor;
1737     HildonTimeEditorPrivate *priv;
1738     GtkAllocation alloc;
1739     GtkAllocation child_alloc;
1740     GtkRequisition child_requisition;
1741     gint mod_w = 0;
1742
1743     editor = HILDON_TIME_EDITOR(widget);
1744     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1745
1746     widget->allocation = *allocation;
1747
1748     /*Init start values*/
1749     alloc.y = widget->allocation.y + widget->style->ythickness;
1750
1751     if (widget->allocation.height > (TIME_EDITOR_HEIGHT +
1752                                      widget->style->ythickness * 2)) {
1753         alloc.height = TIME_EDITOR_HEIGHT;
1754         alloc.y +=
1755             (widget->allocation.height - TIME_EDITOR_HEIGHT) / 2;
1756     } else
1757         alloc.height =
1758             widget->allocation.height - widget->style->ythickness * 2;
1759
1760     if (alloc.height < 0)
1761         alloc.height = 0;
1762
1763     gtk_widget_get_child_requisition(widget, &child_requisition);
1764     if (allocation->width > child_requisition.width) {
1765         mod_w = (allocation->width - child_requisition.width) / 2;
1766         alloc.x = allocation->x + mod_w;
1767     } else
1768         alloc.x = allocation->x;
1769
1770
1771     /** frame **/
1772     if (priv->frame && GTK_WIDGET_VISIBLE(priv->frame))
1773     {
1774         alloc.width = child_requisition.width -
1775             TIME_EDITOR_CLOCK_BORDER - ICON_WIDTH - ICON_PRESSED;
1776         gtk_widget_size_allocate(priv->frame, &alloc);
1777     }
1778
1779     /** icon **/
1780     if (priv->iconbutton && GTK_WIDGET_VISIBLE(priv->iconbutton)) {
1781         gtk_widget_get_child_requisition(priv->iconbutton, 
1782                 &child_requisition);
1783
1784         child_alloc.x = alloc.x + alloc.width + TIME_EDITOR_CLOCK_BORDER;
1785
1786         if(alloc.height > ICON_HEIGHT)
1787             child_alloc.y = alloc.y + (alloc.height - ICON_HEIGHT) / 2 -1;
1788         else
1789             child_alloc.y = alloc.y;
1790         child_alloc.height = ICON_HEIGHT + ICON_PRESSED / 2;
1791         child_alloc.width = ICON_WIDTH + ICON_PRESSED;
1792         gtk_widget_size_allocate(priv->iconbutton, &child_alloc);
1793     }
1794
1795     /* allocation of child widgets */
1796     child_alloc.x = alloc.x + TIME_EDITOR_LBORDER;
1797     child_alloc.y = alloc.y;
1798     child_alloc.height = TIME_EDITOR_HEIGHT;
1799     child_alloc.width = -1;
1800
1801     /* am/pm label (when first) */
1802     if (!priv->duration_mode) {
1803         if (!priv->clock_24h && !priv->ampm_pos_after)
1804           {
1805             set_widget_allocation(priv->eventbox, &child_alloc,
1806                     &widget->allocation);
1807           }
1808     }
1809
1810     /* hours */
1811     if (priv->h_entry && GTK_WIDGET_VISIBLE(priv->h_entry))
1812       {
1813         child_alloc.y += ENTRY_BORDER;
1814         child_alloc.height -= ENTRY_BORDER * 2;
1815         set_widget_allocation(priv->h_entry, &child_alloc,
1816                 &widget->allocation);
1817         child_alloc.y -= ENTRY_BORDER;
1818         child_alloc.height += ENTRY_BORDER * 2;
1819       }
1820
1821     /* first separator label */
1822     if (priv->label && GTK_WIDGET_VISIBLE(priv->label))
1823       {
1824         /* We'll have to subtract the ythickness from the labels
1825          * allocation or it'll be there twice
1826          */
1827         child_alloc.y -= widget->style->ythickness;
1828         set_widget_allocation(priv->label, &child_alloc,
1829                 &widget->allocation);
1830         child_alloc.y += widget->style->ythickness;
1831       }
1832     /* minutes */
1833     if (priv->m_entry && GTK_WIDGET_VISIBLE(priv->m_entry))
1834       {
1835         /* Entries have a little different allocation requirements
1836          * so we'll have to accommodate. This is done per entry
1837          * so that the "running" width value of the allocation isn't lost
1838          * FIXME: Rearrange this code so it could be done just once
1839          */
1840         child_alloc.y += ENTRY_BORDER;
1841         child_alloc.height -= ENTRY_BORDER * 2;
1842         set_widget_allocation(priv->m_entry, &child_alloc,
1843                 &widget->allocation);
1844         child_alloc.y -= ENTRY_BORDER;
1845         child_alloc.height += ENTRY_BORDER * 2;
1846       }
1847     
1848     if (priv->show_s) {
1849         /* second separator label */
1850         if (priv->label2)
1851           {
1852             child_alloc.y -= widget->style->ythickness;
1853             set_widget_allocation(priv->label2, &child_alloc,
1854                     &widget->allocation);
1855             child_alloc.y += widget->style->ythickness;
1856           }
1857
1858         /* seconds */
1859         if (priv->s_entry)
1860           {
1861             child_alloc.y += ENTRY_BORDER;
1862             child_alloc.height -= ENTRY_BORDER * 2;
1863             set_widget_allocation(priv->s_entry, &child_alloc,
1864                     &widget->allocation);
1865             child_alloc.y -= ENTRY_BORDER;
1866             child_alloc.height += ENTRY_BORDER * 2;
1867           }
1868     }
1869
1870     /* am/pm label (when last) */
1871     if (!priv->duration_mode) {
1872         if (!priv->clock_24h && priv->ampm_pos_after)
1873           {
1874             child_alloc.y -= widget->style->ythickness;
1875             set_widget_allocation(priv->eventbox, &child_alloc,
1876                     &widget->allocation);
1877             child_alloc.y += widget->style->ythickness;
1878           }
1879     }
1880 }
1881
1882 static gboolean hildon_time_editor_entry_keypress(GtkWidget * widget,
1883                                                   GdkEventKey * event,
1884                                                   gpointer data)
1885 {
1886     HildonTimeEditor *editor;
1887     HildonTimeEditorPrivate *priv;
1888     gint pos;
1889
1890     g_return_val_if_fail(widget, FALSE);
1891     g_return_val_if_fail(event, FALSE);
1892     g_return_val_if_fail(data, FALSE);
1893
1894     editor = HILDON_TIME_EDITOR(data);
1895     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
1896
1897     pos = gtk_editable_get_position(GTK_EDITABLE(widget));
1898
1899     if (event->keyval == GDK_Return) {
1900         /* Check that we have correct values in entries */
1901         hildon_time_editor_validate (editor);
1902         _gtk_button_set_depressed(GTK_BUTTON(priv->iconbutton), TRUE);
1903         hildon_time_editor_icon_clicked(widget, data);
1904         _gtk_button_set_depressed(GTK_BUTTON(priv->iconbutton), FALSE);
1905         return TRUE;
1906     }
1907     
1908     if  (event->keyval == GDK_KP_Enter)
1909         return FALSE;
1910
1911     /* We don't want wrap */
1912     if (event->keyval == GDK_KP_Left || event->keyval == GDK_Left) {
1913         if (pos == 0 && widget == priv->h_entry) {
1914             return TRUE;
1915         }
1916     }
1917
1918     if (event->keyval == GDK_KP_Right || event->keyval == GDK_Right) {
1919         if (pos >= strlen(GTK_ENTRY(widget)->text)) {
1920             if ((widget == priv->m_entry
1921                  && !GTK_WIDGET_REALIZED(priv->s_entry))
1922                 || (widget == priv->s_entry
1923                     && GTK_WIDGET_REALIZED(priv->s_entry))) {
1924                 return TRUE;
1925             }
1926         }
1927     }
1928
1929     /* numeric key pressed */
1930     if (event->keyval >= GDK_0 && event->keyval <= GDK_9) {
1931         GtkWidgetClass *c = GTK_WIDGET_GET_CLASS(widget);
1932
1933         c->key_press_event(widget, event);
1934
1935         if (GTK_IS_ENTRY (widget))
1936           {
1937             if (strlen (gtk_entry_get_text (GTK_ENTRY (widget))) == 2)
1938               {
1939                 hildon_time_editor_validate (editor);
1940               }
1941           }
1942
1943         return TRUE;
1944     }
1945     /* tab pressed in hour entry */
1946     else if (widget == priv->h_entry && (event->keyval == GDK_Tab ||
1947                    event->keyval == GDK_KP_Tab)) {
1948         gtk_widget_grab_focus(priv->m_entry);
1949         return TRUE;
1950     }
1951     /* tab pressed in minute entry */
1952     else if (widget == priv->m_entry && (event->keyval == GDK_Tab ||
1953                    event->keyval == GDK_KP_Tab)) {
1954         if (priv->show_s)
1955             gtk_widget_grab_focus(priv->s_entry);
1956         else
1957             gtk_widget_grab_focus(priv->h_entry);
1958         return TRUE;
1959     }
1960     /* tab pressed in second entry */
1961     else if (widget == priv->s_entry && (event->keyval == GDK_Tab ||
1962                    event->keyval == GDK_KP_Tab)) {
1963         gtk_widget_grab_focus(priv->h_entry);
1964         return TRUE;
1965     }
1966     /* left tab pressed in second entry */
1967     else if (widget == priv->s_entry &&
1968              event->keyval == GDK_ISO_Left_Tab) {
1969         gtk_widget_grab_focus(priv->m_entry);
1970         return TRUE;
1971     }
1972     /* left tab pressed in minute entry */
1973     else if (widget == priv->m_entry &&
1974              event->keyval == GDK_ISO_Left_Tab) {
1975         gtk_widget_grab_focus(priv->h_entry);
1976         return TRUE;
1977     }
1978     /* left tab pressed in hour entry */
1979     else if (widget == priv->h_entry &&
1980              event->keyval == GDK_ISO_Left_Tab) {
1981         if (priv->show_s)
1982             gtk_widget_grab_focus(priv->s_entry);
1983         else
1984             gtk_widget_grab_focus(priv->m_entry);
1985         return TRUE;
1986     }
1987     /* right arrow pressed in hour entry */
1988     else if (widget == priv->h_entry &&
1989              (event->keyval == GDK_Right || event->keyval == GDK_KP_Right)
1990              && pos >= GTK_ENTRY(priv->h_entry)->text_length) {
1991         gtk_widget_grab_focus(priv->m_entry);
1992         gtk_editable_set_position(GTK_EDITABLE(priv->m_entry), 0);
1993         return TRUE;
1994     }
1995     /* right arrow pressed in minute entry */
1996     else if (widget == priv->m_entry &&
1997              (event->keyval == GDK_Right || event->keyval == GDK_KP_Right)
1998              && pos >= GTK_ENTRY(priv->m_entry)->text_length) {
1999         if (priv->show_s) {
2000             gtk_widget_grab_focus(priv->s_entry);
2001             gtk_editable_set_position(GTK_EDITABLE(priv->s_entry), 0);
2002         } else {
2003             gtk_widget_grab_focus(priv->h_entry);
2004             gtk_editable_set_position(GTK_EDITABLE(priv->h_entry), 0);
2005         }
2006         return TRUE;
2007     }
2008     /* right arrow pressed in second entry */
2009     else if (widget == priv->s_entry &&
2010              (event->keyval == GDK_Right || event->keyval == GDK_KP_Right)
2011              && pos >= GTK_ENTRY(priv->s_entry)->text_length) {
2012         gtk_widget_grab_focus(priv->h_entry);
2013         gtk_editable_set_position(GTK_EDITABLE(priv->h_entry), 0);
2014         return TRUE;
2015     }
2016     /* left arrow key pressed in hour entry */
2017     else if (widget == priv->h_entry &&
2018              (event->keyval == GDK_Left || event->keyval == GDK_KP_Left) &&
2019              pos <= 0) {
2020         if (priv->show_s) {
2021             gtk_widget_grab_focus(priv->s_entry);
2022             gtk_editable_set_position(GTK_EDITABLE(priv->s_entry), -1);
2023         } else {
2024             gtk_widget_grab_focus(priv->m_entry);
2025             gtk_editable_set_position(GTK_EDITABLE(priv->m_entry), -1);
2026         }
2027         return TRUE;
2028     }
2029     /* left arrow key pressed in minute entry */
2030     else if (widget == priv->m_entry &&
2031              (event->keyval == GDK_Left || event->keyval == GDK_KP_Left) &&
2032              pos <= 0) {
2033         gtk_widget_grab_focus(priv->h_entry);
2034         gtk_editable_set_position(GTK_EDITABLE(priv->h_entry), -1);
2035         return TRUE;
2036     }
2037     /* left arrow key pressed in seconds entry */
2038     else if (widget == priv->s_entry &&
2039              (event->keyval == GDK_Left || event->keyval == GDK_KP_Left) &&
2040              pos <= 0) {
2041         gtk_widget_grab_focus(priv->m_entry);
2042         gtk_editable_set_position(GTK_EDITABLE(priv->m_entry), -1);
2043         return TRUE;
2044     }
2045     /* pass other arrow key presses and backspace and del onwards */
2046     else if (event->keyval == GDK_Left || event->keyval == GDK_KP_Left ||
2047              event->keyval == GDK_Right || event->keyval == GDK_KP_Right ||
2048              event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
2049              event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
2050              event->keyval == GDK_BackSpace || event->keyval == GDK_Delete
2051              || event->keyval == GDK_KP_Delete)
2052         return FALSE;   /* pass the keypress on */
2053
2054     /* ingore other keys */
2055     return TRUE;
2056 }
2057
2058 static HildonValidation
2059 hildon_time_editor_validate_duration (HildonTimeEditor * editor, guint ticks)
2060 {
2061   HildonTimeEditorPrivate *priv;
2062
2063   g_return_val_if_fail (editor, VALIDATION_ERROR);
2064
2065   priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
2066
2067   if (ticks > priv->duration_max)
2068     return VALIDATION_DURATION_MAX;
2069
2070   if (ticks < priv->duration_min)
2071     return VALIDATION_DURATION_MIN;
2072
2073   return (VALIDATION_OK);
2074 }
2075
2076
2077 static HildonValidation
2078 hildon_time_editor_validate_time (HildonTimeEditor * editor,
2079                                   guint hours,
2080                                   guint minutes,
2081                                   guint seconds,
2082                                   gboolean mode_24h)
2083 {
2084   HildonTimeEditorPrivate *priv;
2085
2086   g_return_val_if_fail (editor, VALIDATION_ERROR);
2087
2088   priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
2089
2090   priv->validated = FALSE;
2091
2092   if (mode_24h) {
2093     if (hours < HOURS_MIN_24 || hours > HOURS_MAX_24)
2094         return VALIDATION_TIME_HOURS;
2095   } else {
2096     if (hours < HOURS_MIN_12 || hours > HOURS_MAX_12)
2097         return VALIDATION_TIME_HOURS;
2098   }
2099
2100   if (minutes < MINUTES_MIN || minutes > MINUTES_MAX)
2101     return VALIDATION_TIME_MINUTES;
2102   
2103   if (seconds < SECONDS_MIN || seconds > SECONDS_MAX)
2104     return VALIDATION_TIME_SECONDS;
2105
2106   priv->validated = TRUE;
2107   return (VALIDATION_OK);
2108 }
2109
2110 static void
2111 hildon_time_editor_entry_changed(GtkWidget * widget, gpointer user_data)
2112 {
2113   HildonTimeEditor *editor;
2114
2115   editor = HILDON_TIME_EDITOR(user_data);
2116
2117 /*  hildon_time_editor_validate (editor);*/
2118 }
2119
2120 /* NOTE: This function is mostly broken for the duration mode */
2121 static void
2122 hildon_time_editor_get_max_values(HildonTimeEditor *editor, 
2123         guint * pmax_hours, guint * pmin_hours,
2124         guint * pmax_minutes, guint * pmin_minutes,
2125         guint * pmax_seconds, guint * pmin_seconds)
2126 {
2127     guint max_hours;
2128     guint max_minutes;
2129     guint max_seconds;
2130     guint min_hours;
2131     guint min_minutes;
2132     guint min_seconds;
2133
2134     HildonTimeEditorPrivate *priv;
2135
2136     priv = HILDON_TIME_EDITOR_GET_PRIVATE(editor);
2137
2138     max_hours   = priv->duration_max / 3600;
2139     max_minutes = (priv->duration_max - (max_hours * 3600)) / 60;
2140     max_seconds = priv->duration_max - (max_hours * 3600) - (max_minutes * 60);
2141     min_hours   = priv->duration_min / 3600;
2142     min_minutes = (priv->duration_min - (min_hours * 3600)) / 60;
2143     min_seconds = priv->duration_min - (min_hours * 3600) - (min_minutes * 60);
2144
2145     /* Determine max and min values for duration mode */
2146     if (priv->duration_mode)
2147     {
2148       /* if the widget has focus, the value could be out of range, so
2149          use the calculated values then
2150        */
2151       if (!gtk_widget_is_focus (priv->h_entry))
2152         {
2153           if ((guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->h_entry))) < max_hours)
2154             {
2155               max_minutes = 59;
2156               max_seconds = 59;
2157             }
2158           if ((guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->h_entry))) > min_hours)
2159             {
2160               min_minutes = 0;
2161               min_seconds = 0;
2162             }
2163         }
2164       if (!gtk_widget_is_focus (priv->m_entry))
2165         {
2166           if ((guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->m_entry))) < max_minutes)
2167             {
2168               max_seconds = 59;
2169             }
2170           if ((guint) atoi(gtk_entry_get_text(GTK_ENTRY(priv->m_entry))) > min_minutes)
2171             {
2172               min_seconds = 0;
2173             }
2174         }
2175     }
2176     /* 24h clock mode */
2177     else if (priv->clock_24h) {
2178         max_hours = 23;
2179         max_seconds = max_minutes = 59;
2180         min_seconds = min_minutes = min_hours = 0;
2181     }
2182     /* 12h clock mode */
2183     else {
2184         max_hours = 12;
2185         min_hours = 1;
2186         max_seconds = max_minutes = 59;
2187         min_seconds = min_minutes = 0;
2188     }
2189
2190     *pmax_hours   = max_hours;
2191     *pmax_minutes = max_minutes;
2192     *pmax_seconds = max_seconds;
2193     *pmin_hours   = min_hours;
2194     *pmin_minutes = min_minutes;
2195     *pmin_seconds = min_seconds;
2196   
2197 }
2198
2199 /*** 
2200  * Utility functions
2201  */
2202
2203 static void
2204 convert_to_12h (guint *h, guint *m, guint *s, gboolean *am)
2205 {
2206   /* Official time hack: As 12am and 12pm are technically invalid
2207      times, we add a minute to 24h time 00:00 and subtract one from
2208      24h time 12:00 when in 12h mode. This is a custom in railroads
2209      airlines and insurance companies.
2210    */
2211   if (*h == 0 && *m == 0 && *s == 0)
2212     {
2213       *m++;
2214     }
2215   else if (*h == 12 && *m == 0 && *s == 0)
2216     {
2217       *h--;
2218       *m = 59;
2219     }
2220   
2221   /* 0000 to 0059
2222    * add 12 hours
2223    */
2224   if (*h == 0)
2225     {
2226       *h += 12;
2227       *am = TRUE;
2228     }
2229   /* 0100 to 1159
2230    * straight to am
2231    */
2232   else if (*h >= 1 && *h < 12)
2233     {
2234       *am = TRUE;
2235     }
2236   /* 1200 to 1259
2237    * straight to pm
2238    */
2239   else if (*h >= 12 && *h < 13)
2240     {
2241       *am = FALSE;
2242     }
2243   /* 1300 to 23:59
2244    * subtract 12 hours
2245    */
2246   else if (*h >= 13 && *h < 24 )
2247     {
2248       *h -= 12;
2249       *am = FALSE;
2250     }
2251 }
2252
2253 static void
2254 convert_to_24h (guint *h, guint *m, guint *s, gboolean am)
2255 {
2256   /* Official time hack: As 12am and 12pm are technically invalid
2257      times, we add a minute to 24h time 00:00 and subtract one from
2258      24h time 12:00 when in 12h mode. This is a custom in railroads
2259      airlines and insurance companies.
2260    */
2261   if (am && *h == 12 && *m == 0 && *s == 0)
2262     {
2263       *m++;
2264     }
2265   else if (!am && *h == 12 && *m == 0 && *s == 0)
2266     {
2267       *h--;
2268       *m = 59;
2269     }
2270   
2271   /* 12 midnight - 12:59 AM
2272    * subtract 12 hours
2273    */
2274   if (*h == 12 && am)
2275     {
2276       *h -= 12;
2277     }
2278   /* 1:00 PM - 11:59 AM
2279    * add 12 hours
2280    */
2281   else if (!am && *h >= 1 && *h < 12)
2282     {
2283       *h += 12;
2284     }
2285 }
2286
2287 /***
2288  * Deprecated functions
2289  */
2290
2291
2292 #ifndef HILDON_DISABLE_DEPRECATED
2293
2294 /**
2295  * hildon_time_editor_show_seconds:
2296  * @editor: The #HildonTimeEditor.
2297  * @enable: Enable or disable showing of seconds.
2298  *
2299  * This function is deprecated, use @hildon_time_editor_set_show_seconds instead.
2300  *
2301  **/
2302 void hildon_time_editor_show_seconds(HildonTimeEditor * editor,
2303                                      gboolean enable)
2304 {
2305     hildon_time_editor_set_show_seconds (editor, enable);
2306 }
2307 /**
2308  * hildon_time_editor_enable_duration_mode:
2309  * @editor: The #HildonTimeEditor.
2310  * @enable: Enable or disable duration editor mode
2311  *
2312  * This function is deprecated, use @hildon_time_editor_set_duration_mode instead.
2313  *
2314  **/
2315 void hildon_time_editor_enable_duration_mode(HildonTimeEditor * editor,
2316                                              gboolean enable)
2317 {
2318     hildon_time_editor_set_duration_mode (editor, enable);
2319 }
2320
2321 #endif /* HILDON_DISABLE_DEPRECATED */