2004-12-20 Lluis Sanchez Gual <lluis@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / Menu.cs
1 //
2 // System.Web.UI.WebControls.Menu.cs
3 //
4 // Authors:
5 //      Lluis Sanchez Gual (lluis@novell.com)
6 //
7 // (C) 2004 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 #if NET_2_0
32
33 using System;
34 using System.Collections;
35 using System.Text;
36 using System.ComponentModel;
37 using System.Web.UI;
38 using System.Web.Handlers;
39 using System.Collections.Specialized;
40 using System.IO;
41
42 namespace System.Web.UI.WebControls
43 {
44         public class Menu : HierarchicalDataBoundControl, IPostBackEventHandler, INamingContainer
45         {
46                 MenuItemStyle dynamicMenuItemStyle;
47                 MenuItemStyle dynamicMenuStyle;
48                 MenuItemStyle dynamicSelectedStyle;
49                 MenuItemStyle staticMenuItemStyle;
50                 MenuItemStyle staticMenuStyle;
51                 MenuItemStyle staticSelectedStyle;
52                 Style staticHoverStyle;
53                 Style dynamicHoverStyle;
54
55                 MenuItemStyleCollection levelMenuItemStyles;
56                 MenuItemStyleCollection levelSelectedStyles;
57                 
58                 MenuItemCollection items;
59                 MenuItemBindingCollection dataBindings;
60                 MenuItem selectedItem;
61                 Hashtable bindings;
62                 
63                 private static readonly object MenuItemClickEvent = new object();
64                 
65                 public event MenuEventHandler MenuItemClick {
66                         add { Events.AddHandler (MenuItemClickEvent, value); }
67                         remove { Events.RemoveHandler (MenuItemClickEvent, value); }
68                 }
69                 
70                 protected virtual void OnMenuItemClick (MenuEventArgs e)
71                 {
72                         if (Events != null) {
73                                 MenuEventHandler eh = (MenuEventHandler) Events [MenuItemClickEvent];
74                                 if (eh != null) eh (this, e);
75                         }
76                 }
77
78                 [PersistenceMode (PersistenceMode.InnerProperty)]
79                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
80                 [Editor ("System.Web.UI.Design.MenuItemBindingsEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
81                 public virtual MenuItemBindingCollection DataBindings {
82                         get {
83                                 if (dataBindings == null) {
84                                         dataBindings = new MenuItemBindingCollection ();
85                                         if (IsTrackingViewState)
86                                                 ((IStateManager)dataBindings).TrackViewState();
87                                 }
88                                 return dataBindings;
89                         }
90                 }
91
92                 [DefaultValue (500)]
93                 public virtual int DisappearAfter {
94                         get {
95                                 object o = ViewState ["DisappearAfter"];
96                                 if (o != null) return (int)o;
97                                 return 500;
98                         }
99                         set {
100                                 ViewState["DisappearAfter"] = value;
101                         }
102                 }
103
104                 [DefaultValue ("")]
105                 [UrlProperty]
106                 [WebCategory ("Appearance")]
107                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
108                 public virtual string DynamicBottomSeparatorImageUrl {
109                         get {
110                                 object o = ViewState ["dbsiu"];
111                                 if (o != null) return (string)o;
112                                 return "";
113                         }
114                         set {
115                                 ViewState["dbsiu"] = value;
116                         }
117                 }
118
119                 [DefaultValue ("")]
120                 [UrlProperty]
121                 [WebCategory ("Appearance")]
122                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
123                 public virtual string DynamicTopSeparatorImageUrl {
124                         get {
125                                 object o = ViewState ["dtsiu"];
126                                 if (o != null) return (string)o;
127                                 return "";
128                         }
129                         set {
130                                 ViewState["dtsiu"] = value;
131                         }
132                 }
133
134                 [DefaultValue ("")]
135                 [UrlProperty]
136                 [WebCategory ("Appearance")]
137                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
138                 public virtual string StaticBottomSeparatorImageUrl {
139                         get {
140                                 object o = ViewState ["sbsiu"];
141                                 if (o != null) return (string)o;
142                                 return "";
143                         }
144                         set {
145                                 ViewState["sbsiu"] = value;
146                         }
147                 }
148
149                 [DefaultValue ("")]
150                 [UrlProperty]
151                 [WebCategory ("Appearance")]
152                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
153                 public virtual string StaticTopSeparatorImageUrl {
154                         get {
155                                 object o = ViewState ["stsiu"];
156                                 if (o != null) return (string)o;
157                                 return "";
158                         }
159                         set {
160                                 ViewState["stsiu"] = value;
161                         }
162                 }
163
164                 [DefaultValue (Orientation.Vertical)]
165                 public virtual Orientation Orientation {
166                         get {
167                                 object o = ViewState ["Orientation"];
168                                 if (o != null) return (Orientation) o;
169                                 return Orientation.Vertical;
170                         }
171                         set {
172                                 ViewState["Orientation"] = value;
173                         }
174                 }
175
176                 [DefaultValue (1)]
177                 public virtual int StaticDisplayLevels {
178                         get {
179                                 object o = ViewState ["StaticDisplayLevels"];
180                                 if (o != null) return (int)o;
181                                 return 1;
182                         }
183                         set {
184                                 if (value < 1) throw new ArgumentOutOfRangeException ();
185                                 ViewState["StaticDisplayLevels"] = value;
186                         }
187                 }
188
189                 [DefaultValue ("16px")]
190                 public Unit StaticSubMenuIndent {
191                         get {
192                                 object o = ViewState ["StaticSubMenuIndent"];
193                                 if (o != null) return (Unit)o;
194                                 return new Unit (16);
195                         }
196                         set {
197                                 ViewState["StaticSubMenuIndent"] = value;
198                         }
199                 }
200
201                 [DefaultValue (3)]
202                 public virtual int MaximumDynamicDisplayLevels {
203                         get {
204                                 object o = ViewState ["MaximumDynamicDisplayLevels"];
205                                 if (o != null) return (int)o;
206                                 return 3;
207                         }
208                         set {
209                                 if (value < 0) throw new ArgumentOutOfRangeException ();
210                                 ViewState["MaximumDynamicDisplayLevels"] = value;
211                         }
212                 }
213
214                 [DefaultValue (0)]
215                 public virtual int DynamicVerticalOffset {
216                         get {
217                                 object o = ViewState ["DynamicVerticalOffset"];
218                                 if (o != null) return (int)o;
219                                 return 0;
220                         }
221                         set {
222                                 ViewState["DynamicVerticalOffset"] = value;
223                         }
224                 }
225
226                 [DefaultValue (0)]
227                 public virtual int DynamicHorizontalOffset {
228                         get {
229                                 object o = ViewState ["DynamicHorizontalOffset"];
230                                 if (o != null) return (int)o;
231                                 return 0;
232                         }
233                         set {
234                                 ViewState["DynamicHorizontalOffset"] = value;
235                         }
236                 }
237
238                 [DefaultValue (true)]
239                 public virtual bool DynamicEnableDefaultPopOutImage {
240                         get {
241                                 object o = ViewState ["dedpoi"];
242                                 if (o != null) return (bool)o;
243                                 return true;
244                         }
245                         set {
246                                 ViewState["dedpoi"] = value;
247                         }
248                 }
249
250                 [DefaultValue (true)]
251                 public virtual bool StaticEnableDefaultPopOutImage {
252                         get {
253                                 object o = ViewState ["sedpoi"];
254                                 if (o != null) return (bool)o;
255                                 return true;
256                         }
257                         set {
258                                 ViewState["sedpoi"] = value;
259                         }
260                 }
261
262                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
263                 [PersistenceMode (PersistenceMode.InnerProperty)]
264                 [Editor ("System.Web.UI.Design.MenuItemCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
265                 public virtual MenuItemCollection Items {
266                         get {
267                                 if (items == null) {
268                                         items = new MenuItemCollection (this);
269                                         if (IsTrackingViewState)
270                                                 ((IStateManager)items).TrackViewState();
271                                 }
272                                 return items;
273                         }
274                 }
275
276                 [DefaultValue ('/')]
277                 public virtual char PathSeparator {
278                         get {
279                                 object o = ViewState ["PathSeparator"];
280                                 if(o != null) return (char)o;
281                                 return '/';
282                         }
283                         set {
284                                 ViewState ["PathSeparator"] = value;
285                         }
286                 }
287
288                 [DefaultValue (false)]
289                 public virtual bool ItemWrap {
290                         get {
291                                 object o = ViewState ["ItemWrap"];
292                                 if(o != null) return (bool)o;
293                                 return false;
294                         }
295                         set {
296                                 ViewState ["ItemWrap"] = value;
297                         }
298                 }
299
300                 [PersistenceMode (PersistenceMode.InnerProperty)]
301                 [NotifyParentProperty (true)]
302                 [DefaultValue (null)]
303                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
304                 public virtual MenuItemStyle DynamicMenuItemStyle {
305                         get {
306                                 if (dynamicMenuItemStyle == null) {
307                                         dynamicMenuItemStyle = new MenuItemStyle ();
308                                         if (IsTrackingViewState)
309                                                 dynamicMenuItemStyle.TrackViewState();
310                                 }
311                                 return dynamicMenuItemStyle;
312                         }
313                 }
314                 
315                 [PersistenceMode (PersistenceMode.InnerProperty)]
316                 [NotifyParentProperty (true)]
317                 [DefaultValue (null)]
318                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
319                 public virtual MenuItemStyle DynamicSelectedStyle {
320                         get {
321                                 if (dynamicSelectedStyle == null) {
322                                         dynamicSelectedStyle = new MenuItemStyle ();
323                                         if (IsTrackingViewState)
324                                                 dynamicSelectedStyle.TrackViewState();
325                                 }
326                                 return dynamicSelectedStyle;
327                         }
328                 }
329                 
330                 [PersistenceMode (PersistenceMode.InnerProperty)]
331                 [NotifyParentProperty (true)]
332                 [DefaultValue (null)]
333                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
334                 public virtual MenuItemStyle DynamicMenuStyle {
335                         get {
336                                 if (dynamicMenuStyle == null) {
337                                         dynamicMenuStyle = new MenuItemStyle ();
338                                         if (IsTrackingViewState)
339                                                 dynamicMenuStyle.TrackViewState();
340                                 }
341                                 return dynamicMenuStyle;
342                         }
343                 }
344                 
345                 [PersistenceMode (PersistenceMode.InnerProperty)]
346                 [NotifyParentProperty (true)]
347                 [DefaultValue (null)]
348                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
349                 public virtual MenuItemStyle StaticMenuItemStyle {
350                         get {
351                                 if (staticMenuItemStyle == null) {
352                                         staticMenuItemStyle = new MenuItemStyle ();
353                                         if (IsTrackingViewState)
354                                                 staticMenuItemStyle.TrackViewState();
355                                 }
356                                 return staticMenuItemStyle;
357                         }
358                 }
359                 
360                 [PersistenceMode (PersistenceMode.InnerProperty)]
361                 [NotifyParentProperty (true)]
362                 [DefaultValue (null)]
363                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
364                 public virtual MenuItemStyle StaticSelectedStyle {
365                         get {
366                                 if (staticSelectedStyle == null) {
367                                         staticSelectedStyle = new MenuItemStyle ();
368                                         if (IsTrackingViewState)
369                                                 staticSelectedStyle.TrackViewState();
370                                 }
371                                 return staticSelectedStyle;
372                         }
373                 }
374                 
375                 [PersistenceMode (PersistenceMode.InnerProperty)]
376                 [NotifyParentProperty (true)]
377                 [DefaultValue (null)]
378                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
379                 public virtual MenuItemStyle StaticMenuStyle {
380                         get {
381                                 if (staticMenuStyle == null) {
382                                         staticMenuStyle = new MenuItemStyle ();
383                                         if (IsTrackingViewState)
384                                                 staticMenuStyle.TrackViewState();
385                                 }
386                                 return staticMenuStyle;
387                         }
388                 }
389
390                 [PersistenceMode (PersistenceMode.InnerProperty)]
391                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
392                 public virtual MenuItemStyleCollection LevelMenuItemStyles {
393                         get {
394                                 if (levelMenuItemStyles == null) {
395                                         levelMenuItemStyles = new MenuItemStyleCollection ();
396                                         if (IsTrackingViewState)
397                                                 ((IStateManager)levelMenuItemStyles).TrackViewState();
398                                 }
399                                 return levelMenuItemStyles;
400                         }
401                 }
402
403                 [PersistenceMode (PersistenceMode.InnerProperty)]
404                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
405                 public virtual MenuItemStyleCollection LevelSelectedStyles {
406                         get {
407                                 if (levelSelectedStyles == null) {
408                                         levelSelectedStyles = new MenuItemStyleCollection ();
409                                         if (IsTrackingViewState)
410                                                 ((IStateManager)levelSelectedStyles).TrackViewState();
411                                 }
412                                 return levelSelectedStyles;
413                         }
414                 }
415
416                 [PersistenceMode (PersistenceMode.InnerProperty)]
417                 [NotifyParentProperty (true)]
418                 [DefaultValue (null)]
419                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
420                 public virtual Style DynamicHoverStyle {
421                         get {
422                                 if (dynamicHoverStyle == null) {
423                                         dynamicHoverStyle = new Style ();
424                                         if (IsTrackingViewState)
425                                                 dynamicHoverStyle.TrackViewState();
426                                 }
427                                 return dynamicHoverStyle;
428                         }
429                 }
430                 
431                 [PersistenceMode (PersistenceMode.InnerProperty)]
432                 [NotifyParentProperty (true)]
433                 [DefaultValue (null)]
434                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
435                 public virtual Style StaticHoverStyle {
436                         get {
437                                 if (staticHoverStyle == null) {
438                                         staticHoverStyle = new Style ();
439                                         if (IsTrackingViewState)
440                                                 staticHoverStyle.TrackViewState();
441                                 }
442                                 return staticHoverStyle;
443                         }
444                 }
445                 
446                 [Browsable (false)]
447                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
448                 public MenuItem SelectedItem {
449                         get { return selectedItem; }
450                 }
451
452                 internal void SetSelectedItem (MenuItem item)
453                 {
454                         if (selectedItem == item) return;
455                         if (selectedItem != null)
456                                 selectedItem.SelectedFlag = false;
457                         selectedItem = item;
458                         selectedItem.SelectedFlag = true;
459                 }
460                 
461                 public MenuItem FindItem (string valuePath)
462                 {
463                         if (valuePath == null) throw new ArgumentNullException ("valuePath");
464                         string[] path = valuePath.Split (PathSeparator);
465                         int n = 0;
466                         MenuItemCollection col = Items;
467                         bool foundBranch = true;
468                         while (col.Count > 0 && foundBranch) {
469                                 foundBranch = false;
470                                 foreach (MenuItem item in col) {
471                                         if (item.Value == path [n]) {
472                                                 if (++n == path.Length) return item;
473                                                 col = item.ChildItems;
474                                                 foundBranch = true;
475                                                 break;
476                                         }
477                                 }
478                         }
479                         return null;
480                 }
481                 
482                 string GetBindingKey (string dataMember, int depth)
483                 {
484                         return dataMember + " " + depth;
485                 }
486                 
487                 internal MenuItemBinding FindBindingForItem (string type, int depth)
488                 {
489                         if (bindings == null) return null;
490
491                         MenuItemBinding bin = (MenuItemBinding) bindings [GetBindingKey (type, depth)];
492                         if (bin != null) return bin;
493                         
494                         bin = (MenuItemBinding) bindings [GetBindingKey (type, -1)];
495                         if (bin != null) return bin;
496                         
497                         bin = (MenuItemBinding) bindings [GetBindingKey ("", depth)];
498                         if (bin != null) return bin;
499                         
500                         bin = (MenuItemBinding) bindings [GetBindingKey ("", -1)];
501                         return bin;
502                 }
503                 
504                 protected internal override void PerformDataBinding ()
505                 {
506                         base.PerformDataBinding ();
507                         HierarchicalDataSourceView data = GetData ("");
508                         IHierarchicalEnumerable e = data.Select ();
509                         foreach (object obj in e) {
510                                 IHierarchyData hdata = e.GetHierarchyData (obj);
511                                 MenuItem item = new MenuItem ();
512                                 item.Bind (hdata);
513                                 Items.Add (item);
514                         }
515                 }
516                 
517                 void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
518                 {
519                         MenuItem item = FindItemByPos (eventArgument);
520                         if (item == null) return;
521                         item.Selected = true;
522                         OnMenuItemClick (new MenuEventArgs (item));
523                 }
524                 
525                 MenuItem FindItemByPos (string path)
526                 {
527                         string[] indexes = path.Split ('_');
528                         MenuItem item = null;
529                         
530                         foreach (string index in indexes) {
531                                 int i = int.Parse (index);
532                                 if (item == null) {
533                                         if (i >= Items.Count) return null;
534                                         item = Items [i];
535                                 } else {
536                                         if (i >= item.ChildItems.Count) return null;
537                                         item = item.ChildItems [i];
538                                 }
539                         }
540                         return item;
541                 }
542                 
543                 protected override void TrackViewState()
544                 {
545                         EnsureDataBound ();
546                         
547                         base.TrackViewState();
548                         if (dataBindings != null) {
549                                 ((IStateManager)dataBindings).TrackViewState ();
550                         }
551                         if (items != null) {
552                                 ((IStateManager)items).TrackViewState();
553                         }
554                         if (dynamicMenuItemStyle != null)
555                                 dynamicMenuItemStyle.TrackViewState ();
556                         if (dynamicMenuStyle != null)
557                                 dynamicMenuStyle.TrackViewState ();
558                         if (levelMenuItemStyles != null)
559                                 ((IStateManager)levelMenuItemStyles).TrackViewState();
560                         if (levelSelectedStyles != null)
561                                 ((IStateManager)levelSelectedStyles).TrackViewState();
562                         if (dynamicSelectedStyle != null)
563                                 dynamicSelectedStyle.TrackViewState();
564                         if (staticMenuItemStyle != null)
565                                 staticMenuItemStyle.TrackViewState ();
566                         if (staticMenuStyle != null)
567                                 staticMenuStyle.TrackViewState ();
568                         if (staticSelectedStyle != null)
569                                 staticSelectedStyle.TrackViewState();
570                         if (staticHoverStyle != null)
571                                 staticHoverStyle.TrackViewState();
572                         if (dynamicHoverStyle != null)
573                                 dynamicHoverStyle.TrackViewState();
574                 }
575
576                 protected override object SaveViewState()
577                 {
578                         object[] states = new object [13];
579                         states[0] = base.SaveViewState ();
580                         states[1] = dataBindings == null ? null : ((IStateManager)dataBindings).SaveViewState();
581                         states[2] = items == null ? null : ((IStateManager)items).SaveViewState();
582                         states[3] = dynamicMenuItemStyle == null ? null : dynamicMenuItemStyle.SaveViewState();
583                         states[4] = dynamicMenuStyle == null ? null : dynamicMenuStyle.SaveViewState();
584                         states[5] = levelMenuItemStyles == null ? null : ((IStateManager)levelMenuItemStyles).SaveViewState();
585                         states[6] = levelSelectedStyles == null ? null : ((IStateManager)levelSelectedStyles).SaveViewState();
586                         states[7] = dynamicSelectedStyle == null ? null : dynamicSelectedStyle.SaveViewState();
587                         states[8] = (staticMenuItemStyle == null ? null : staticMenuItemStyle.SaveViewState());
588                         states[9] = staticMenuStyle == null ? null : staticMenuStyle.SaveViewState();
589                         states[10] = staticSelectedStyle == null ? null : staticSelectedStyle.SaveViewState();
590                         states[11] = staticHoverStyle == null ? null : staticHoverStyle.SaveViewState();
591                         states[12] = dynamicHoverStyle == null ? null : dynamicHoverStyle.SaveViewState();
592
593                         for (int i = states.Length - 1; i >= 0; i--) {
594                                 if (states [i] != null)
595                                         return states;
596                         }
597
598                         return null;
599                 }
600
601                 protected override void LoadViewState (object savedState)
602                 {
603                         if (savedState == null)
604                                 return;
605
606                         object [] states = (object []) savedState;
607                         base.LoadViewState (states[0]);
608                         
609                         if (states[1] != null)
610                                 ((IStateManager)dataBindings).LoadViewState(states[1]);
611                         if (states[2] != null)
612                                 ((IStateManager)Items).LoadViewState(states[2]);
613                         if (states[3] != null)
614                                 dynamicMenuItemStyle.LoadViewState (states[3]);
615                         if (states[4] != null)
616                                 dynamicMenuStyle.LoadViewState (states[4]);
617                         if (states[5] != null)
618                                 ((IStateManager)levelMenuItemStyles).LoadViewState(states[5]);
619                         if (states[6] != null)
620                                 ((IStateManager)levelSelectedStyles).LoadViewState(states[6]);
621                         if (states[7] != null)
622                                 dynamicSelectedStyle.LoadViewState (states[7]);
623                         if (states[8] != null)
624                                 staticMenuItemStyle.LoadViewState (states[8]);
625                         if (states[9] != null)
626                                 staticMenuStyle.LoadViewState (states[9]);
627                         if (states[10] != null)
628                                 staticSelectedStyle.LoadViewState (states[10]);
629                         if (states[11] != null)
630                                 staticHoverStyle.LoadViewState (states[11]);
631                         if (states[12] != null)
632                                 dynamicHoverStyle.LoadViewState (states[12]);
633                 }
634                 
635                 protected override void OnPreRender (EventArgs e)
636                 {
637                         base.OnPreRender (e);
638                         
639                         if (!Page.ClientScript.IsClientScriptIncludeRegistered (typeof(Menu), "Menu.js")) {
640                                 string url = Page.GetWebResourceUrl (typeof(Menu), "Menu.js");
641                                 Page.ClientScript.RegisterClientScriptInclude (typeof(Menu), "Menu.js", url);
642                         }
643                         
644                         string cmenu = ClientID + "_data";
645                         string script = string.Format ("var {0} = new Object ();\n", cmenu);
646                         script += string.Format ("{0}.disappearAfter = {1};\n", cmenu, ClientScriptManager.GetScriptLiteral (DisappearAfter));
647                         script += string.Format ("{0}.vertical = {1};\n", cmenu, ClientScriptManager.GetScriptLiteral (Orientation == Orientation.Vertical));
648                         if (DynamicHorizontalOffset != 0)
649                                 script += string.Format ("{0}.dho = {1};\n", cmenu, ClientScriptManager.GetScriptLiteral (DynamicHorizontalOffset));
650                         if (DynamicVerticalOffset != 0)
651                                 script += string.Format ("{0}.dvo = {1};\n", cmenu, ClientScriptManager.GetScriptLiteral (DynamicVerticalOffset));
652                                 
653                         // The order in which styles are defined matters when more than one class
654                         // is assigned to an element
655                         
656                         if (dynamicMenuStyle != null)
657                                 RegisterItemStyle (dynamicMenuStyle);
658                         if (staticMenuStyle != null)
659                                 RegisterItemStyle (staticMenuStyle);
660                 
661                         if (staticMenuItemStyle != null)
662                                 RegisterItemStyle (staticMenuItemStyle);
663                         if (staticSelectedStyle != null)
664                                 RegisterItemStyle (staticSelectedStyle);
665
666                         if (dynamicMenuItemStyle != null)
667                                 RegisterItemStyle (dynamicMenuItemStyle);
668                         if (dynamicSelectedStyle != null)
669                                 RegisterItemStyle (dynamicSelectedStyle);
670
671                         if (levelMenuItemStyles != null)
672                                 foreach (Style style in levelMenuItemStyles)
673                                         RegisterItemStyle (style);
674
675                         if (levelSelectedStyles != null)
676                                 foreach (Style style in levelSelectedStyles)
677                                         RegisterItemStyle (style);
678                         
679                         if (dynamicHoverStyle != null)
680                                 RegisterItemStyle (dynamicHoverStyle);
681                         if (staticHoverStyle != null)
682                                 RegisterItemStyle (staticHoverStyle);
683
684                         if (staticHoverStyle != null)
685                                 script += string.Format ("{0}.staticHover = {1};\n", cmenu, ClientScriptManager.GetScriptLiteral (staticHoverStyle.RegisteredCssClass));
686                         if (dynamicHoverStyle != null)
687                                 script += string.Format ("{0}.dynamicHover = {1};\n", cmenu, ClientScriptManager.GetScriptLiteral (dynamicHoverStyle.RegisteredCssClass));
688                         
689                         Page.ClientScript.RegisterStartupScript (typeof(Menu), ClientID, script, true);
690
691                         if (dataBindings != null && dataBindings.Count > 0) {
692                                 bindings = new Hashtable ();
693                                 foreach (TreeNodeBinding bin in dataBindings) {
694                                         string key = GetBindingKey (bin.DataMember, bin.Depth);
695                                         bindings [key] = bin;
696                                 }
697                         }
698                         else
699                                 bindings = null;
700                 }
701                 
702                 void RegisterItemStyle (Style baseStyle)
703                 {
704                         Page.Header.StyleSheet.RegisterStyle (baseStyle, this);
705                         Style ts = new Style ();
706                         ts.CopyTextStylesFrom (baseStyle);
707                         Page.Header.StyleSheet.CreateStyleRule (ts, "." + baseStyle.RegisteredCssClass + " A", this);
708                 }
709                 
710                 protected override void RenderContents (HtmlTextWriter writer)
711                 {
712                         ArrayList dynamicMenus = new ArrayList ();
713                         
714                         RenderMenu (writer, Items, Orientation == Orientation.Vertical, dynamicMenus, false);
715                         
716                         for (int n=0; n<dynamicMenus.Count; n++) {
717                                 MenuItem item = (MenuItem) dynamicMenus [n];
718                                 writer.AddStyleAttribute ("visibility", "hidden");
719                                 writer.AddStyleAttribute ("position", "absolute");
720                                 writer.AddStyleAttribute ("left", "0px");
721                                 writer.AddStyleAttribute ("top", "0px");
722                                 writer.AddAttribute ("id", GetItemClientId (item, "s"));
723                                 writer.RenderBeginTag (HtmlTextWriterTag.Div);
724                                 
725                                 RenderMenu (writer, item.ChildItems, true, dynamicMenus, true);
726                                 
727                                 writer.RenderEndTag (); // DIV
728                         }
729                 }
730                 
731                 void RenderMenu (HtmlTextWriter writer, MenuItemCollection items, bool vertical, ArrayList dynamicMenus, bool dynamic)
732                 {
733                         writer.AddAttribute ("cellpadding", "0");
734                         writer.AddAttribute ("cellspacing", "0");
735
736                         if (dynamic && dynamicMenuStyle != null)
737                                 writer.AddAttribute ("class", dynamicMenuStyle.RegisteredCssClass);
738                         else if (!dynamic && staticMenuStyle != null)
739                                 writer.AddAttribute ("class", staticMenuStyle.RegisteredCssClass);
740                                 
741                         writer.RenderBeginTag (HtmlTextWriterTag.Table);
742                         if (!vertical) writer.RenderBeginTag (HtmlTextWriterTag.Tr);
743                         
744                         for (int n=0; n<items.Count; n++) {
745                                 MenuItem item = items [n];
746                                 if (n > 0) {
747                                         int itemSpacing = GetItemSpacing (item, dynamic);
748                                         if (itemSpacing != 0) {
749                                                 if (vertical) {
750                                                         writer.AddAttribute ("height", itemSpacing + "px");
751                                                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
752                                                         writer.RenderEndTag ();
753                                                 } else {
754                                                         writer.AddAttribute ("width", itemSpacing + "px");
755                                                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
756                                                         writer.RenderEndTag ();
757                                                 }
758                                         }
759                                 }
760                                 RenderMenuItem (writer, item, dynamicMenus);
761                         }
762                         
763                         if (!vertical) writer.RenderEndTag ();  // TR
764                         writer.RenderEndTag (); // TABLE
765                         
766                 }
767                 
768                 void RenderMenuItem (HtmlTextWriter writer, MenuItem item, ArrayList dynamicMenus)
769                 {
770                         bool displayChildren = (item.Depth + 1 < StaticDisplayLevels + MaximumDynamicDisplayLevels);
771                         bool dynamicChildren = displayChildren && (item.Depth + 1 >= StaticDisplayLevels) && item.ChildItems.Count > 0;
772                         bool isDynamicItem = item.Depth + 1 > StaticDisplayLevels;
773                         bool vertical = (Orientation == Orientation.Vertical) || isDynamicItem;
774
775                         if (vertical)
776                                 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
777                         
778                         Style itemStyle = null;
779                         if (levelMenuItemStyles != null && item.Depth < levelMenuItemStyles.Count)
780                                 itemStyle = levelMenuItemStyles [item.Depth];
781                         else if (isDynamicItem) {
782                                 if (dynamicMenuItemStyle != null)
783                                         itemStyle = dynamicMenuItemStyle;
784                         } else {
785                                 if (staticMenuItemStyle != null)
786                                         itemStyle = staticMenuItemStyle;
787                         }
788                         
789                         Style selectedStyle = null;
790                         if (item == SelectedItem) {
791                                 if (levelSelectedStyles != null && item.Depth < levelSelectedStyles.Count)
792                                         selectedStyle = levelSelectedStyles [item.Depth];
793                                 else if (isDynamicItem) {
794                                         if (dynamicSelectedStyle != null)
795                                                 selectedStyle = dynamicSelectedStyle;
796                                 } else {
797                                         if (staticSelectedStyle != null)
798                                                 selectedStyle = staticSelectedStyle;
799                                 }
800                         }
801                         
802                         string cls = "";
803                         if (itemStyle != null) cls += itemStyle.RegisteredCssClass + " ";
804                         if (selectedStyle != null) cls += selectedStyle.RegisteredCssClass + " ";
805                         if (cls != "")
806                                 writer.AddAttribute ("class", cls);
807                         
808                         string parentId = isDynamicItem ? "'" + item.Parent.Path + "'" : "null";
809                         if (dynamicChildren) {
810                                 writer.AddAttribute ("onmouseover", string.Format ("javascript:Menu_OverItem ('{0}','{1}',{2})", ClientID, item.Path, parentId));
811                                 writer.AddAttribute ("onmouseout", string.Format ("javascript:Menu_OutItem ('{0}','{1}')", ClientID, item.Path));
812                         } else if (isDynamicItem) {
813                                 writer.AddAttribute ("onmouseover", string.Format ("javascript:Menu_OverDynamicLeafItem ('{0}','{1}',{2})", ClientID, item.Path, parentId));
814                                 writer.AddAttribute ("onmouseout", string.Format ("javascript:Menu_OutItem ('{0}','{1}',{2})", ClientID, item.Path, parentId));
815                         } else {
816                                 writer.AddAttribute ("onmouseover", string.Format ("javascript:Menu_OverStaticLeafItem ('{0}','{1}')", ClientID, item.Path));
817                                 writer.AddAttribute ("onmouseout", string.Format ("javascript:Menu_OutItem ('{0}','{1}')", ClientID, item.Path));
818                         }
819                         
820                         writer.AddAttribute ("id", GetItemClientId (item, "i"));
821                         
822                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
823
824                         // Bottom separator image
825
826                         if (isDynamicItem && DynamicTopSeparatorImageUrl != "") {
827                                 writer.AddAttribute ("src", DynamicTopSeparatorImageUrl);
828                                 writer.RenderBeginTag (HtmlTextWriterTag.Img);
829                                 writer.RenderEndTag (); // IMG
830                         } else  if (!isDynamicItem && StaticTopSeparatorImageUrl != "") {
831                                 writer.AddAttribute ("src", StaticTopSeparatorImageUrl);
832                                 writer.RenderBeginTag (HtmlTextWriterTag.Img);
833                                 writer.RenderEndTag (); // IMG
834                         }
835                         
836                         // Menu item box
837                         
838                         
839                         writer.AddAttribute ("cellpadding", "0");
840                         writer.AddAttribute ("cellspacing", "0");
841                         writer.AddAttribute ("width", "100%");
842                         writer.RenderBeginTag (HtmlTextWriterTag.Table);
843                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
844                         
845                         if (item.Depth > 0 && !isDynamicItem) {
846                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);
847                                 writer.AddStyleAttribute ("width", StaticSubMenuIndent.ToString ());
848                                 writer.RenderBeginTag (HtmlTextWriterTag.Div);
849                                 writer.RenderEndTag (); // DIV
850                                 writer.RenderEndTag (); // TD
851                         }
852                         
853                         if (item.ImageUrl != "") {
854                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);
855                                 RenderItemHref (writer, item);
856                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
857                                 writer.AddAttribute ("src", item.ImageUrl);
858                                 writer.AddAttribute ("border", "0");
859                                 writer.RenderBeginTag (HtmlTextWriterTag.Img);
860                                 writer.RenderEndTag (); // IMG
861                                 writer.RenderEndTag (); // A
862                                 writer.RenderEndTag (); // TD
863                         }
864                         
865                         // Menu item text
866                         
867                         writer.AddAttribute ("width", "100%");
868                         if (!ItemWrap)
869                                 writer.AddAttribute ("nowrap", "nowrap");
870                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
871                         
872                         RenderItemHref (writer, item);
873                         writer.AddStyleAttribute ("text-decoration", "none");
874                         writer.RenderBeginTag (HtmlTextWriterTag.A);
875                         writer.Write (item.Text);
876                         writer.RenderEndTag (); // A
877                         
878                         writer.RenderEndTag (); // TD
879                         
880                         // Popup image
881                         
882                         if (dynamicChildren && ((isDynamicItem && DynamicEnableDefaultPopOutImage) || (!isDynamicItem && StaticEnableDefaultPopOutImage) || item.PopOutImageUrl != ""))
883                         {
884                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);
885
886                                 string src;
887                                 if (item.PopOutImageUrl != "")
888                                         src = item.PopOutImageUrl;
889                                 else
890                                         src = AssemblyResourceLoader.GetResourceUrl (typeof(Menu), "arrow_plus.gif");
891
892                                 writer.AddAttribute ("src", src);
893                                 writer.AddAttribute ("border", "0");
894                                 writer.RenderBeginTag (HtmlTextWriterTag.Img);
895                                 writer.RenderEndTag (); // IMG
896                                 
897                                 writer.RenderEndTag (); // TD
898                         }
899                         
900                         writer.RenderEndTag (); // TR
901                         writer.RenderEndTag (); // TABLE
902                         
903                         // Bottom separator image
904                                 
905                         if (isDynamicItem && DynamicBottomSeparatorImageUrl != "") {
906                                 writer.AddAttribute ("src", DynamicBottomSeparatorImageUrl);
907                                 writer.RenderBeginTag (HtmlTextWriterTag.Img);
908                                 writer.RenderEndTag (); // IMG
909                         } else  if (!isDynamicItem && StaticBottomSeparatorImageUrl != "") {
910                                 writer.AddAttribute ("src", StaticBottomSeparatorImageUrl);
911                                 writer.RenderBeginTag (HtmlTextWriterTag.Img);
912                                 writer.RenderEndTag (); // IMG
913                         }
914                         
915                         // Submenu
916                                 
917                         if (vertical) {
918                                 if (displayChildren) {
919                                         if (dynamicChildren) dynamicMenus.Add (item);
920                                         else {
921                                                 writer.AddAttribute ("width", "100%");
922                                                 RenderMenu (writer, item.ChildItems, true, dynamicMenus, false);
923                                         }
924                                 }
925                                 
926                                 writer.RenderEndTag (); // TD
927                                 writer.RenderEndTag (); // TR
928                         } else {
929                                 writer.RenderEndTag (); // TD
930                                 
931                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);
932                                 if (displayChildren) {
933                                         if (dynamicChildren) dynamicMenus.Add (item);
934                                         else RenderMenu (writer, item.ChildItems, false, dynamicMenus, false);
935                                 }
936                                 writer.RenderEndTag (); // TD
937                         }
938                 }
939                 
940                 int GetItemSpacing (MenuItem item, bool dynamic)
941                 {
942                         int itemSpacing;
943                         
944                         if (item.Selected) {
945                                 if (levelSelectedStyles != null && item.Depth < levelSelectedStyles.Count) {
946                                         itemSpacing = levelSelectedStyles [item.Depth].ItemSpacing;
947                                         if (itemSpacing != 0) return itemSpacing;
948                                 }
949                                 
950                                 if (dynamic) itemSpacing = DynamicSelectedStyle.ItemSpacing;
951                                 else itemSpacing = StaticSelectedStyle.ItemSpacing;
952                                 if (itemSpacing != 0) return itemSpacing;
953                         }
954                         
955                         if (levelMenuItemStyles != null && item.Depth < levelMenuItemStyles.Count) {
956                                 itemSpacing = levelMenuItemStyles [item.Depth].ItemSpacing;
957                                 if (itemSpacing != 0) return itemSpacing;
958                         }
959                                 
960                         if (dynamic) return DynamicMenuItemStyle.ItemSpacing;
961                         else return StaticMenuItemStyle.ItemSpacing;
962                 }
963                 
964                 void RenderItemHref (HtmlTextWriter writer, MenuItem item)
965                 {
966                         if (item.NavigateUrl != "") {
967                                 writer.AddAttribute ("href", item.NavigateUrl);
968                                 if (item.Target != null)
969                                         writer.AddAttribute ("target", item.Target);
970                         }
971                         else {
972                                 writer.AddAttribute ("href", GetClientEvent (item));
973                         }
974                 }
975                 
976                 string GetItemClientId (MenuItem item, string sufix)
977                 {
978                         return ClientID + "_" + item.Path + sufix;
979                 }
980                                                         
981                 string GetClientEvent (MenuItem item)
982                 {
983                         return Page.GetPostBackClientHyperlink (this, item.Path);
984                 }
985         }
986 }
987
988 #endif