[NUI] Change date/time picker param to formal C# DateTime class instead of int value
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / DatePicker.cs
1 /* Copyright (c) 2021 Samsung Electronics Co., Ltd.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  *
15  */
16 using System;
17 using Tizen.NUI;
18 using Tizen.NUI.BaseComponents;
19 using System.Collections.Generic;
20 using System.Collections.ObjectModel;
21 using System.ComponentModel;
22 using System.Globalization;
23 using System.Diagnostics.CodeAnalysis;
24
25 namespace Tizen.NUI.Components
26 {
27     /// <summary>
28     /// DateChangedEventArgs is a class to notify changed DatePicker value argument which will sent to user.
29     /// </summary>
30     [EditorBrowsable(EditorBrowsableState.Never)]
31     public class DateChangedEventArgs : EventArgs
32     {
33         /// <summary>
34         /// DateChangedEventArgs default constructor.
35         /// <param name="date">date value of DatePicker.</param>
36         /// </summary>
37         [EditorBrowsable(EditorBrowsableState.Never)]   
38         public DateChangedEventArgs(DateTime date)
39         {
40             Date = date;
41         }
42
43         /// <summary>
44         /// DateChangedEventArgs default constructor.
45         /// <returns>The current date value of DatePicker.</returns>
46         /// </summary>
47         [EditorBrowsable(EditorBrowsableState.Never)]   
48         public DateTime Date { get; }
49     }
50
51     /// <summary>
52     /// DatePicker is a class which provides a function that allows the user to select 
53     /// a date through a scrolling motion by expressing the specified value as a list.
54     /// DatePicker expresses the current date using the locale information of the system.
55     /// Year range is 1970~2038 (glibc time_t struct min, max value)
56     /// </summary>
57     [EditorBrowsable(EditorBrowsableState.Never)]
58     public class DatePicker : Control
59     {
60         private DateTime currentDate;
61         private Picker dayPicker;
62         private Picker monthPicker;
63         private Picker yearPicker;
64         private DatePickerStyle datePickerStyle => ViewStyle as DatePickerStyle;
65         
66         /// <summary>
67         /// Creates a new instance of DatePicker.
68         /// </summary>
69         [EditorBrowsable(EditorBrowsableState.Never)]
70         public DatePicker()
71         {
72             Initialize();
73         }
74         
75         /// <summary>
76         /// Creates a new instance of DatePicker.
77         /// </summary>
78         /// <param name="style">Creates DatePicker by special style defined in UX.</param>
79         [EditorBrowsable(EditorBrowsableState.Never)]
80         public DatePicker(string style) : base(style)
81         {
82             Initialize();
83         }
84
85         /// <summary>
86         /// Creates a new instance of DatePicker.
87         /// </summary>
88         /// <param name="datePickerStyle">Creates DatePicker by style customized by user.</param>
89         [EditorBrowsable(EditorBrowsableState.Never)]
90         public DatePicker(DatePickerStyle datePickerStyle) : base(datePickerStyle)
91         {
92             Initialize();
93         }
94
95
96         /// <summary>
97         /// Dispose DatePicker and all children on it.
98         /// </summary>
99         /// <param name="type">Dispose type.</param>
100         [EditorBrowsable(EditorBrowsableState.Never)]
101         protected override void Dispose(DisposeTypes type)
102         {
103             if (disposed)
104             {
105                 return;
106             }
107
108             if (type == DisposeTypes.Explicit)
109             {
110                 Remove(monthPicker);
111                 Utility.Dispose(monthPicker);
112                 monthPicker = null;
113                 Remove(dayPicker);
114                 Utility.Dispose(dayPicker);
115                 dayPicker = null;
116                 Remove(yearPicker);
117                 Utility.Dispose(yearPicker);
118                 yearPicker = null;
119             }
120
121             base.Dispose(type);
122         }
123
124         /// <summary>
125         /// An event emitted when DatePicker value changed, user can subscribe or unsubscribe to this event handler.
126         /// </summary>
127         [EditorBrowsable(EditorBrowsableState.Never)]
128         public event EventHandler<DateChangedEventArgs> DateChanged;
129         
130         /// <summary>
131         /// The Date value of DatePicker.
132         /// </summary>
133         [EditorBrowsable(EditorBrowsableState.Never)]
134         public DateTime Date
135         {
136             get
137             {
138                 return currentDate;
139             }
140             set
141             {
142                 currentDate = value;
143                 dayPicker.CurrentValue = currentDate.Day;
144                 monthPicker.CurrentValue = currentDate.Month;
145                 yearPicker.CurrentValue = currentDate.Year;
146             }
147         }
148
149         /// <summary>
150         /// Initialize TimePicker object.
151         /// </summary>
152         [EditorBrowsable(EditorBrowsableState.Never)]
153         public override void OnInitialize()
154         {
155             base.OnInitialize();
156             SetAccessibilityConstructor(Role.DateEditor, AccessibilityInterface.Value);
157
158             dayPicker = new Picker()
159             {
160                 MinValue = 1,
161                 MaxValue = 31,
162             };
163             dayPicker.ValueChanged += OnDayValueChanged;
164
165             monthPicker = new Picker()
166             {
167                 MinValue = 1,
168                 MaxValue = 12,
169             };
170             monthPicker.ValueChanged += OnMonthValueChanged;
171
172             yearPicker = new Picker()
173             {
174                 MinValue = 1970,
175                 MaxValue = 2100,
176             };
177             yearPicker.ValueChanged += OnYearValueChanged;
178
179             currentDate = DateTime.Now;
180             dayPicker.CurrentValue = currentDate.Day;
181             monthPicker.CurrentValue = currentDate.Month;
182             yearPicker.CurrentValue = currentDate.Year;
183         }
184     
185         [SuppressMessage("Microsoft.Reliability",
186                          "CA2000:DisposeObjectsBeforeLosingScope",
187                          Justification = "The CellPadding will be dispose when the date picker disposed")]
188         private void Initialize()
189         {
190             AccessibilityHighlightable = true;
191             HeightSpecification = LayoutParamPolicies.MatchParent;
192
193             Layout = new LinearLayout() { 
194                 LinearOrientation = LinearLayout.Orientation.Horizontal,
195                 CellPadding = new Size(datePickerStyle.CellPadding.Width, datePickerStyle.CellPadding.Height),
196             };
197
198             PickersOrderSet();
199             SetMonthText();
200             MaxDaySet(currentDate.Month);
201         }
202
203         private void OnDayValueChanged(object sender, ValueChangedEventArgs e)
204         {
205             if (currentDate.Day == e.Value) return;
206
207             currentDate = new DateTime(currentDate.Year, currentDate.Month, e.Value);
208             
209             OnDateChanged();
210         }
211
212         private void OnMonthValueChanged(object sender, ValueChangedEventArgs e)
213         { 
214             if (currentDate.Month == e.Value) return;
215
216             MaxDaySet(e.Value);
217
218             OnDateChanged();
219         }
220
221         private void OnYearValueChanged(object sender, ValueChangedEventArgs e)
222         { 
223             if (currentDate.Year == e.Value) return;
224
225             currentDate = new DateTime(e.Value, currentDate.Month, currentDate.Day);
226
227             OnDateChanged();
228         }
229
230         private void OnDateChanged()
231         { 
232             DateChangedEventArgs eventArgs = new DateChangedEventArgs(currentDate);
233             DateChanged?.Invoke(this, eventArgs);
234         }
235
236         private void MaxDaySet(int month)
237         {
238             int maxDaysInMonth = DateTime.DaysInMonth(currentDate.Year, month);
239             dayPicker.MaxValue = maxDaysInMonth;
240             if (currentDate.Day > maxDaysInMonth)
241             {
242                 currentDate = new DateTime(currentDate.Year, month, maxDaysInMonth);
243                 dayPicker.CurrentValue = maxDaysInMonth;
244                 return;
245             }
246             currentDate = new DateTime(currentDate.Year, month, currentDate.Day);
247         }
248
249         //FIXME: There is no way to know when system locale changed in NUI.
250         //       Pickers order and Month text has to be follow system locale.
251         private void PickersOrderSet()
252         {           
253             String locale = Environment.GetEnvironmentVariable("LC_TIME");
254             DateTimeFormatInfo DateFormat = new CultureInfo(locale, false ).DateTimeFormat;
255             String temp = DateFormat.ShortDatePattern;
256             String[] strArray = temp.Split(' ', '/');
257             foreach (String format in strArray) {
258                 if (format.IndexOf("M") != -1|| format.IndexOf("m") != -1)  Add(monthPicker);
259                 else if (format.IndexOf("d") != -1 || format.IndexOf("D") != -1) Add(dayPicker);
260                 else if (format.IndexOf("y") != -1 || format.IndexOf("Y") != -1) Add(yearPicker);
261             }
262         }
263
264         private void SetMonthText()
265         {
266             String locale = Environment.GetEnvironmentVariable("LC_TIME");
267             CultureInfo info = new CultureInfo(locale);
268             monthPicker.DisplayedValues = new ReadOnlyCollection<string>(info.DateTimeFormat.AbbreviatedMonthNames);
269         }
270     }
271 }