New test.
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / Calendar.cs
1 //
2 // System.Web.UI.WebControls.Calendar.cs
3 //
4 // Authors:
5 //    Jordi Mas i Hernandez (jordi@ximian.com)
6 //
7 // (C) 2005 Novell, Inc (http://www.novell.com)
8 //
9 //
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //
31
32 using System.Globalization;
33 using System.Collections;
34 using System.ComponentModel;
35 using System.Drawing;
36 using System.Security.Permissions;
37 using System.Threading;
38
39 namespace System.Web.UI.WebControls {
40         // CAS
41         [AspNetHostingPermissionAttribute (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
42         [AspNetHostingPermissionAttribute (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
43         // attributes
44         [DataBindingHandler("System.Web.UI.Design.WebControls.CalendarDataBindingHandler, " + Consts.AssemblySystem_Design)]
45         [DefaultEvent("SelectionChanged")]
46         [DefaultProperty("SelectedDate")]
47         [Designer("System.Web.UI.Design.WebControls.CalendarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
48 #if NET_2_0
49         [ControlValueProperty ("SelectedDate", "1/1/0001 12:00:00 AM")]
50         [SupportsEventValidation]
51 #endif          
52         public class Calendar : WebControl, IPostBackEventHandler {
53
54                 private TableItemStyle dayHeaderStyle;
55                 private TableItemStyle dayStyle;
56                 private TableItemStyle nextPrevStyle;
57                 private TableItemStyle otherMonthDayStyle;
58                 private TableItemStyle selectedDayStyle;
59                 private TableItemStyle titleStyle;
60                 private TableItemStyle todayDayStyle;
61                 private TableItemStyle selectorStyle;
62                 private TableItemStyle weekendDayStyle;
63                 private DateTimeFormatInfo dateInfo;
64                 private SelectedDatesCollection selectedDatesCollection;
65                 private ArrayList dateList;
66                 private static DateTime dateZenith  = new DateTime (2000, 1,1);
67                 private const int daysInAWeek = 7;
68                 private static readonly object DayRenderEvent = new object ();
69                 private static readonly object SelectionChangedEvent = new object ();
70                 private static readonly object VisibleMonthChangedEvent = new object ();
71
72                 public Calendar ()
73                 {
74                         dateInfo = Thread.CurrentThread.CurrentUICulture.DateTimeFormat;
75                 }
76
77 #if NET_2_0
78                 [Localizable (true)]
79                 [DefaultValue ("")]
80                 [WebSysDescription ("")]
81                 [WebCategoryAttribute ("Appearance")]
82                 public virtual string Caption 
83                 {
84                         get {
85                                 return ViewState.GetString ("Caption", "");
86                         }
87                         set {
88                                 ViewState["Caption"] = value;
89                         }
90                 }
91
92                 [DefaultValue (TableCaptionAlign.NotSet)]
93                 [WebSysDescription ("")]
94                 [WebCategoryAttribute ("Accessibility")]
95                 public virtual TableCaptionAlign CaptionAlign 
96                 {
97                         get {
98                                 return (TableCaptionAlign)ViewState.GetInt ("CaptionAlign", (int)TableCaptionAlign.NotSet);
99                         }
100                         set {
101                                 ViewState ["CaptionAlign"] = value;
102                         }
103                 }
104 #endif
105
106 #if ONLY_1_1
107                 [Bindable(true)]
108 #endif          
109                 [DefaultValue(2)]
110                 [WebSysDescription ("")]
111                 [WebCategory ("Layout")]
112                 public int CellPadding {
113                         get {
114                                 return ViewState.GetInt ("CellPadding", 2);
115                         }
116
117                         set {
118                                 if (value < -1)
119                                         throw new ArgumentOutOfRangeException ("The specified cell padding is less than -1.");
120
121                                 ViewState ["CellPadding"] = value;
122                         }
123                 }
124
125 #if ONLY_1_1
126                 [Bindable(true)]
127 #endif          
128                 [DefaultValue(0)]
129                 [WebSysDescription ("")]
130                 [WebCategory ("Layout")]
131                 public int CellSpacing {
132                         get {
133                                 return ViewState.GetInt ("CellSpacing", 0);
134                         }
135
136                         set {
137                                 if (value < -1)
138                                         throw new ArgumentOutOfRangeException ("The specified cell spacing is less than -1");
139
140                                 ViewState ["CellSpacing"] = value;
141                         }
142                 }
143
144                 [PersistenceMode(PersistenceMode.InnerProperty)]
145                 [NotifyParentProperty(true)]
146                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
147                 [WebSysDescription ("")]
148                 [WebCategory ("Style")]
149                 public TableItemStyle DayHeaderStyle {
150                         get {
151                                 if (dayHeaderStyle == null) {
152                                         dayHeaderStyle = new TableItemStyle ();
153                                         if (IsTrackingViewState)
154                                                 dayHeaderStyle.TrackViewState ();
155                                 }
156
157                                 return dayHeaderStyle;
158                         }
159                 }
160
161 #if ONLY_1_1
162                 [Bindable(true)]
163 #endif          
164                 [DefaultValue(DayNameFormat.Short)]
165                 [WebSysDescription ("")]
166                 [WebCategory ("Appearance")]
167                 public DayNameFormat DayNameFormat {
168                         get {
169                                 return (DayNameFormat) ViewState.GetInt ("DayNameFormat", (int) DayNameFormat.Short);
170                         }
171
172                         set {
173                                 if (value != DayNameFormat.FirstLetter && value != DayNameFormat.FirstTwoLetters &&
174                                         value != DayNameFormat.Full && value != DayNameFormat.Short) {
175                                         throw new ArgumentOutOfRangeException ("The specified day name format is not one of the DayNameFormat values.");
176                                 }
177
178                                 ViewState ["DayNameFormat"] = value;
179                         }
180                 }
181
182                 [DefaultValue(null)]
183                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
184                 [NotifyParentProperty(true)]
185                 [PersistenceMode(PersistenceMode.InnerProperty)]
186                 [WebSysDescription ("")]
187                 [WebCategory ("Style")]
188                 public TableItemStyle DayStyle {
189                         get {
190                                 if (dayStyle == null) {
191                                         dayStyle = new TableItemStyle ();
192                                         if (IsTrackingViewState)
193                                                 dayStyle.TrackViewState ();
194                                 }
195
196                                 return dayStyle;
197                         }
198                 }
199
200 #if ONLY_1_1
201                 [Bindable(true)]
202 #endif          
203                 [DefaultValue(FirstDayOfWeek.Default)]
204                 [WebSysDescription ("")]
205                 [WebCategory ("Appearance")]
206                 public FirstDayOfWeek FirstDayOfWeek {
207                         get {
208                                 return (FirstDayOfWeek) ViewState.GetInt ("FirstDayOfWeek", (int) FirstDayOfWeek.Default);
209                         }
210
211                         set {
212                                 if (value < FirstDayOfWeek.Sunday || value > FirstDayOfWeek.Default) {
213                                         throw new ArgumentOutOfRangeException ("The specified day name format is not one of the DayNameFormat values.");
214                                 }
215
216                                 ViewState ["FirstDayOfWeek"] = value;
217                         }
218                 }
219
220 #if ONLY_1_1
221                 [Bindable(true)]
222 #endif          
223                 [DefaultValue("&gt;")]
224 #if NET_2_0
225                 [Localizable (true)]
226 #endif
227                 [WebSysDescription ("")]
228                 [WebCategory ("Appearance")]
229                 public string NextMonthText {
230                         get {
231                                 return ViewState.GetString ("NextMonthText", "&gt;");
232                         }
233
234                         set {
235                                 ViewState ["NextMonthText"] = value;
236                         }
237                 }
238
239 #if ONLY_1_1
240                 [Bindable(true)]
241 #endif          
242                 [DefaultValue(NextPrevFormat.CustomText)]
243                 [WebSysDescription ("")]
244                 [WebCategory ("Appearance")]
245                 public NextPrevFormat NextPrevFormat {
246                         get {
247                                 return (NextPrevFormat) ViewState.GetInt ("NextPrevFormat", (int) NextPrevFormat.CustomText);
248                         }
249
250                         set {
251                                 if (value != NextPrevFormat.CustomText && value != NextPrevFormat.ShortMonth && value != NextPrevFormat.FullMonth) {
252                                         throw new ArgumentOutOfRangeException ("The specified day name format is not one of the DayNameFormat values.");
253                                 }
254
255                                 ViewState ["NextPrevFormat"] = value;
256                         }
257                 }
258
259                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
260                 [NotifyParentProperty(true)]
261                 [PersistenceMode(PersistenceMode.InnerProperty)]
262                 [WebSysDescription ("")]
263                 [WebCategory ("Style")]
264                 public TableItemStyle NextPrevStyle {
265                         get {
266                                 if (nextPrevStyle == null) {
267                                         nextPrevStyle = new TableItemStyle ();
268                                         if (IsTrackingViewState)
269                                                 nextPrevStyle.TrackViewState ();
270                                 }
271
272                                 return nextPrevStyle;
273                         }
274                 }
275
276                 [DefaultValue(null)]
277                 [NotifyParentProperty(true)]
278                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
279                 [PersistenceMode(PersistenceMode.InnerProperty)]
280                 [WebSysDescription ("")]
281                 [WebCategory ("Style")]
282                 public TableItemStyle OtherMonthDayStyle {
283                         get {
284                                 if (otherMonthDayStyle == null) {
285                                         otherMonthDayStyle = new TableItemStyle ();
286                                         if (IsTrackingViewState)
287                                                 otherMonthDayStyle.TrackViewState ();
288                                 }
289
290                                 return otherMonthDayStyle;
291                         }
292                 }
293
294 #if ONLY_1_1
295                 [Bindable(true)]
296 #endif          
297                 [DefaultValue("&lt;")]
298 #if NET_2_0
299                 [Localizable (true)]
300 #endif
301                 [WebSysDescription ("")]
302                 [WebCategory ("Appearance")]
303                 public string PrevMonthText {
304                         get {
305                                 return ViewState.GetString ("PrevMonthText", "&lt;");
306                         }
307
308                         set {
309                                 ViewState ["PrevMonthText"] = value;
310                         }
311                 }
312
313 #if NET_2_0
314                 [Bindable(true, BindingDirection.TwoWay)]
315 #else
316                 [Bindable(true)]
317 #endif          
318                 [DefaultValue("1/1/0001 12:00:00 AM")]
319                 [WebSysDescription ("")]
320                 [WebCategory ("Appearance")]
321                 public DateTime SelectedDate {
322                         get {
323                                 if (SelectedDates.Count > 0)
324                                         return SelectedDates [0];
325
326                                 return DateTime.MinValue;
327                         }
328
329                         set {
330                                 SelectedDates.SelectRange (value, value);
331                         }
332                 }
333
334                 [Browsable(false)]
335                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
336                 [WebSysDescription ("")]
337                 [WebCategory ("Appearance")]
338                 public SelectedDatesCollection SelectedDates {
339                         get {
340                                 if (dateList == null)
341                                         dateList = new ArrayList ();
342
343                                 if (selectedDatesCollection == null)
344                                         selectedDatesCollection = new SelectedDatesCollection (dateList);
345
346                                 return selectedDatesCollection;
347                         }
348                 }
349
350                 [DefaultValue(null)]
351                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
352                 [NotifyParentProperty(true)]
353                 [PersistenceMode(PersistenceMode.InnerProperty)]
354                 [WebSysDescription ("")]
355                 [WebCategory ("Style")]
356                 public TableItemStyle SelectedDayStyle {
357                         get {
358                                 if (selectedDayStyle == null) {
359                                         selectedDayStyle = new TableItemStyle ();
360                                         if (IsTrackingViewState)
361                                                 selectedDayStyle.TrackViewState ();
362                                 }
363
364                                 return selectedDayStyle;
365                         }
366                 }
367
368 #if ONLY_1_1
369                 [Bindable(true)]
370 #endif          
371                 [DefaultValue(CalendarSelectionMode.Day)]
372                 [WebSysDescription ("")]
373                 [WebCategory ("Behavior")]
374                 public CalendarSelectionMode SelectionMode {
375                         get {
376                                 return (CalendarSelectionMode) ViewState.GetInt ("SelectionMode", (int) CalendarSelectionMode.Day);
377                         }
378
379                         set {
380                                 if (value != CalendarSelectionMode.Day  && value != CalendarSelectionMode.DayWeek &&
381                                         value != CalendarSelectionMode.DayWeekMonth  && value != CalendarSelectionMode.None) {
382                                         throw new ArgumentOutOfRangeException ("The specified selection mode is not one of the CalendarSelectionMode values.");
383                                 }
384                                 ViewState ["SelectionMode"] = value;
385                         }
386                 }
387
388 #if ONLY_1_1
389                 [Bindable(true)]
390 #endif          
391                 [DefaultValue("&gt;&gt;")]
392 #if NET_2_0
393                 [Localizable (true)]
394 #endif
395                 [WebSysDescription ("")]
396                 [WebCategory ("Appearance")]
397                 public string SelectMonthText {
398                         get {
399                                 return ViewState.GetString ("SelectMonthText", "&gt;&gt;");
400                         }
401
402                         set {
403                                 ViewState ["SelectMonthText"] = value;
404                         }
405                 }
406
407                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
408                 [NotifyParentProperty(true)]
409                 [PersistenceMode(PersistenceMode.InnerProperty)]
410                 [WebSysDescription ("")]
411                 [WebCategory ("Style")]
412                 public TableItemStyle SelectorStyle {
413                         get {
414                                 if (selectorStyle == null) {
415                                          selectorStyle = new TableItemStyle ();
416                                         if (IsTrackingViewState)
417                                                 selectorStyle.TrackViewState ();
418                                 }
419
420                                 return selectorStyle;
421                         }
422                 }
423
424 #if ONLY_1_1
425                 [Bindable(true)]
426 #endif          
427                 [DefaultValue("&gt;")]
428 #if NET_2_0             
429                 [Localizable (true)]
430 #endif          
431                 [WebSysDescription ("")]
432                 [WebCategory ("Appearance")]
433                 public string SelectWeekText {
434                         get {
435                                 return ViewState.GetString ("SelectWeekText", "&gt;");
436                         }
437
438                         set {
439                                 ViewState ["SelectWeekText"] = value;
440                         }
441                 }
442
443 #if ONLY_1_1
444                 [Bindable(true)]
445 #endif          
446                 [DefaultValue(true)]
447                 [WebSysDescription ("")]
448                 [WebCategory ("Appearance")]
449                 public bool ShowDayHeader {
450                         get {
451                                 return ViewState.GetBool ("ShowDayHeader", true);
452                         }
453
454                         set {
455                                 ViewState ["ShowDayHeader"] = value;
456                         }
457                 }
458
459 #if ONLY_1_1
460                 [Bindable(true)]
461 #endif          
462                 [DefaultValue(false)]
463                 [WebSysDescription ("")]
464                 [WebCategory ("Appearance")]
465                 public bool ShowGridLines {
466                         get {
467                                 return ViewState.GetBool ("ShowGridLines", false);
468                         }
469
470                         set {
471                                 ViewState ["ShowGridLines"] = value;
472                         }
473                 }
474
475 #if ONLY_1_1
476                 [Bindable(true)]
477 #endif          
478                 [DefaultValue(true)]
479                 [WebSysDescription ("")]
480                 [WebCategory ("Appearance")]
481                 public bool ShowNextPrevMonth {
482                         get {
483                                 return ViewState.GetBool ("ShowNextPrevMonth", true);
484                         }
485
486                         set {
487                                 ViewState ["ShowNextPrevMonth"] = value;
488                         }
489                 }
490
491 #if ONLY_1_1
492                 [Bindable(true)]
493 #endif          
494                 [DefaultValue(true)]
495                 [WebSysDescription ("")]
496                 [WebCategory ("Appearance")]
497                 public bool ShowTitle {
498                         get {
499                                 return ViewState.GetBool ("ShowTitle", true);
500                         }
501
502                         set {
503                                 ViewState ["ShowTitle"] = value;
504                         }
505                 }
506
507 #if ONLY_1_1
508                 [Bindable(true)]
509 #endif          
510                 [DefaultValue(TitleFormat.MonthYear)]
511                 [WebSysDescription ("")]
512                 [WebCategory ("Appearance")]
513                 public TitleFormat TitleFormat {
514                         get {
515                                 return (TitleFormat) ViewState.GetInt ("TitleFormat", (int) TitleFormat.MonthYear);
516                         }
517
518                         set {
519                                 if (value != TitleFormat.Month && value != TitleFormat.MonthYear) {
520                                         throw new ArgumentOutOfRangeException ("The specified title format is not one of the TitleFormat values.");
521                                 }
522
523                                 ViewState ["TitleFormat"] = value;
524                         }
525                 }
526
527                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
528                 [NotifyParentProperty(true)]
529                 [PersistenceMode(PersistenceMode.InnerProperty)]
530                 [WebSysDescription ("")]
531                 [WebCategory ("Style")]
532                 public TableItemStyle TitleStyle {
533                         get {
534                                 if (titleStyle == null) {
535                                         titleStyle = new TableItemStyle ();
536                                         if (IsTrackingViewState)
537                                                 titleStyle.TrackViewState ();
538                                 }
539
540                                 return titleStyle;
541                         }
542                 }
543
544                 [DefaultValue(null)]
545                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
546                 [NotifyParentProperty(true)]
547                 [PersistenceMode(PersistenceMode.InnerProperty)]
548                 [WebSysDescription ("")]
549                 [WebCategory ("Style")]
550                 public TableItemStyle TodayDayStyle {
551                         get {
552                                 if (todayDayStyle == null) {
553                                         todayDayStyle = new TableItemStyle ();
554                                         if (IsTrackingViewState)
555                                                 todayDayStyle.TrackViewState ();
556                                 }
557
558                                 return todayDayStyle;
559                         }
560                 }
561
562 #if ONLY_1_1
563                 [Bindable(true)]
564 #endif          
565                 [Browsable(false)]
566                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
567                 [WebSysDescription ("")]
568                 [WebCategory ("Style")]
569                 public DateTime TodaysDate {
570                         get {
571                                 object obj = ViewState ["TodaysDate"];
572
573                                 if (obj != null)
574                                         return (DateTime) obj;
575
576                                 return DateTime.Today;
577                         }
578
579                         set {
580                                 ViewState ["TodaysDate"] = value.Date;
581                         }
582                 }
583
584 #if NET_2_0
585                 [DefaultValue (true)]
586                 [WebSysDescription ("")]
587                 [WebCategoryAttribute ("Accessibility")]
588                 public virtual bool UseAccessibleHeader 
589                 {
590                         get {
591                                 return ViewState.GetBool ("UseAccessibleHeader", true);
592                         }
593                         set {
594                                 ViewState ["UseAccessibleHeader"] = value;
595                         }
596                 }
597 #endif          
598
599                 [Bindable(true)]
600                 [DefaultValue("1/1/0001 12:00:00 AM")]
601                 [WebSysDescription ("")]
602                 [WebCategory ("Style")]
603                 public DateTime VisibleDate {
604                         get {
605                                 object obj = ViewState ["VisibleDate"];
606
607                                 if (obj != null)
608                                         return (DateTime) obj;
609
610                                 return DateTime.MinValue;
611                         }
612
613                         set {
614                                 ViewState ["VisibleDate"] = value.Date;
615                         }
616                 }
617
618                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
619                 [NotifyParentProperty(true)]
620                 [PersistenceMode(PersistenceMode.InnerProperty)]
621                 [WebSysDescription ("")]
622                 [WebCategory ("Style")]
623                 public TableItemStyle WeekendDayStyle {
624                         get {
625                                 if (weekendDayStyle == null) {
626                                         weekendDayStyle = new TableItemStyle ();
627                                         if (IsTrackingViewState)
628                                                 weekendDayStyle.TrackViewState ();
629                                 }
630
631                                 return weekendDayStyle;
632                         }
633                 }
634
635
636                 // Private properties
637                 private DateTime DisplayDate {
638                         get {
639                                 DateTime dateTime = VisibleDate;
640                                 if (dateTime == DateTime.MinValue) // If visibledate is still the default value
641                                         dateTime = TodaysDate;
642
643                                 return dateTime;
644                         }
645                 }
646
647                 private DayOfWeek DisplayFirstDayOfWeek {
648                         get {
649                                 if (FirstDayOfWeek != FirstDayOfWeek.Default)
650                                         return (DayOfWeek)  FirstDayOfWeek;
651
652                                 return (DayOfWeek) dateInfo.FirstDayOfWeek;
653                         }
654                 }
655
656                 protected override ControlCollection CreateControlCollection ()
657                 {
658                         return base.CreateControlCollection ();
659                 }
660
661                 protected bool HasWeekSelectors (CalendarSelectionMode selectionMode)
662                 {
663                         if (selectionMode == CalendarSelectionMode.DayWeek || selectionMode == CalendarSelectionMode.DayWeekMonth)
664                                 return true;
665
666                         return false;
667                 }
668                 
669 #if NET_2_0
670                 void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
671                 {
672                         RaisePostBackEvent (eventArgument);
673                 }
674
675                 protected virtual void RaisePostBackEvent (string arg)
676 #else
677                 void IPostBackEventHandler.RaisePostBackEvent (string arg)
678 #endif
679                 {
680                         if (arg.Length < 1)
681                                 return;
682
683                         if (arg[0] == 'V') { // Goes to Next or Previous month
684                                 DateTime prev = VisibleDate;
685                                 int days = Int32.Parse (arg.Substring (1));
686                                 DateTime dt = GetGlobalCalendar().AddDays (dateZenith, days);
687                                 VisibleDate = dt;
688                                 OnVisibleMonthChanged (VisibleDate, prev);
689                                 return;
690                         }
691
692                         if (arg[0] == 'R') { // Selects a range of dates
693                                 string num, date, days;
694                                 num = arg.Substring (1);
695                                 days = num.Substring (num.Length - 2, 2);
696                                 date = num.Substring (0, num.Length - 2);
697                                 DateTime d = GetGlobalCalendar().AddDays (dateZenith, Int32.Parse (date));
698                                 SelectedDates.SelectRange (d, d.AddDays (Int32.Parse (days)));
699                                 OnSelectionChanged ();
700                                 return;
701                         }
702
703                         // Selects a single day
704                         int daysFromZenith = Int32.Parse (arg);
705                         DateTime day = GetGlobalCalendar().AddDays (dateZenith, daysFromZenith);
706                         SelectedDates.SelectRange (day, day);
707                         OnSelectionChanged ();
708                 }
709
710                 protected override void LoadViewState (object savedState)
711                 {
712                         object [] states = (object []) savedState;
713
714                         if (states [0] != null)
715                                  base.LoadViewState (states [0]);
716
717                         if (states [1] != null)
718                                 DayHeaderStyle.LoadViewState (states [1]);
719
720                         if (states [2] != null)
721                                 DayStyle.LoadViewState (states [2]);
722
723                         if (states [3] != null)
724                                 NextPrevStyle.LoadViewState (states [3]);
725
726                         if (states [4] != null)
727                                 OtherMonthDayStyle.LoadViewState (states [4]);
728
729                         if (states [5] != null)
730                                 SelectedDayStyle.LoadViewState (states [5]);
731
732                         if (states [6] != null)
733                                 TitleStyle.LoadViewState (states [6]);
734
735                         if (states [7] != null)
736                                 TodayDayStyle.LoadViewState (states [7]);
737
738                         if (states [8] != null)
739                                 SelectorStyle.LoadViewState (states [8]);
740
741                         if (states [9] != null)
742                                 WeekendDayStyle.LoadViewState (states [9]);
743
744                         ArrayList array = (ArrayList) ViewState ["SelectedDates"];
745                         if (array != null) {
746                                 dateList = array;
747                                 selectedDatesCollection = new SelectedDatesCollection (dateList);
748                         }
749                 }
750
751                 protected virtual void OnDayRender (TableCell cell, CalendarDay day)
752                 {
753                         DayRenderEventHandler eh = (DayRenderEventHandler) (Events [DayRenderEvent]);
754                         if (eh != null)
755                                 eh (this, new DayRenderEventArgs (cell, day));
756                 }
757
758 #if NET_2_0
759                 protected internal
760 #else           
761                 protected
762 #endif          
763                 override void OnPreRender (EventArgs e)
764                 {
765                         base.OnPreRender (e);
766                 }
767
768                 protected virtual void OnSelectionChanged ()
769                 {
770                         EventHandler eh = (EventHandler) (Events [SelectionChangedEvent]);
771                         if (eh != null)
772                                 eh (this, EventArgs.Empty);
773                 }
774
775                 protected virtual void OnVisibleMonthChanged (DateTime newDate,  DateTime previousDate)
776                 {
777                         MonthChangedEventHandler eh = (MonthChangedEventHandler) (Events [VisibleMonthChangedEvent]);
778                         if (eh != null)
779                                 eh (this, new MonthChangedEventArgs (newDate, previousDate));
780                 }
781
782 #if NET_2_0
783                 protected internal
784 #else           
785                 protected
786 #endif          
787                 override void Render (HtmlTextWriter writer)
788                 {
789                         Table table = new Table ();
790                         table.CellSpacing = CellSpacing;
791                         table.CellPadding = CellPadding;
792                         if (ControlStyleCreated)
793                                 table.ControlStyle.CopyFrom (ControlStyle);
794                         table.CopyBaseAttributes (this);
795                         table.ID = ID;
796
797                         if (ShowGridLines)
798                                 table.GridLines = GridLines.Both;
799
800                         table.RenderBeginTag (writer);
801
802 #if NET_2_0
803                         if (Caption != "")
804                                 WriteCaption (writer);
805 #endif
806
807                         if (ShowTitle)
808                                 WriteTitle (writer);
809
810                         if (ShowDayHeader)
811                                 WriteDayHeader (writer);
812
813                         WriteDays (writer);
814
815                         table.RenderEndTag (writer);
816                 }
817
818                 protected override object SaveViewState ()
819                 {
820                         object [] states = new object [10];
821
822                         if (dayHeaderStyle != null)
823                                 states [1] = dayHeaderStyle.SaveViewState ();
824
825                         if (dayStyle != null)
826                                 states [2] = dayStyle.SaveViewState ();
827
828                         if (nextPrevStyle != null)
829                                 states [3] = nextPrevStyle.SaveViewState ();
830
831                         if (otherMonthDayStyle != null)
832                                 states [4] = otherMonthDayStyle.SaveViewState ();
833
834                         if (selectedDayStyle != null)
835                                 states [5] = selectedDayStyle.SaveViewState ();
836
837                         if (titleStyle != null)
838                                 states [6] = titleStyle.SaveViewState ();
839
840                         if (todayDayStyle != null)
841                                 states [7] =todayDayStyle.SaveViewState ();
842
843                         if (selectorStyle != null)
844                                 states [8] = selectorStyle.SaveViewState ();
845
846                         if (weekendDayStyle != null)
847                                 states [9] = weekendDayStyle.SaveViewState ();
848
849                         if (SelectedDates.Count > 0) {
850                                 ViewState ["SelectedDates"] = dateList;
851                         }
852
853                         states [0] = base.SaveViewState ();
854
855                         for (int i = 0; i < states.Length; i++) {
856                                 if (states [i] != null) {
857                                         return states;
858                                 }
859                         }
860
861                         return null;
862                 }
863
864                 protected override void TrackViewState ()
865                 {
866                         base.TrackViewState ();
867
868                         if (dayHeaderStyle != null)
869                                 dayHeaderStyle.TrackViewState ();
870
871                         if (dayStyle != null)
872                                 dayStyle.TrackViewState ();
873
874                         if (nextPrevStyle != null)
875                                 nextPrevStyle.TrackViewState ();
876
877                         if (otherMonthDayStyle != null)
878                                 otherMonthDayStyle.TrackViewState ();
879
880                         if (selectedDayStyle != null)
881                                 selectedDayStyle.TrackViewState ();
882
883                         if (titleStyle != null)
884                                 titleStyle.TrackViewState ();
885
886                         if (todayDayStyle  != null)
887                                 todayDayStyle.TrackViewState ();
888
889                         if (selectorStyle != null)
890                                 selectorStyle.TrackViewState ();
891
892                         if (weekendDayStyle != null)
893                                 weekendDayStyle.TrackViewState ();
894                 }
895
896                 //
897                 // Private methods
898                 //
899                 private void WriteDayHeader (HtmlTextWriter writer)
900                 {
901                         int i, first;
902                         string dayName;
903                         i = first = (int) (DisplayFirstDayOfWeek);
904                         TableCell cell;
905
906
907                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
908
909                         if (SelectionMode == CalendarSelectionMode.DayWeek) {
910                                 cell = new TableCell();
911                                 cell.HorizontalAlign = HorizontalAlign.Center;
912                                 cell.ApplyStyle (DayHeaderStyle);
913
914                                 // Empty Cell
915                                 cell.RenderBeginTag (writer);
916                                 cell.RenderEndTag (writer);
917                         } else {
918                                 if (SelectionMode == CalendarSelectionMode.DayWeekMonth) {
919                                         TableCell selector = new TableCell ();
920                                         selector.ApplyStyle (SelectorStyle);
921                                         selector.HorizontalAlign = HorizontalAlign.Center;
922
923                                         DateTime date = new DateTime (DisplayDate.Year, DisplayDate.Month, 1); // first date
924                                         int days =  DateTime.DaysInMonth (DisplayDate.Year, DisplayDate.Month);
925
926                                         selector.RenderBeginTag (writer);
927                                         writer.Write (BuildLink ("R" + GetDaysFromZenith (date) + days, SelectMonthText, DayHeaderStyle.ForeColor, Enabled));
928                                         selector.RenderEndTag (writer);
929                                 }
930                         }
931
932                         while (true) {
933                                 DayOfWeek dayOfWeek = (DayOfWeek) i;
934                                 dayName = dateInfo.GetDayName (dayOfWeek);
935
936 #if NET_2_0
937                                 if (UseAccessibleHeader) {
938                                         writer.AddAttribute (HtmlTextWriterAttribute.Abbr, dayName);
939                                         writer.AddAttribute (HtmlTextWriterAttribute.Scope, "col");
940                                         cell = new TableHeaderCell();
941                                 }
942                                 else
943 #endif
944                                         cell = new TableCell();
945
946                                 cell.HorizontalAlign = HorizontalAlign.Center;
947                                 cell.ApplyStyle (DayHeaderStyle);
948
949                                 cell.RenderBeginTag (writer);
950
951                                 switch (DayNameFormat) {
952                                 case DayNameFormat.FirstLetter:
953                                         dayName = dayName.Substring (0, 1);
954                                         break;
955                                 case DayNameFormat.FirstTwoLetters:
956                                         dayName = dayName.Substring (0, 2);
957                                         break;
958                                 case DayNameFormat.Full:
959                                         break;
960                                 case DayNameFormat.Short:
961                                 default:
962                                         dayName = dateInfo.GetAbbreviatedDayName (dayOfWeek);
963                                         break;
964                                 }
965
966                                 writer.Write (dayName);
967                                 cell.RenderEndTag (writer);
968
969                                 if (i >= daysInAWeek - 1) {
970                                         i = 0;
971                                 }
972                                 else {
973                                         i++;
974                                 }
975                                 if (i == first)
976                                         break;
977                         }
978
979                         writer.RenderEndTag ();
980                 }
981
982                 private void WriteDay (DateTime date, HtmlTextWriter writer)
983                 {                       
984                         Style style = new Style ();
985                         TableCell cell = new TableCell ();
986
987                         CalendarDay day = new CalendarDay (date,
988                                 IsWeekEnd (date.DayOfWeek),
989                                 date == TodaysDate, SelectedDates.Contains (date),
990                                 GetGlobalCalendar ().GetMonth (DisplayDate) != GetGlobalCalendar ().GetMonth (date),
991                                 date.Day.ToString ());
992
993                         day.IsSelectable = SelectionMode != CalendarSelectionMode.None;
994                         cell.HorizontalAlign = HorizontalAlign.Center;
995                         cell.Width = Unit.Percentage (GetCellWidth ());
996
997                         LiteralControl lit = new LiteralControl (day.DayNumberText);
998                         cell.Controls.Add (lit);
999
1000                         OnDayRender (cell, day);
1001                                         
1002                         if (dayStyle != null && !dayStyle.IsEmpty) {
1003                                 style.CopyFrom (dayStyle);
1004                         }
1005
1006                         if (day.IsWeekend && weekendDayStyle != null && !weekendDayStyle.IsEmpty) {
1007                                 style.CopyFrom (weekendDayStyle);
1008                         }
1009
1010                         if (day.IsToday && todayDayStyle != null && !todayDayStyle.IsEmpty) {
1011                                 style.CopyFrom (todayDayStyle);
1012                         }
1013
1014                         if (day.IsOtherMonth && otherMonthDayStyle != null && !otherMonthDayStyle.IsEmpty) {
1015                                 style.CopyFrom (otherMonthDayStyle);
1016                         }
1017
1018                         if (day.IsSelected && Enabled) {
1019                                 style.BackColor = Color.Silver;
1020                                 style.ForeColor = Color.White;
1021                                 if (selectedDayStyle != null && !selectedDayStyle.IsEmpty) {
1022                                         style.CopyFrom (selectedDayStyle);
1023                                 }
1024                         }
1025
1026                         cell.ApplyStyle (style);
1027
1028                         lit.Text = BuildLink (GetDaysFromZenith (date).ToString (), day.DayNumberText,
1029                                               cell.ForeColor, day.IsSelectable && Enabled);
1030
1031                         cell.RenderControl (writer);
1032                 }
1033
1034                 private void WriteDays (HtmlTextWriter writer)
1035                 {
1036                         DateTime date = new DateTime (DisplayDate.Year, DisplayDate.Month, 1); // first date
1037                         DateTime lastDate;
1038                         TableCell selectorCell = null;
1039                         int n;
1040
1041                         // Goes backwards until we find the date of that is begining of the week
1042                         for (n = 0; n < daysInAWeek; n++) {
1043                                 if (date.DayOfWeek == DisplayFirstDayOfWeek)
1044                                         break;
1045
1046                                 date = GetGlobalCalendar().AddDays (date, -1);
1047                         }
1048                         /* if the start date is the first day of the week, we need to shift backward one more week */
1049                         if (n == 0)
1050                                 date = GetGlobalCalendar().AddDays (date, -1 * daysInAWeek);
1051
1052                         lastDate = GetGlobalCalendar().AddDays (date, 6 * daysInAWeek); // Always six weeks per months
1053
1054                         while (true) {
1055                                 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1056
1057                                 if (HasWeekSelectors (SelectionMode)) { // Week selector
1058                                         if (selectorCell == null) {
1059                                                 selectorCell = new TableCell ();
1060                                                 selectorCell.ApplyStyle (SelectorStyle);
1061                                                 selectorCell.HorizontalAlign = HorizontalAlign.Center;
1062                                                 selectorCell.Width = Unit.Percentage (GetCellWidth ());
1063                                         }
1064
1065                                         selectorCell.RenderBeginTag (writer);
1066                                         writer.Write (BuildLink ("R" + GetDaysFromZenith (date) + "07", SelectWeekText, selectorCell.ForeColor, Enabled));
1067                                         selectorCell.RenderEndTag (writer);
1068                                 }
1069
1070                                 for (int i = 0; i < daysInAWeek; i++) {
1071                                         WriteDay (date, writer);
1072                                         date = GetGlobalCalendar().AddDays (date, 1);
1073                                 }
1074
1075                                 writer.RenderEndTag ();
1076                                 if (date >= lastDate)
1077                                         break;
1078                         }
1079                 }
1080
1081                 private string BuildLink (string arg, string text, Color foreColor, bool hasLink)
1082                 {
1083                         string str = string.Empty;
1084                         Color clr;
1085                         hasLink = (Page != null && hasLink == true) ? true : false;
1086
1087                         if (hasLink) {
1088 #if NET_2_0
1089                                 Page.ClientScript.RegisterForEventValidation(this.UniqueID, arg);
1090 #endif                  
1091                                 str = "<a href=\"";
1092                                 str += Page.ClientScript.GetPostBackClientHyperlink (this, arg);
1093                                 str += "\"";
1094                         
1095
1096                                 if (!foreColor.IsEmpty) {
1097                                         clr = foreColor;
1098                                 } else {
1099                                         if (ForeColor.IsEmpty)
1100                                                 clr = Color.Black;
1101                                         else
1102                                                 clr = ForeColor;
1103                                 }
1104
1105                                 str += " style=color:" + ColorTranslator.ToHtml (clr);
1106                                 str += ">";
1107                                 str += text;
1108                                 str += "</a>";
1109                         }
1110                         else 
1111                                 str += text;
1112
1113                         return str;
1114                 }
1115
1116                 private int GetDaysFromZenith (DateTime date)
1117                 {
1118                         TimeSpan span =  date.Subtract (dateZenith);
1119                         return span.Days;
1120                 }
1121
1122 #if NET_2_0
1123                 void WriteCaption (HtmlTextWriter writer)
1124                 {
1125                         if (CaptionAlign != TableCaptionAlign.NotSet)
1126                                 writer.AddAttribute (HtmlTextWriterAttribute.Align, CaptionAlign.ToString (CultureInfo.InvariantCulture));
1127
1128                         writer.RenderBeginTag (HtmlTextWriterTag.Caption);
1129                         writer.Write (Caption);
1130                         writer.RenderEndTag ();
1131                 }
1132 #endif
1133
1134                 private void WriteTitle (HtmlTextWriter writer)
1135                 {
1136                         TableCell cellNextPrev = null;
1137                         TableCell titleCell = new TableCell ();
1138                         Table tableTitle = new Table ();
1139
1140                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1141
1142                         titleCell.ColumnSpan = HasWeekSelectors (SelectionMode) ? 8 : 7;
1143
1144                         if (titleStyle != null && !titleStyle.IsEmpty && !titleStyle.BackColor.IsEmpty) {
1145                                 titleCell.BackColor = titleStyle.BackColor;
1146                         } else {
1147                                 titleCell.BackColor = Color.Silver;
1148                         }
1149
1150                         titleCell.RenderBeginTag (writer);
1151
1152                         // Table
1153                         tableTitle.Width =  Unit.Percentage (100);
1154                         if (titleStyle != null && !titleStyle.IsEmpty) {
1155                                 tableTitle.ApplyStyle (titleStyle);
1156                         }
1157
1158                         tableTitle.RenderBeginTag (writer);
1159                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1160
1161                         if (ShowNextPrevMonth) { // Previous Table Data
1162                                 cellNextPrev = new TableCell ();
1163                                 cellNextPrev.ApplyStyle (nextPrevStyle);
1164                                 cellNextPrev.Width = Unit.Percentage (15);
1165
1166                                 DateTime date = GetGlobalCalendar().AddMonths (DisplayDate, - 1);
1167                                 date = GetGlobalCalendar().AddDays (date, -DisplayDate.Day + 1);
1168                                 cellNextPrev.RenderBeginTag (writer);
1169                                 writer.Write (BuildLink ("V" + GetDaysFromZenith (date), GetNextPrevFormatText (date, false), cellNextPrev.ForeColor, Enabled));
1170                                 cellNextPrev.RenderEndTag (writer);
1171                         }
1172
1173                         // Current Month Table Data
1174                         {
1175                                 string str;
1176                                 TableCell cellMonth = new TableCell ();
1177                                 cellMonth.Width = Unit.Percentage (70);
1178                                 cellMonth.HorizontalAlign = HorizontalAlign.Center;
1179
1180                                 cellMonth.RenderBeginTag (writer);
1181
1182                                 str = dateInfo.GetMonthName (GetGlobalCalendar ().GetMonth (DisplayDate));
1183
1184                                 if (TitleFormat == TitleFormat.MonthYear)
1185                                         str += " " + (DisplayDate.Year.ToString ());
1186
1187                                 writer.Write (str);
1188                                 cellMonth.RenderEndTag (writer);
1189                         }
1190
1191                         if (ShowNextPrevMonth) { // Next Table Data
1192                                 DateTime date = GetGlobalCalendar().AddMonths (DisplayDate, + 1);
1193                                 date = GetGlobalCalendar().AddDays (date, -DisplayDate.Day + 1);
1194
1195                                 cellNextPrev.HorizontalAlign = HorizontalAlign.Right;
1196                                 cellNextPrev.RenderBeginTag (writer);
1197                                 writer.Write (BuildLink ("V" + GetDaysFromZenith (date), GetNextPrevFormatText (date, true), cellNextPrev.ForeColor, Enabled));
1198                                 cellNextPrev.RenderEndTag (writer);
1199                         }
1200
1201                         writer.RenderEndTag ();
1202                         tableTitle.RenderEndTag (writer);
1203                         titleCell.RenderEndTag (writer);
1204                         writer.RenderEndTag (); //tr
1205
1206                 }
1207
1208
1209                 private string GetNextPrevFormatText (DateTime date, bool next)
1210                 {
1211                         string text;
1212                         switch (NextPrevFormat) {
1213                                 case NextPrevFormat.FullMonth:
1214                                         text = dateInfo.GetMonthName (GetGlobalCalendar ().GetMonth (date));
1215                                         break;
1216                                 case NextPrevFormat.ShortMonth:
1217                                         text = dateInfo.GetAbbreviatedMonthName (GetGlobalCalendar ().GetMonth (date));
1218                                         break;
1219                                 case NextPrevFormat.CustomText:
1220                                 default:
1221                                         text = ((next) ? NextMonthText : PrevMonthText);
1222                                         break;
1223                         }
1224
1225                         return text;
1226                 }
1227
1228                 private bool IsWeekEnd (DayOfWeek day)
1229                 {
1230                         return (day == DayOfWeek.Saturday || day == DayOfWeek.Sunday);
1231                 }
1232
1233                 private double GetCellWidth ()
1234                 {
1235                         return HasWeekSelectors (SelectionMode) ? 100/8 : 100/7;
1236                 }
1237
1238                 private System.Globalization.Calendar GetGlobalCalendar ()
1239                 {
1240                         return DateTimeFormatInfo.CurrentInfo.Calendar;
1241                 }
1242
1243                 [WebSysDescription ("")]
1244                 [WebCategory ("Action")]
1245                 public event DayRenderEventHandler DayRender {
1246                         add {
1247                                 Events.AddHandler (DayRenderEvent, value);
1248                         }
1249                         remove {
1250                                 Events.RemoveHandler (DayRenderEvent, value);
1251                         }
1252                 }
1253
1254                 [WebSysDescription ("")]
1255                 [WebCategory ("Action")]
1256                 public event EventHandler SelectionChanged {
1257                         add {
1258                                 Events.AddHandler (SelectionChangedEvent, value);
1259                         }
1260                         remove {
1261                                 Events.RemoveHandler (SelectionChangedEvent, value);
1262                         }
1263                 }
1264
1265                 [WebSysDescription ("")]
1266                 [WebCategory ("Action")]
1267                 public event MonthChangedEventHandler VisibleMonthChanged {
1268                         add {
1269                                 Events.AddHandler (VisibleMonthChangedEvent, value);
1270                         }
1271                         remove {
1272                                 Events.RemoveHandler (VisibleMonthChangedEvent, value);
1273                         }
1274                 }
1275         }
1276 }
1277