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