Initialize Tizen 2.3
[framework/uifw/elementary.git] / mobile / src / lib / elm_datetime.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_datetime.h"
4
5 #ifdef HAVE_LOCALE_H
6 # include <locale.h>
7 #endif
8
9 #ifdef HAVE_LANGINFO_H
10 # include <langinfo.h>
11 #endif
12
13 EAPI const char ELM_DATETIME_SMART_NAME[] = "elm_datetime";
14
15 #define MAX_SEPARATOR_LEN              6
16 #define MIN_DAYS_IN_MONTH              28
17 #define BUFFER_SIZE                    1024
18
19 /* interface between EDC & C code (field & signal names). values 0 to
20  * ELM_DATETIME_TYPE_COUNT are in the valid range, and must get in the
21  * place of "%d".
22  */
23 #define EDC_DATETIME_FOCUSIN_SIG_STR   "elm,action,focus"
24 #define EDC_DATETIME_FOCUSOUT_SIG_STR  "elm,action,unfocus"
25 #define EDC_PART_FIELD_STR             "field%d"
26 #define EDC_PART_SEPARATOR_STR         "separator%d"
27 #define EDC_PART_FIELD_ENABLE_SIG_STR  "field%d,enable"
28 #define EDC_PART_FIELD_DISABLE_SIG_STR "field%d,disable"
29 #define EDC_PART_FIELD_SEPARATOR_ENABLE_SIG_STR  "field%d,separator,enable"
30 #define EDC_PART_FIELD_SEPARATOR_DISABLE_SIG_STR "field%d,separator,disable"
31
32 /* struct tm does not define the fields in the order year, month,
33  * date, hour, minute. values are reassigned to an array for easy
34  * handling.
35  */
36 #define DATETIME_TM_ARRAY(intptr, tmptr) \
37   int *intptr[] = {                      \
38      &(tmptr)->tm_year,                  \
39      &(tmptr)->tm_mon,                   \
40      &(tmptr)->tm_mday,                  \
41      &(tmptr)->tm_hour,                  \
42      &(tmptr)->tm_min}
43
44 // default limits for individual fields
45 static Format_Map mapping[ELM_DATETIME_TYPE_COUNT] = {
46    [ELM_DATETIME_YEAR] = { "Yy", -1, -1, "" },
47    [ELM_DATETIME_MONTH] = { "mbBh", 0, 11, "" },
48    [ELM_DATETIME_DATE] = { "de", 1, 31, "" },
49    [ELM_DATETIME_HOUR] = { "IHkl", 0, 23, "" },
50    [ELM_DATETIME_MINUTE] = { "M", 0, 59, ":" },
51    [ELM_DATETIME_AMPM] = { "pP", 0, 1, "" }
52 };
53
54 static const char *multifield_formats = "cxXrRTDF";
55 static const char *ignore_separators = "() ";
56 static Datetime_Mod_Api *dt_mod = NULL;
57
58 static const char SIG_CHANGED[] = "changed";
59 static const char SIG_LANGUAGE_CHANGED[] = "language,changed";
60 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
61    {SIG_CHANGED, ""},
62    {SIG_LANGUAGE_CHANGED, ""},
63    {NULL, NULL}
64 };
65
66 EVAS_SMART_SUBCLASS_NEW
67   (ELM_DATETIME_SMART_NAME, _elm_datetime, Elm_Datetime_Smart_Class,
68   Elm_Layout_Smart_Class, elm_layout_smart_class_get, _smart_callbacks);
69
70 static Datetime_Mod_Api *
71 _dt_mod_init()
72 {
73    Elm_Module *mod = NULL;
74
75    if (!(mod = _elm_module_find_as("datetime/api"))) return NULL;
76
77    mod->api = malloc(sizeof(Datetime_Mod_Api));
78    if (!mod->api) return NULL;
79
80    ((Datetime_Mod_Api *)(mod->api))->obj_hook =
81      _elm_module_symbol_get(mod, "obj_hook");
82    ((Datetime_Mod_Api *)(mod->api))->obj_unhook =
83      _elm_module_symbol_get(mod, "obj_unhook");
84    ((Datetime_Mod_Api *)(mod->api))->obj_theme_hook =
85      _elm_module_symbol_get(mod, "obj_theme_hook");
86    ((Datetime_Mod_Api *)(mod->api))->obj_format_hook =
87      _elm_module_symbol_get(mod, "obj_format_hook");
88    ((Datetime_Mod_Api *)(mod->api))->obj_focus_hook =
89      _elm_module_symbol_get(mod, "obj_focus_hook");
90    ((Datetime_Mod_Api *)(mod->api))->focus_object_list_get =
91      _elm_module_symbol_get(mod, "focus_object_list_get");
92    ((Datetime_Mod_Api *)(mod->api))->access_register =
93      _elm_module_symbol_get(mod, "access_register");
94    ((Datetime_Mod_Api *)(mod->api))->create_fields =
95      _elm_module_symbol_get(mod, "create_fields");
96    ((Datetime_Mod_Api *)(mod->api))->display_fields =
97      _elm_module_symbol_get(mod, "display_fields");
98
99    return mod->api;
100 }
101
102 // FIXME: provide nl_langinfo on Windows if possible
103 // returns expanded format string for corresponding multi-field format character
104 static char *
105 _expanded_fmt_str_get(char ch)
106 {
107    char *exp_fmt = "";
108    switch (ch)
109      {
110       case 'c':
111 #ifdef HAVE_LANGINFO_H
112         exp_fmt = nl_langinfo(D_T_FMT);
113 #else
114         exp_fmt = "";
115 #endif
116         break;
117
118       case 'x':
119 #ifdef HAVE_LANGINFO_H
120         exp_fmt = nl_langinfo(D_FMT);
121 #else
122         exp_fmt = "";
123 #endif
124         break;
125
126       case 'X':
127 #ifdef HAVE_LANGINFO_H
128         exp_fmt = nl_langinfo(T_FMT);
129 #else
130         exp_fmt = "";
131 #endif
132         break;
133
134       case 'r':
135 #ifdef HAVE_LANGINFO_H
136         exp_fmt = nl_langinfo(T_FMT_AMPM);
137 #else
138         exp_fmt = "";
139 #endif
140         break;
141
142       case 'R':
143         exp_fmt = "%H:%M";
144         break;
145
146       case 'T':
147         exp_fmt = "%H:%M:%S";
148         break;
149
150       case 'D':
151         exp_fmt = "%m/%d/%y";
152         break;
153
154       case 'F':
155         exp_fmt = "%Y-%m-%d";
156         break;
157
158       default:
159         exp_fmt = "";
160         break;
161      }
162
163    return exp_fmt;
164 }
165
166 static void
167 _expand_format(char *dt_fmt)
168 {
169    char *ptr, *expanded_fmt, ch;
170    unsigned int idx = 0, len = 0;
171    char buf[ELM_DATETIME_MAX_FORMAT_LEN] = {0, };
172    Eina_Bool fmt_char = EINA_FALSE;
173
174    ptr = dt_fmt;
175    while ((ch = *ptr))
176      {
177         if ((fmt_char) && (strchr(multifield_formats, ch)))
178           {
179              /* replace the multi-field format characters with
180               * corresponding expanded format */
181              expanded_fmt = _expanded_fmt_str_get(ch);
182              len = strlen(expanded_fmt);
183              buf[--idx] = 0;
184              strncat(buf, expanded_fmt, len);
185              idx += len;
186           }
187         else buf[idx++] = ch;
188
189         if (ch == '%') fmt_char = EINA_TRUE;
190         else fmt_char = EINA_FALSE;
191
192         ptr++;
193      }
194
195    buf[idx] = 0;
196    strncpy(dt_fmt, buf, ELM_DATETIME_MAX_FORMAT_LEN);
197 }
198
199 static unsigned int
200 _parse_format(Evas_Object *obj,
201               char *fmt_ptr)
202 {
203    Eina_Bool fmt_parsing = EINA_FALSE, sep_parsing = EINA_FALSE,
204              sep_lookup = EINA_FALSE;
205    unsigned int len = 0, idx = 0, location = 0;
206    char separator[MAX_SEPARATOR_LEN];
207    Datetime_Field *field = NULL;
208    char cur;
209
210    ELM_DATETIME_DATA_GET(obj, sd);
211
212    while ((cur = *fmt_ptr))
213      {
214         if (fmt_parsing)
215           {
216              /* some locales have format specifiers like %-d for Date.
217               * parse each field format as similar to LIBC snprintf() formatting */
218              if ((cur == ' ' || cur == '-'))
219                {
220                   fmt_ptr++;
221                   continue;
222                }
223              fmt_parsing = EINA_FALSE;
224              for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
225                {
226                   if (strchr(mapping[idx].fmt_char, cur))
227                     {
228                        field = sd->field_list + idx;
229                        /* ignore the fields already have or disabled
230                         * valid formats, means already parsed &
231                         * repeated, ignore. */
232                        if (field->location != -1) break;
233                        field->fmt[1] = cur;
234                        field->fmt_exist = EINA_TRUE;
235                        field->location = location++;
236                        sep_lookup = EINA_TRUE;
237                        len = 0;
238                        break;
239                     }
240                }
241           }
242         if (cur == '%')
243           {
244              fmt_parsing = EINA_TRUE;
245              sep_parsing = EINA_FALSE;
246              // set the separator to previous field
247              separator[len] = 0;
248              if (field) eina_stringshare_replace(&field->separator, separator);
249           }
250         // ignore the set of chars (global, field specific) as field separators
251         if (sep_parsing &&
252             (len < MAX_SEPARATOR_LEN - 1) && field &&
253             (field->type != ELM_DATETIME_AMPM) &&
254             (!strchr(ignore_separators, cur)) &&
255             (!strchr(mapping[idx].ignore_sep, cur)))
256           separator[len++] = cur;
257         if (sep_lookup) sep_parsing = EINA_TRUE;
258         sep_lookup = EINA_FALSE;
259         fmt_ptr++;
260      }
261
262    //update the separator for last field
263    if (field)
264      {
265         separator[len] = 0;
266         eina_stringshare_replace(&field->separator, separator);
267      }
268
269    // return the number of valid fields parsed.
270    return location;
271 }
272
273 static void
274 _reload_format(Evas_Object *obj)
275 {
276    unsigned int idx, field_count;
277    Datetime_Field *field;
278    char buf[BUFFER_SIZE];
279    char *dt_fmt;
280
281    ELM_DATETIME_DATA_GET(obj, sd);
282
283    // FIXME: provide nl_langinfo on Windows if possible
284    // fetch the default format from Libc.
285    if (!sd->user_format)
286 #ifdef HAVE_LANGINFO_H
287      strncpy(sd->format, nl_langinfo(D_T_FMT), ELM_DATETIME_MAX_FORMAT_LEN);
288 #else
289      strncpy(sd->format, "", ELM_DATETIME_MAX_FORMAT_LEN);
290 #endif
291    sd->format[ELM_DATETIME_MAX_FORMAT_LEN - 1] = '\0';
292
293    dt_fmt = (char *)malloc(ELM_DATETIME_MAX_FORMAT_LEN);
294    if (!dt_fmt) return;
295
296    strncpy(dt_fmt, sd->format, ELM_DATETIME_MAX_FORMAT_LEN);
297
298    _expand_format(dt_fmt);
299
300    // reset all the fields to disable state
301    for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
302      {
303         field = sd->field_list + idx;
304         field->fmt_exist = EINA_FALSE;
305         field->location = -1;
306      }
307
308    field_count = _parse_format(obj, dt_fmt);
309    free(dt_fmt);
310
311    // assign locations to disabled fields for uniform usage
312    for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
313      {
314         field = sd->field_list + idx;
315         if (field->location == -1) field->location = field_count++;
316
317         if (field->fmt_exist && field->visible)
318           {
319              snprintf(buf, sizeof(buf), EDC_PART_FIELD_ENABLE_SIG_STR,
320                       field->location);
321              elm_layout_signal_emit(obj, buf, "elm");
322
323              if (field->separator && strcmp(field->separator, ""))
324                {
325                   snprintf(buf, sizeof(buf), EDC_PART_FIELD_SEPARATOR_ENABLE_SIG_STR,
326                            field->location);
327                   elm_layout_signal_emit(obj, buf, "elm");
328                   snprintf(buf, sizeof(buf), EDC_PART_SEPARATOR_STR, field->location);
329                   elm_layout_text_set(obj, buf, field->separator);
330                }
331              else
332                {
333                   snprintf(buf, sizeof(buf), EDC_PART_FIELD_SEPARATOR_DISABLE_SIG_STR,
334                            field->location);
335                   elm_layout_signal_emit(obj, buf, "elm");
336                }
337           }
338         else
339           {
340              snprintf(buf, sizeof(buf), EDC_PART_FIELD_DISABLE_SIG_STR,
341                       field->location);
342              elm_layout_signal_emit(obj, buf, "elm");
343              snprintf(buf, sizeof(buf), EDC_PART_FIELD_SEPARATOR_DISABLE_SIG_STR,
344                                         field->location);
345              elm_layout_signal_emit(obj, buf, "elm");
346           }
347      }
348
349    if ((dt_mod) && (dt_mod->obj_format_hook))
350      dt_mod->obj_format_hook(sd->mod_data);
351
352    if ((dt_mod) && (dt_mod->display_fields))
353      dt_mod->display_fields(sd->mod_data);
354 }
355
356 static Eina_Bool
357 _elm_datetime_smart_translate(Evas_Object *obj)
358 {
359    ELM_DATETIME_DATA_GET(obj, sd);
360
361    if (sd->user_format)
362      {
363         if ((dt_mod) && (dt_mod->display_fields))
364           dt_mod->display_fields(sd->mod_data);
365      }
366    else
367      _reload_format(obj);
368
369    evas_object_smart_callback_call(obj, SIG_LANGUAGE_CHANGED, NULL);
370
371    return EINA_TRUE;
372 }
373
374 static Eina_List *
375 _datetime_items_get(const Evas_Object *obj)
376 {
377    Eina_List *items = NULL;
378
379    ELM_DATETIME_DATA_GET(obj, sd);
380
381    if ((dt_mod) && (dt_mod->focus_object_list_get))
382      items = dt_mod->focus_object_list_get(sd->mod_data);
383
384    return items;
385 }
386
387 static Eina_Bool
388 _elm_datetime_smart_focus_next(const Evas_Object *obj,
389                                Elm_Focus_Direction dir,
390                                Evas_Object **next)
391 {
392    Eina_Bool ret;
393    const Eina_List *items;
394    Eina_List *(*list_free)(Eina_List *list);
395    void *(*list_data_get)(const Eina_List *list);
396
397    if ((items = elm_widget_focus_custom_chain_get(obj)))
398      {
399         list_data_get = eina_list_data_get;
400         list_free = NULL;
401      }
402    else
403      {
404         items = _datetime_items_get(obj);
405         list_data_get = eina_list_data_get;
406         list_free = eina_list_free;
407         if (!items) return EINA_FALSE;
408      }
409
410    ret = elm_widget_focus_list_next_get(obj, items, list_data_get, dir, next);
411    if (list_free) list_free((Eina_List *)items);
412
413    return ret;
414 }
415
416 static Eina_Bool
417 _elm_datetime_smart_on_focus(Evas_Object *obj)
418 {
419   ELM_DATETIME_DATA_GET(obj, sd);
420
421   if ((dt_mod) && (dt_mod->obj_focus_hook))
422     dt_mod->obj_focus_hook(sd->mod_data);
423
424    return EINA_TRUE;
425 }
426
427 static void
428 _elm_datetime_smart_sizing_eval(Evas_Object *obj)
429 {
430    Datetime_Field *field;
431    Evas_Coord minw = -1, minh = -1;
432    unsigned int idx, field_count = 0;
433
434    ELM_DATETIME_DATA_GET(obj, sd);
435
436    for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
437      {
438         field = sd->field_list + idx;
439         if ((field->visible) && (field->fmt_exist)) field_count++;
440      }
441    if (field_count)
442      elm_coords_finger_size_adjust(field_count, &minw, 1, &minh);
443    edje_object_size_min_restricted_calc
444      (ELM_WIDGET_DATA(sd)->resize_obj, &minw, &minh, minw, minh);
445    evas_object_size_hint_min_set(obj, minw, minh);
446    evas_object_size_hint_max_set(obj, -1, -1);
447 }
448
449 static Eina_Bool
450 _elm_datetime_smart_theme(Evas_Object *obj)
451 {
452    Datetime_Field *field;
453    char buf[BUFFER_SIZE];
454    unsigned int idx;
455
456    ELM_DATETIME_DATA_GET(obj, sd);
457
458    if (!ELM_WIDGET_CLASS(_elm_datetime_parent_sc)->theme(obj))
459      return EINA_FALSE;
460
461    if (!dt_mod) return EINA_TRUE;
462
463    for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
464      {
465         field = sd->field_list + idx;
466         if (field->fmt_exist && field->visible)
467           {
468              snprintf(buf, sizeof(buf), EDC_PART_FIELD_ENABLE_SIG_STR,
469                       field->location);
470              elm_layout_signal_emit(obj, buf, "elm");
471
472              if (field->separator && strcmp(field->separator, ""))
473                {
474                   snprintf(buf, sizeof(buf), EDC_PART_FIELD_SEPARATOR_ENABLE_SIG_STR,
475                            field->location);
476                   elm_layout_signal_emit(obj, buf, "elm");
477                   snprintf(buf, sizeof(buf), EDC_PART_SEPARATOR_STR, field->location);
478                   elm_layout_text_set(obj, buf, field->separator);
479                }
480              else
481                {
482                   snprintf(buf, sizeof(buf), EDC_PART_FIELD_SEPARATOR_DISABLE_SIG_STR,
483                            field->location);
484                   elm_layout_signal_emit(obj, buf, "elm");
485                }
486           }
487         else
488           {
489              snprintf(buf, sizeof(buf), EDC_PART_FIELD_DISABLE_SIG_STR,
490                       field->location);
491              elm_layout_signal_emit(obj, buf, "elm");
492              snprintf(buf, sizeof(buf), EDC_PART_FIELD_SEPARATOR_DISABLE_SIG_STR,
493                       field->location);
494              elm_layout_signal_emit(obj, buf, "elm");
495           }
496      }
497    elm_layout_sizing_eval(obj);
498
499    if (dt_mod->obj_theme_hook)
500      dt_mod->obj_theme_hook(sd->mod_data);
501
502    return EINA_TRUE;
503 }
504
505 static int
506 _max_days_get(int year,
507               int month)
508 {
509    struct tm time1;
510    time_t t;
511    int day;
512
513    t = time(NULL);
514    localtime_r(&t, &time1);
515    time1.tm_year = year;
516    time1.tm_mon = month;
517    for (day = MIN_DAYS_IN_MONTH; day <= mapping[ELM_DATETIME_DATE].def_max;
518         day++)
519      {
520         time1.tm_mday = day;
521         /* FIXME: To restrict month wrapping because of summer time in some locales,
522          * ignore day light saving mode in mktime(). */
523         time1.tm_isdst = -1;
524         mktime(&time1);
525         if (time1.tm_mday == 1) break;
526      }
527    day--;
528    return day;
529 }
530
531 static Eina_Bool
532 _date_cmp(struct tm *time1,
533           struct tm *time2)
534 {
535    unsigned int idx;
536
537    DATETIME_TM_ARRAY(timearr1, time1);
538    DATETIME_TM_ARRAY(timearr2, time2);
539
540    for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT - 1; idx++)
541      {
542         if (*timearr1[idx] != *timearr2[idx])
543           return EINA_FALSE;
544      }
545
546    return EINA_TRUE;
547 }
548
549 // validates curr_time/min_limt/max_limit according to the newly set value
550 static void
551 _validate_datetime_limits(struct tm *time1,
552                           struct tm *time2,
553                           Eina_Bool swap)
554 {
555    struct tm *t1, *t2;
556    unsigned int idx;
557
558    if (!time1 || !time2) return;
559
560    t1 = (swap) ? time2 : time1;
561    t2 = (swap) ? time1 : time2;
562
563    DATETIME_TM_ARRAY(timearr1, time1);
564    DATETIME_TM_ARRAY(timearr2, time2);
565    for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT - 1; idx++)
566      {
567         if (*timearr1[idx] < *timearr2[idx])
568           {
569              memcpy(t1, t2, sizeof(struct tm));
570              break;
571           }
572         else if (*timearr1[idx] > *timearr2[idx])
573           break;
574      }
575 }
576
577 static void
578 _apply_field_limits(Evas_Object *obj)
579 {
580    Datetime_Field *field;
581    unsigned int idx = 0;
582    int val;
583
584    ELM_DATETIME_DATA_GET(obj, sd);
585
586    DATETIME_TM_ARRAY(timearr, &sd->curr_time);
587    for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT - 1; idx++)
588      {
589         field = sd->field_list + idx;
590         val = *timearr[idx];
591         if (val < field->min)
592           *timearr[idx] = field->min;
593         else if (val > field->max)
594           *timearr[idx] = field->max;
595      }
596
597    if ((dt_mod) && (dt_mod->display_fields))
598      dt_mod->display_fields(sd->mod_data);
599 }
600
601 static void
602 _apply_range_restrictions(struct tm *tim)
603 {
604    unsigned int idx;
605    int val, min, max;
606
607    if (!tim) return;
608
609    DATETIME_TM_ARRAY(timearr, tim);
610    for (idx = ELM_DATETIME_MONTH; idx < ELM_DATETIME_TYPE_COUNT - 1; idx++)
611      {
612         val = *timearr[idx];
613         min = mapping[idx].def_min;
614         max = mapping[idx].def_max;
615         if (idx == ELM_DATETIME_DATE)
616           max = _max_days_get(tim->tm_year, tim->tm_mon);
617         if (val < min)
618           *timearr[idx] = min;
619         else if (val > max)
620           *timearr[idx] = max;
621      }
622 }
623
624 static const char *
625 _field_format_get(Evas_Object *obj,
626                   Elm_Datetime_Field_Type field_type)
627 {
628    Datetime_Field *field;
629
630    ELM_DATETIME_DATA_GET(obj, sd);
631
632    field = sd->field_list + field_type;
633    if (!field) return NULL;
634
635    return field->fmt;
636 }
637
638 static Eina_Bool
639 _field_location_get(Evas_Object *obj, Elm_Datetime_Field_Type field_type,
640                     int *loc)
641 {
642    Datetime_Field *field;
643
644    ELM_DATETIME_DATA_GET(obj, sd);
645
646    field = sd->field_list + field_type;
647    if (!field) return EINA_FALSE;
648
649    if (loc) *loc = field->location;
650
651    return (field->fmt_exist && field->visible);
652 }
653
654 static void
655 _field_limit_get(Evas_Object *obj,
656                  Elm_Datetime_Field_Type field_type,
657                  int *range_min,
658                  int *range_max)
659 {
660    int min, max, max_days;
661    Datetime_Field *field;
662    unsigned int idx;
663
664    ELM_DATETIME_DATA_GET(obj, sd);
665
666    field = sd->field_list + field_type;
667    if (!field) return;
668
669    min = field->min;
670    max = field->max;
671
672    DATETIME_TM_ARRAY(curr_timearr, &sd->curr_time);
673    DATETIME_TM_ARRAY(min_timearr, &sd->min_limit);
674    DATETIME_TM_ARRAY(max_timearr, &sd->max_limit);
675
676    for (idx = 0; idx < field->type; idx++)
677      if (*curr_timearr[idx] > *min_timearr[idx]) break;
678    if ((idx == field_type) && (min < *min_timearr[field_type]))
679      min = *min_timearr[field_type];
680    if (field_type == ELM_DATETIME_DATE)
681      {
682         max_days = _max_days_get(sd->curr_time.tm_year, sd->curr_time.tm_mon);
683         if (max > max_days) max = max_days;
684      }
685    for (idx = 0; idx < field->type; idx++)
686      if (*curr_timearr[idx] < *max_timearr[idx]) break;
687    if ((idx == field_type) && (max > *max_timearr[field_type]))
688      max = *max_timearr[field_type];
689
690    *range_min = min;
691    *range_max = max;
692 }
693
694 static void
695 _fields_min_max_get(Evas_Object *obj, struct tm *set_value,
696                     struct tm *min_value, struct tm *max_value)
697 {
698    int min, max, max_days;
699    Datetime_Field *field;
700    unsigned int i, idx;
701
702    ELM_DATETIME_DATA_GET(obj, sd);
703
704    if (!set_value || !min_value || !max_value) return;
705
706    DATETIME_TM_ARRAY(mod_set_timearr, set_value);
707    DATETIME_TM_ARRAY(mod_min_timearr, min_value);
708    DATETIME_TM_ARRAY(mod_max_timearr, max_value);
709
710    DATETIME_TM_ARRAY(min_timearr, &sd->min_limit);
711    DATETIME_TM_ARRAY(max_timearr, &sd->max_limit);
712
713    for (idx = 0; idx < ELM_DATETIME_AMPM; idx++)
714      {
715         field = sd->field_list + idx;
716         min = field->min;
717         max = field->max;
718
719         for (i = 0; i < idx; i++)
720           if (*mod_set_timearr[i] > *min_timearr[i]) break;
721         if ((i == idx) && (min < *min_timearr[idx]))
722           min = *min_timearr[idx];
723
724         if (idx == ELM_DATETIME_DATE)
725           {
726              max_days = _max_days_get(set_value->tm_year, set_value->tm_mon);
727              if (max > max_days) max = max_days;
728           }
729         for (i = 0; i < idx; i++)
730           if (*mod_set_timearr[i] < *max_timearr[i]) break;
731         if ((i == idx) && (max > *max_timearr[idx]))
732           max = *max_timearr[idx];
733
734         *mod_min_timearr[idx] = min;
735         *mod_max_timearr[idx] = max;
736      }
737 }
738
739 static void
740 _field_list_init(Evas_Object *obj)
741 {
742    Datetime_Field *field;
743    unsigned int idx;
744    time_t t;
745
746    ELM_DATETIME_DATA_GET(obj, sd);
747
748    t = time(NULL);
749    localtime_r(&t, &sd->curr_time);
750
751    mapping[ELM_DATETIME_YEAR].def_min = _elm_config->year_min;
752    mapping[ELM_DATETIME_YEAR].def_max = _elm_config->year_max;
753    for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
754      {
755         field = sd->field_list + idx;
756         field->type = ELM_DATETIME_YEAR + idx;
757         field->fmt[0] = '%';
758         field->fmt_exist = EINA_FALSE;
759         field->visible = EINA_TRUE;
760         field->min = mapping[idx].def_min;
761         field->max = mapping[idx].def_max;
762      }
763    DATETIME_TM_ARRAY(min_timearr, &sd->min_limit);
764    DATETIME_TM_ARRAY(max_timearr, &sd->max_limit);
765    for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT - 1; idx++)
766      {
767         *min_timearr[idx] = mapping[idx].def_min;
768         *max_timearr[idx] = mapping[idx].def_max;
769      }
770 }
771
772 static void
773 _elm_datetime_smart_add(Evas_Object *obj)
774 {
775    EVAS_SMART_DATA_ALLOC(obj, Elm_Datetime_Smart_Data);
776
777    ELM_WIDGET_CLASS(_elm_datetime_parent_sc)->base.add(obj);
778 }
779
780 static void
781 _elm_datetime_smart_del(Evas_Object *obj)
782 {
783    Datetime_Field *field;
784    unsigned int idx;
785
786    ELM_DATETIME_DATA_GET(obj, sd);
787
788    for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
789      {
790         field = sd->field_list + idx;
791         eina_stringshare_del(field->separator);
792      }
793
794    if ((dt_mod) && (dt_mod->obj_unhook))
795      dt_mod->obj_unhook(sd->mod_data);
796
797    ELM_WIDGET_CLASS(_elm_datetime_parent_sc)->base.del(obj);
798 }
799
800 static void
801 _elm_datetime_smart_set_user(Elm_Datetime_Smart_Class *sc)
802 {
803    ELM_WIDGET_CLASS(sc)->base.add = _elm_datetime_smart_add;
804    ELM_WIDGET_CLASS(sc)->base.del = _elm_datetime_smart_del;
805    ELM_WIDGET_CLASS(sc)->translate = _elm_datetime_smart_translate;
806    ELM_WIDGET_CLASS(sc)->focus_next = _elm_datetime_smart_focus_next;
807    ELM_WIDGET_CLASS(sc)->on_focus = _elm_datetime_smart_on_focus;
808    ELM_WIDGET_CLASS(sc)->theme = _elm_datetime_smart_theme;
809    ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_datetime_smart_sizing_eval;
810 }
811
812 EAPI const Elm_Datetime_Smart_Class *
813 elm_datetime_smart_class_get(void)
814 {
815    static Elm_Datetime_Smart_Class _sc =
816      ELM_DATETIME_SMART_CLASS_INIT_NAME_VERSION(ELM_DATETIME_SMART_NAME);
817    static const Elm_Datetime_Smart_Class *class = NULL;
818    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
819
820    if (class)
821      return class;
822
823    _elm_datetime_smart_set(&_sc);
824    esc->callbacks = _smart_callbacks;
825    class = &_sc;
826
827    return class;
828 }
829
830 EAPI Evas_Object *
831 elm_datetime_add(Evas_Object *parent)
832 {
833    Evas_Object *obj;
834    int idx;
835    Datetime_Field *field;
836
837    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
838
839    obj = elm_widget_add(_elm_datetime_smart_class_new(), parent);
840    if (!obj) return NULL;
841
842    if (!elm_widget_sub_object_add(parent, obj))
843      ERR("could not add %p as sub object of %p", obj, parent);
844
845    ELM_DATETIME_DATA_GET(obj, sd);
846
847    elm_layout_theme_set(obj, "datetime", "base", elm_widget_style_get(obj));
848
849    // module - initialise module for datetime
850    if (!dt_mod) dt_mod = _dt_mod_init();
851
852    if ((dt_mod) && (dt_mod->obj_hook))
853     sd->mod_data = dt_mod->obj_hook(obj);
854
855    // update module data
856    if (sd->mod_data)
857      {
858         sd->mod_data->base = obj;
859         sd->mod_data->field_format_get = _field_format_get;
860         sd->mod_data->field_location_get = _field_location_get;
861         sd->mod_data->field_limit_get = _field_limit_get;
862         sd->mod_data->fields_min_max_get = _fields_min_max_get;
863      }
864
865    _field_list_init(obj);
866    _reload_format(obj);
867
868    if ((dt_mod) && (dt_mod->create_fields))
869      dt_mod->create_fields(sd->mod_data);
870
871    if ((dt_mod) && (dt_mod->display_fields))
872      dt_mod->display_fields(sd->mod_data);
873
874    if ((dt_mod) && (dt_mod->access_register))
875      dt_mod->access_register(sd->mod_data);
876
877    elm_widget_can_focus_set(obj, EINA_TRUE);
878    elm_layout_sizing_eval(obj);
879
880    return obj;
881 }
882
883 EAPI const char *
884 elm_datetime_format_get(const Evas_Object *obj)
885 {
886    ELM_DATETIME_CHECK(obj) NULL;
887    ELM_DATETIME_DATA_GET(obj, sd);
888
889    return sd->format;
890 }
891
892 EAPI void
893 elm_datetime_format_set(Evas_Object *obj,
894                         const char *fmt)
895 {
896    ELM_DATETIME_CHECK(obj);
897    ELM_DATETIME_DATA_GET(obj, sd);
898
899    if (fmt)
900      {
901         strncpy(sd->format, fmt, ELM_DATETIME_MAX_FORMAT_LEN);
902         sd->format[ELM_DATETIME_MAX_FORMAT_LEN - 1] = '\0';
903         sd->user_format = EINA_TRUE;
904      }
905    else sd->user_format = EINA_FALSE;
906
907    _reload_format(obj);
908 }
909
910 EAPI Eina_Bool
911 elm_datetime_field_visible_get(const Evas_Object *obj,
912                                Elm_Datetime_Field_Type fieldtype)
913 {
914    Datetime_Field *field;
915    ELM_DATETIME_CHECK(obj) EINA_FALSE;
916    ELM_DATETIME_DATA_GET(obj, sd);
917
918    if (fieldtype > ELM_DATETIME_AMPM) return EINA_FALSE;
919
920    field = sd->field_list + fieldtype;
921
922    return field->visible;
923 }
924
925 EAPI void
926 elm_datetime_field_visible_set(Evas_Object *obj,
927                                Elm_Datetime_Field_Type fieldtype,
928                                Eina_Bool visible)
929 {
930    Datetime_Field *field;
931
932    ELM_DATETIME_CHECK(obj);
933    ELM_DATETIME_DATA_GET(obj, sd);
934
935    if (fieldtype > ELM_DATETIME_AMPM) return;
936
937    field = sd->field_list + fieldtype;
938    if (field->visible == visible) return;
939
940    field->visible = visible;
941    _reload_format(obj);
942 }
943
944 EAPI void
945 elm_datetime_field_limit_get(const Evas_Object *obj,
946                              Elm_Datetime_Field_Type fieldtype,
947                              int *min,
948                              int *max)
949 {
950    Datetime_Field *field;
951
952    ELM_DATETIME_CHECK(obj);
953    ELM_DATETIME_DATA_GET(obj, sd);
954
955    if (fieldtype >= ELM_DATETIME_AMPM) return;
956
957    field = sd->field_list + fieldtype;
958    if (min) *min = field->min;
959    if (max) *max = field->max;
960 }
961
962 EAPI void
963 elm_datetime_field_limit_set(Evas_Object *obj,
964                              Elm_Datetime_Field_Type fieldtype,
965                              int min,
966                              int max)
967 {
968    Datetime_Field *field;
969
970    ELM_DATETIME_CHECK(obj);
971    ELM_DATETIME_DATA_GET(obj, sd);
972
973    if (fieldtype >= ELM_DATETIME_AMPM) return;
974
975    if (min > max) return;
976
977    field = sd->field_list + fieldtype;
978    if (((min >= mapping[fieldtype].def_min) && 
979         (min <= mapping[fieldtype].def_max)) ||
980        (field->type == ELM_DATETIME_YEAR))
981      field->min = min;
982    if (((max >= mapping[fieldtype].def_min) && 
983         (max <= mapping[fieldtype].def_max)) ||
984        (field->type == ELM_DATETIME_YEAR))
985      field->max = max;
986
987    _apply_field_limits(obj);
988 }
989
990 EAPI Eina_Bool
991 elm_datetime_value_get(const Evas_Object *obj,
992                        struct tm *currtime)
993 {
994    ELM_DATETIME_CHECK(obj) EINA_FALSE;
995    EINA_SAFETY_ON_NULL_RETURN_VAL(currtime, EINA_FALSE);
996    ELM_DATETIME_DATA_GET(obj, sd);
997
998    *currtime = sd->curr_time;
999    return EINA_TRUE;
1000 }
1001
1002 EAPI Eina_Bool
1003 elm_datetime_value_set(Evas_Object *obj,
1004                        const struct tm *newtime)
1005 {
1006    struct tm old_time;
1007
1008    ELM_DATETIME_CHECK(obj) EINA_FALSE;
1009    EINA_SAFETY_ON_NULL_RETURN_VAL(newtime, EINA_FALSE);
1010    ELM_DATETIME_DATA_GET(obj, sd);
1011
1012    old_time = sd->curr_time;
1013    sd->curr_time = *newtime;
1014    // apply default field restrictions for curr_time
1015    _apply_range_restrictions(&sd->curr_time);
1016    // validate the curr_time according to the min_limt and max_limt
1017    _validate_datetime_limits(&sd->curr_time, &sd->min_limit, EINA_FALSE);
1018    _validate_datetime_limits(&sd->max_limit, &sd->curr_time, EINA_TRUE);
1019    _apply_field_limits(obj);
1020
1021    if (!_date_cmp(&old_time, &sd->curr_time))
1022      evas_object_smart_callback_call(obj, SIG_CHANGED, NULL);
1023
1024    return EINA_TRUE;
1025 }
1026
1027 EAPI Eina_Bool
1028 elm_datetime_value_min_get(const Evas_Object *obj,
1029                            struct tm *mintime)
1030 {
1031    ELM_DATETIME_CHECK(obj) EINA_FALSE;
1032    EINA_SAFETY_ON_NULL_RETURN_VAL(mintime, EINA_FALSE);
1033    ELM_DATETIME_DATA_GET(obj, sd);
1034
1035    *mintime = sd->min_limit;
1036    return EINA_TRUE;
1037 }
1038
1039 EAPI Eina_Bool
1040 elm_datetime_value_min_set(Evas_Object *obj,
1041                            const struct tm *mintime)
1042 {
1043    struct tm old_time;
1044
1045    ELM_DATETIME_CHECK(obj) EINA_FALSE;
1046    EINA_SAFETY_ON_NULL_RETURN_VAL(mintime, EINA_FALSE);
1047    ELM_DATETIME_DATA_GET(obj, sd);
1048
1049    sd->min_limit = *mintime;
1050    old_time = sd->curr_time;
1051    // apply default field restrictions for min_limit
1052    _apply_range_restrictions(&sd->min_limit);
1053    // validate curr_time and max_limt according to the min_limit
1054    _validate_datetime_limits(&sd->max_limit, &sd->min_limit, EINA_FALSE);
1055    _validate_datetime_limits(&sd->curr_time, &sd->min_limit, EINA_FALSE);
1056    _apply_field_limits(obj);
1057
1058    if (!_date_cmp(&old_time, &sd->curr_time))
1059      evas_object_smart_callback_call(obj, SIG_CHANGED, NULL);
1060
1061    return EINA_TRUE;
1062 }
1063
1064 EAPI Eina_Bool
1065 elm_datetime_value_max_get(const Evas_Object *obj,
1066                            struct tm *maxtime)
1067 {
1068    ELM_DATETIME_CHECK(obj) EINA_FALSE;
1069    EINA_SAFETY_ON_NULL_RETURN_VAL(maxtime, EINA_FALSE);
1070    ELM_DATETIME_DATA_GET(obj, sd);
1071
1072    *maxtime = sd->max_limit;
1073    return EINA_TRUE;
1074 }
1075
1076 EAPI Eina_Bool
1077 elm_datetime_value_max_set(Evas_Object *obj,
1078                            const struct tm *maxtime)
1079 {
1080    struct tm old_time;
1081
1082    ELM_DATETIME_CHECK(obj) EINA_FALSE;
1083    EINA_SAFETY_ON_NULL_RETURN_VAL(maxtime, EINA_FALSE);
1084    ELM_DATETIME_DATA_GET(obj, sd);
1085
1086    sd->max_limit = *maxtime;
1087    old_time = sd->curr_time;
1088    // apply default field restrictions for max_limit
1089    _apply_range_restrictions(&sd->max_limit);
1090    // validate curr_time and min_limt according to the max_limit
1091    _validate_datetime_limits(&sd->max_limit, &sd->min_limit, EINA_TRUE);
1092    _validate_datetime_limits(&sd->max_limit, &sd->curr_time, EINA_TRUE);
1093    _apply_field_limits(obj);
1094
1095    if (!_date_cmp(&old_time, &sd->curr_time))
1096      evas_object_smart_callback_call(obj, SIG_CHANGED, NULL);
1097
1098    return EINA_TRUE;
1099 }