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