2008-03-13 Marek Habersack <mhabersack@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 //      Igor Zelmanovich (igorz@mainsoft.com)
7 //
8 // (C) 2004 Novell, Inc (http://www.novell.com)
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 #if NET_2_0
33
34 using System;
35 using System.Collections;
36 using System.Text;
37 using System.ComponentModel;
38 using System.Web.UI;
39 using System.Web.Handlers;
40 using System.Collections.Specialized;
41 using System.IO;
42 using System.Drawing;
43 using System.Collections.Generic;
44
45 namespace System.Web.UI.WebControls
46 {
47         [DefaultEvent ("MenuItemClick")]
48         [ControlValueProperty ("SelectedValue")]
49         [Designer ("System.Web.UI.Design.WebControls.MenuDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
50         public class Menu : HierarchicalDataBoundControl, IPostBackEventHandler, INamingContainer
51         {
52                 MenuItemStyle dynamicMenuItemStyle;
53                 SubMenuStyle dynamicMenuStyle;
54                 MenuItemStyle dynamicSelectedStyle;
55                 MenuItemStyle staticMenuItemStyle;
56                 SubMenuStyle staticMenuStyle;
57                 MenuItemStyle staticSelectedStyle;
58                 Style staticHoverStyle;
59                 Style dynamicHoverStyle;
60
61                 MenuItemStyleCollection levelMenuItemStyles;
62                 MenuItemStyleCollection levelSelectedStyles;
63                 SubMenuStyleCollection levelSubMenuStyles;
64                 ITemplate staticItemTemplate;
65                 ITemplate dynamicItemTemplate;
66                 
67                 MenuItemCollection items;
68                 MenuItemBindingCollection dataBindings;
69                 MenuItem selectedItem;
70                 string selectedItemPath;
71                 Hashtable bindings;
72
73                 Hashtable _menuItemControls;
74                 bool _requiresChildControlsDataBinding;
75                 SiteMapNode _currSiteMapNode;
76                 int registeredStylesCounter = -1;
77                 List<Style> levelSelectedLinkStyles;
78                 List<Style> levelMenuItemLinkStyles;
79                 Style popOutBoxStyle;
80                 Style controlLinkStyle;
81                 Style dynamicMenuItemLinkStyle;
82                 Style staticMenuItemLinkStyle;
83                 Style dynamicSelectedLinkStyle;
84                 Style staticSelectedLinkStyle;
85                 Style dynamicHoverLinkStyle;
86                 Style staticHoverLinkStyle;
87
88                 private static readonly object MenuItemClickEvent = new object();
89                 private static readonly object MenuItemDataBoundEvent = new object();
90                 
91                 public static readonly string MenuItemClickCommandName = "Click";
92                 
93                 public event MenuEventHandler MenuItemClick {
94                         add { Events.AddHandler (MenuItemClickEvent, value); }
95                         remove { Events.RemoveHandler (MenuItemClickEvent, value); }
96                 }
97                 
98                 public event MenuEventHandler MenuItemDataBound {
99                         add { Events.AddHandler (MenuItemDataBoundEvent, value); }
100                         remove { Events.RemoveHandler (MenuItemDataBoundEvent, value); }
101                 }
102                 
103                 protected virtual void OnMenuItemClick (MenuEventArgs e)
104                 {
105                         if (Events != null) {
106                                 MenuEventHandler eh = (MenuEventHandler) Events [MenuItemClickEvent];
107                                 if (eh != null) eh (this, e);
108                         }
109                 }
110                 
111                 protected virtual void OnMenuItemDataBound (MenuEventArgs e)
112                 {
113                         if (Events != null) {
114                                 MenuEventHandler eh = (MenuEventHandler) Events [MenuItemDataBoundEvent];
115                                 if (eh != null) eh (this, e);
116                         }
117                 }
118
119             [DefaultValueAttribute (null)]
120                 [PersistenceMode (PersistenceMode.InnerProperty)]
121             [EditorAttribute ("System.Web.UI.Design.WebControls.MenuBindingsEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
122             [MergablePropertyAttribute (false)]
123                 public MenuItemBindingCollection DataBindings {
124                         get {
125                                 if (dataBindings == null) {
126                                         dataBindings = new MenuItemBindingCollection ();
127                                         if (IsTrackingViewState)
128                                                 ((IStateManager)dataBindings).TrackViewState();
129                                 }
130                                 return dataBindings;
131                         }
132                 }
133
134                 [DefaultValue (500)]
135                 [ThemeableAttribute (false)]
136                 public int DisappearAfter {
137                         get {
138                                 object o = ViewState ["DisappearAfter"];
139                                 if (o != null) return (int)o;
140                                 return 500;
141                         }
142                         set {
143                                 ViewState["DisappearAfter"] = value;
144                         }
145                 }
146
147                 [ThemeableAttribute (true)]
148                 [DefaultValue ("")]
149                 [UrlProperty]
150                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
151                 public string DynamicBottomSeparatorImageUrl {
152                         get {
153                                 object o = ViewState ["dbsiu"];
154                                 if (o != null) return (string)o;
155                                 return "";
156                         }
157                         set {
158                                 ViewState["dbsiu"] = value;
159                         }
160                 }
161
162             [DefaultValueAttribute ("")]
163                 public string DynamicItemFormatString {
164                         get {
165                                 object o = ViewState ["DynamicItemFormatString"];
166                                 if (o != null) return (string)o;
167                                 return "";
168                         }
169                         set {
170                                 ViewState["DynamicItemFormatString"] = value;
171                         }
172                 }
173
174                 [DefaultValue ("")]
175                 [UrlProperty]
176                 [WebCategory ("Appearance")]
177                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
178                 public string DynamicTopSeparatorImageUrl {
179                         get {
180                                 object o = ViewState ["dtsiu"];
181                                 if (o != null) return (string)o;
182                                 return "";
183                         }
184                         set {
185                                 ViewState["dtsiu"] = value;
186                         }
187                 }
188
189                 [DefaultValue ("")]
190                 [UrlProperty]
191                 [WebCategory ("Appearance")]
192                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
193                 public string StaticBottomSeparatorImageUrl {
194                         get {
195                                 object o = ViewState ["sbsiu"];
196                                 if (o != null) return (string)o;
197                                 return "";
198                         }
199                         set {
200                                 ViewState["sbsiu"] = value;
201                         }
202                 }
203
204                 [DefaultValue ("")]
205                 [UrlProperty]
206                 [WebCategory ("Appearance")]
207                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
208                 public string StaticTopSeparatorImageUrl {
209                         get {
210                                 object o = ViewState ["stsiu"];
211                                 if (o != null) return (string)o;
212                                 return "";
213                         }
214                         set {
215                                 ViewState["stsiu"] = value;
216                         }
217                 }
218
219                 [DefaultValue (Orientation.Vertical)]
220                 public Orientation Orientation {
221                         get {
222                                 object o = ViewState ["Orientation"];
223                                 if (o != null) return (Orientation) o;
224                                 return Orientation.Vertical;
225                         }
226                         set {
227                                 ViewState["Orientation"] = value;
228                         }
229                 }
230
231                 [DefaultValue (1)]
232                 [ThemeableAttribute (true)]
233                 public int StaticDisplayLevels {
234                         get {
235                                 object o = ViewState ["StaticDisplayLevels"];
236                                 if (o != null) return (int)o;
237                                 return 1;
238                         }
239                         set {
240                                 if (value < 1) throw new ArgumentOutOfRangeException ();
241                                 ViewState["StaticDisplayLevels"] = value;
242                         }
243                 }
244
245             [DefaultValueAttribute ("")]
246                 public string StaticItemFormatString {
247                         get {
248                                 object o = ViewState ["StaticItemFormatString"];
249                                 if (o != null) return (string)o;
250                                 return "";
251                         }
252                         set {
253                                 ViewState["StaticItemFormatString"] = value;
254                         }
255                 }
256
257                 [DefaultValue (typeof (Unit), "16px")]
258                 [ThemeableAttribute (true)]
259                 public Unit StaticSubMenuIndent {
260                         get {
261                                 object o = ViewState ["StaticSubMenuIndent"];
262                                 if (o != null) return (Unit)o;
263                                 return new Unit (16);
264                         }
265                         set {
266                                 ViewState["StaticSubMenuIndent"] = value;
267                         }
268                 }
269
270                 [ThemeableAttribute (true)]
271                 [DefaultValue (3)]
272                 public int MaximumDynamicDisplayLevels {
273                         get {
274                                 object o = ViewState ["MaximumDynamicDisplayLevels"];
275                                 if (o != null) return (int)o;
276                                 return 3;
277                         }
278                         set {
279                                 if (value < 0) throw new ArgumentOutOfRangeException ();
280                                 ViewState["MaximumDynamicDisplayLevels"] = value;
281                         }
282                 }
283
284                 [DefaultValue (0)]
285                 public int DynamicVerticalOffset {
286                         get {
287                                 object o = ViewState ["DynamicVerticalOffset"];
288                                 if (o != null) return (int)o;
289                                 return 0;
290                         }
291                         set {
292                                 ViewState["DynamicVerticalOffset"] = value;
293                         }
294                 }
295
296                 [DefaultValue (0)]
297                 public int DynamicHorizontalOffset {
298                         get {
299                                 object o = ViewState ["DynamicHorizontalOffset"];
300                                 if (o != null) return (int)o;
301                                 return 0;
302                         }
303                         set {
304                                 ViewState["DynamicHorizontalOffset"] = value;
305                         }
306                 }
307
308                 [DefaultValue (true)]
309                 public bool DynamicEnableDefaultPopOutImage {
310                         get {
311                                 object o = ViewState ["dedpoi"];
312                                 if (o != null) return (bool)o;
313                                 return true;
314                         }
315                         set {
316                                 ViewState["dedpoi"] = value;
317                         }
318                 }
319
320                 [DefaultValue (true)]
321                 public bool StaticEnableDefaultPopOutImage {
322                         get {
323                                 object o = ViewState ["sedpoi"];
324                                 if (o != null) return (bool)o;
325                                 return true;
326                         }
327                         set {
328                                 ViewState["sedpoi"] = value;
329                         }
330                 }
331
332                 [DefaultValueAttribute (null)]
333                 [PersistenceMode (PersistenceMode.InnerProperty)]
334                 [Editor ("System.Web.UI.Design.MenuItemCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
335                 [MergablePropertyAttribute (false)]
336                 public MenuItemCollection Items {
337                         get {
338                                 if (items == null) {
339                                         items = new MenuItemCollection (this);
340                                         if (IsTrackingViewState)
341                                                 ((IStateManager)items).TrackViewState();
342                                 }
343                                 return items;
344                         }
345                 }
346
347                 [DefaultValue ('/')]
348                 public char PathSeparator {
349                         get {
350                                 object o = ViewState ["PathSeparator"];
351                                 if(o != null) return (char)o;
352                                 return '/';
353                         }
354                         set {
355                                 ViewState ["PathSeparator"] = value;
356                         }
357                 }
358
359                 [DefaultValue (false)]
360                 public bool ItemWrap {
361                         get {
362                                 object o = ViewState ["ItemWrap"];
363                                 if(o != null) return (bool)o;
364                                 return false;
365                         }
366                         set {
367                                 ViewState ["ItemWrap"] = value;
368                         }
369                 }
370
371                 private Style PopOutBoxStyle {
372                         get {
373                                 if (popOutBoxStyle == null) {
374                                         popOutBoxStyle = new Style ();
375                                         popOutBoxStyle.BackColor = Color.White;
376                                 }
377                                 return popOutBoxStyle;
378                         }
379                 }
380
381                 private Style ControlLinkStyle {
382                         get {
383                                 if (controlLinkStyle == null) {
384                                         controlLinkStyle = new Style ();
385                                         controlLinkStyle.AlwaysRenderTextDecoration = true;
386                                 }
387                                 return controlLinkStyle;
388                         }
389                 }
390
391                 private Style DynamicMenuItemLinkStyle {
392                         get {
393                                 if (dynamicMenuItemLinkStyle == null) {
394                                         dynamicMenuItemLinkStyle = new Style ();
395                                 }
396                                 return dynamicMenuItemLinkStyle;
397                         }
398                 }
399
400                 private Style StaticMenuItemLinkStyle {
401                         get {
402                                 if (staticMenuItemLinkStyle == null) {
403                                         staticMenuItemLinkStyle = new Style ();
404                                 }
405                                 return staticMenuItemLinkStyle;
406                         }
407                 }
408
409                 private Style DynamicSelectedLinkStyle {
410                         get {
411                                 if (dynamicSelectedLinkStyle == null) {
412                                         dynamicSelectedLinkStyle = new Style ();
413                                 }
414                                 return dynamicSelectedLinkStyle;
415                         }
416                 }
417
418                 private Style StaticSelectedLinkStyle {
419                         get {
420                                 if (staticSelectedLinkStyle == null) {
421                                         staticSelectedLinkStyle = new Style ();
422                                 }
423                                 return staticSelectedLinkStyle;
424                         }
425                 }
426
427                 private Style DynamicHoverLinkStyle {
428                         get {
429                                 if (dynamicHoverLinkStyle == null) {
430                                         dynamicHoverLinkStyle = new Style ();
431                                 }
432                                 return dynamicHoverLinkStyle;
433                         }
434                 }
435
436                 private Style StaticHoverLinkStyle {
437                         get {
438                                 if (staticHoverLinkStyle == null) {
439                                         staticHoverLinkStyle = new Style ();
440                                 }
441                                 return staticHoverLinkStyle;
442                         }
443                 }
444
445                 [PersistenceMode (PersistenceMode.InnerProperty)]
446                 [NotifyParentProperty (true)]
447                 [DefaultValue (null)]
448                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
449                 public MenuItemStyle DynamicMenuItemStyle {
450                         get {
451                                 if (dynamicMenuItemStyle == null) {
452                                         dynamicMenuItemStyle = new MenuItemStyle ();
453                                         if (IsTrackingViewState)
454                                                 dynamicMenuItemStyle.TrackViewState();
455                                 }
456                                 return dynamicMenuItemStyle;
457                         }
458                 }
459                 
460                 [PersistenceMode (PersistenceMode.InnerProperty)]
461                 [NotifyParentProperty (true)]
462                 [DefaultValue (null)]
463                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
464                 public MenuItemStyle DynamicSelectedStyle {
465                         get {
466                                 if (dynamicSelectedStyle == null) {
467                                         dynamicSelectedStyle = new MenuItemStyle ();
468                                         if (IsTrackingViewState)
469                                                 dynamicSelectedStyle.TrackViewState();
470                                 }
471                                 return dynamicSelectedStyle;
472                         }
473                 }
474                 
475                 [PersistenceMode (PersistenceMode.InnerProperty)]
476                 [NotifyParentProperty (true)]
477                 [DefaultValue (null)]
478                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
479                 public SubMenuStyle DynamicMenuStyle {
480                         get {
481                                 if (dynamicMenuStyle == null) {
482                                         dynamicMenuStyle = new SubMenuStyle ();
483                                         if (IsTrackingViewState)
484                                                 dynamicMenuStyle.TrackViewState();
485                                 }
486                                 return dynamicMenuStyle;
487                         }
488                 }
489                 
490                 [PersistenceMode (PersistenceMode.InnerProperty)]
491                 [NotifyParentProperty (true)]
492                 [DefaultValue (null)]
493                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
494                 public MenuItemStyle StaticMenuItemStyle {
495                         get {
496                                 if (staticMenuItemStyle == null) {
497                                         staticMenuItemStyle = new MenuItemStyle ();
498                                         if (IsTrackingViewState)
499                                                 staticMenuItemStyle.TrackViewState();
500                                 }
501                                 return staticMenuItemStyle;
502                         }
503                 }
504                 
505                 [PersistenceMode (PersistenceMode.InnerProperty)]
506                 [NotifyParentProperty (true)]
507                 [DefaultValue (null)]
508                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
509                 public MenuItemStyle StaticSelectedStyle {
510                         get {
511                                 if (staticSelectedStyle == null) {
512                                         staticSelectedStyle = new MenuItemStyle ();
513                                         if (IsTrackingViewState)
514                                                 staticSelectedStyle.TrackViewState();
515                                 }
516                                 return staticSelectedStyle;
517                         }
518                 }
519                 
520                 [PersistenceMode (PersistenceMode.InnerProperty)]
521                 [NotifyParentProperty (true)]
522                 [DefaultValue (null)]
523                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
524                 public SubMenuStyle StaticMenuStyle {
525                         get {
526                                 if (staticMenuStyle == null) {
527                                         staticMenuStyle = new SubMenuStyle ();
528                                         if (IsTrackingViewState)
529                                                 staticMenuStyle.TrackViewState();
530                                 }
531                                 return staticMenuStyle;
532                         }
533                 }
534
535                 [DefaultValue (null)]
536                 [PersistenceMode (PersistenceMode.InnerProperty)]
537             [Editor ("System.Web.UI.Design.WebControls.MenuItemStyleCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
538                 public MenuItemStyleCollection LevelMenuItemStyles {
539                         get {
540                                 if (levelMenuItemStyles == null) {
541                                         levelMenuItemStyles = new MenuItemStyleCollection ();
542                                         if (IsTrackingViewState)
543                                                 ((IStateManager)levelMenuItemStyles).TrackViewState();
544                                 }
545                                 return levelMenuItemStyles;
546                         }
547                 }
548
549                 [DefaultValue (null)]
550                 [PersistenceMode (PersistenceMode.InnerProperty)]
551             [Editor ("System.Web.UI.Design.WebControls.MenuItemStyleCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
552                 public MenuItemStyleCollection LevelSelectedStyles {
553                         get {
554                                 if (levelSelectedStyles == null) {
555                                         levelSelectedStyles = new MenuItemStyleCollection ();
556                                         if (IsTrackingViewState)
557                                                 ((IStateManager)levelSelectedStyles).TrackViewState();
558                                 }
559                                 return levelSelectedStyles;
560                         }
561                 }
562
563                 [DefaultValue (null)]
564                 [PersistenceMode (PersistenceMode.InnerProperty)]
565             [Editor ("System.Web.UI.Design.WebControls.SubMenuStyleCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
566                 public SubMenuStyleCollection LevelSubMenuStyles {
567                         get {
568                                 if (levelSubMenuStyles == null) {
569                                         levelSubMenuStyles = new SubMenuStyleCollection ();
570                                         if (IsTrackingViewState)
571                                                 ((IStateManager)levelSubMenuStyles).TrackViewState();
572                                 }
573                                 return levelSubMenuStyles;
574                         }
575                 }
576
577                 [PersistenceMode (PersistenceMode.InnerProperty)]
578                 [NotifyParentProperty (true)]
579                 [DefaultValue (null)]
580                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
581                 public Style DynamicHoverStyle {
582                         get {
583                                 if (dynamicHoverStyle == null) {
584                                         dynamicHoverStyle = new Style ();
585                                         if (IsTrackingViewState)
586                                                 dynamicHoverStyle.TrackViewState();
587                                 }
588                                 return dynamicHoverStyle;
589                         }
590                 }
591                 
592                 [PersistenceMode (PersistenceMode.InnerProperty)]
593                 [NotifyParentProperty (true)]
594                 [DefaultValue (null)]
595                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
596                 public Style StaticHoverStyle {
597                         get {
598                                 if (staticHoverStyle == null) {
599                                         staticHoverStyle = new Style ();
600                                         if (IsTrackingViewState)
601                                                 staticHoverStyle.TrackViewState();
602                                 }
603                                 return staticHoverStyle;
604                         }
605                 }
606                 
607                 [DefaultValue ("")]
608                 [UrlProperty]
609                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
610                 public string ScrollDownImageUrl {
611                         get {
612                                 object o = ViewState ["sdiu"];
613                                 if (o != null) return (string)o;
614                                 return "";
615                         }
616                         set {
617                                 ViewState["sdiu"] = value;
618                         }
619                 }
620
621                 [DefaultValue ("")]
622                 [UrlProperty]
623                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
624                 public string ScrollUpImageUrl {
625                         get {
626                                 object o = ViewState ["suiu"];
627                                 if (o != null) return (string)o;
628                                 return "";
629                         }
630                         set {
631                                 ViewState["suiu"] = value;
632                         }
633                 }
634
635                 [Localizable (true)]
636                 public string ScrollDownText {
637                         get {
638                                 object o = ViewState ["ScrollDownText"];
639                                 if (o != null) return (string) o;
640                                 return Locale.GetText ("Scroll down");
641                         }
642                         set {
643                                 ViewState["ScrollDownText"] = value;
644                         }
645                 }
646
647                 [Localizable (true)]
648                 public string ScrollUpText {
649                         get {
650                                 object o = ViewState ["ScrollUpText"];
651                                 if (o != null) return (string) o;
652                                 return Locale.GetText ("Scroll up");
653                         }
654                         set {
655                                 ViewState["ScrollUpText"] = value;
656                         }
657                 }
658
659                 public string DynamicPopOutImageTextFormatString 
660                 {
661                         get
662                         {
663                                 object o = ViewState ["dpoitf"];
664                                 if (o != null) return (string) o;
665                                 return Locale.GetText ("Expand {0}");
666                         }
667                         set
668                         {
669                                 ViewState ["dpoitf"] = value;
670                         }
671                 }
672                 
673
674                 [DefaultValue ("")]
675                 [UrlProperty]
676                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
677                 public string DynamicPopOutImageUrl {
678                         get {
679                                 object o = ViewState ["dpoiu"];
680                                 if (o != null) return (string)o;
681                                 return "";
682                         }
683                         set {
684                                 ViewState["dpoiu"] = value;
685                         }
686                 }
687
688                 public string StaticPopOutImageTextFormatString
689                 {
690                         get
691                         {
692                                 object o = ViewState ["spoitf"];
693                                 if (o != null) return (string) o;
694                                 return Locale.GetText ("Expand {0}");
695                         }
696                         set
697                         {
698                                 ViewState ["spoitf"] = value;
699                         }
700                 }
701                 
702
703                 [DefaultValue ("")]
704                 [UrlProperty]
705                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
706                 public string StaticPopOutImageUrl {
707                         get {
708                                 object o = ViewState ["spoiu"];
709                                 if (o != null) return (string)o;
710                                 return "";
711                         }
712                         set {
713                                 ViewState["spoiu"] = value;
714                         }
715                 }
716
717                 [DefaultValue ("")]
718                 public string Target {
719                         get {
720                                 object o = ViewState ["Target"];
721                                 if (o != null) return (string) o;
722                                 return "";
723                         }
724                         set {
725                                 ViewState["Target"] = value;
726                         }
727                 }
728
729                 [DefaultValue (null)]
730                 [TemplateContainer (typeof(MenuItemTemplateContainer), BindingDirection.OneWay)]
731                 [PersistenceMode (PersistenceMode.InnerProperty)]
732             [Browsable (false)]
733                 public ITemplate StaticItemTemplate {
734                         get { return staticItemTemplate; }
735                         set { staticItemTemplate = value; }
736                 }
737                 
738                 [DefaultValue (null)]
739                 [TemplateContainer (typeof(MenuItemTemplateContainer), BindingDirection.OneWay)]
740                 [PersistenceMode (PersistenceMode.InnerProperty)]
741             [Browsable (false)]
742                 public ITemplate DynamicItemTemplate {
743                         get { return dynamicItemTemplate; }
744                         set { dynamicItemTemplate = value; }
745                 }
746                 
747                 [Browsable (false)]
748                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
749                 public MenuItem SelectedItem {
750                         get {
751                                 if (selectedItem == null && selectedItemPath != null) {
752                                         selectedItem = FindItemByPos (selectedItemPath);
753                                 }
754                                 
755                                 return selectedItem;
756                         }
757                 }
758
759                 [Browsable (false)]
760                 [DefaultValue ("")]
761                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
762                 public string SelectedValue {
763                         get { return selectedItem != null ? selectedItem.Value : ""; }
764                 }
765
766                 [Localizable (true)]
767                 public string SkipLinkText 
768                 {
769                         get {
770                                 object o = ViewState ["SkipLinkText"];
771                                 if (o != null)
772                                         return (string) o;
773                                 return "Skip Navigation Links";
774                         }
775                         set {
776                                 ViewState ["SkipLinkText"] = value;
777                         }
778                 }
779                 
780
781                 internal void SetSelectedItem (MenuItem item)
782                 {
783                         if (selectedItem == item) return;
784                         selectedItem = item;
785                         selectedItemPath = item.Path;
786                 }
787                 
788                 public MenuItem FindItem (string valuePath)
789                 {
790                         if (valuePath == null) throw new ArgumentNullException ("valuePath");
791                         string[] path = valuePath.Split (PathSeparator);
792                         int n = 0;
793                         MenuItemCollection col = Items;
794                         bool foundBranch = true;
795                         while (col.Count > 0 && foundBranch) {
796                                 foundBranch = false;
797                                 foreach (MenuItem item in col) {
798                                         if (item.Value == path [n]) {
799                                                 if (++n == path.Length) return item;
800                                                 col = item.ChildItems;
801                                                 foundBranch = true;
802                                                 break;
803                                         }
804                                 }
805                         }
806                         return null;
807                 }
808                 
809                 string GetBindingKey (string dataMember, int depth)
810                 {
811                         return dataMember + " " + depth;
812                 }
813                 
814                 internal MenuItemBinding FindBindingForItem (string type, int depth)
815                 {
816                         if (bindings == null) return null;
817
818                         MenuItemBinding bin = (MenuItemBinding) bindings [GetBindingKey (type, depth)];
819                         if (bin != null) return bin;
820                         
821                         bin = (MenuItemBinding) bindings [GetBindingKey (type, -1)];
822                         if (bin != null) return bin;
823                         
824                         bin = (MenuItemBinding) bindings [GetBindingKey ("", depth)];
825                         if (bin != null) return bin;
826                         
827                         bin = (MenuItemBinding) bindings [GetBindingKey ("", -1)];
828                         return bin;
829                 }
830                 
831                 protected internal override void PerformDataBinding ()
832                 {
833                         base.PerformDataBinding ();
834
835                         // Do not attempt to bind data if there is no
836                         // data source set.
837                         if (!IsBoundUsingDataSourceID && (DataSource == null)) {
838                                 EnsureChildControlsDataBound ();
839                                 return;
840                         }
841
842                         InitializeDataBindings ();
843
844                         HierarchicalDataSourceView data = GetData ("");
845
846                         if (data == null) {
847                                 throw new InvalidOperationException ("No view returned by data source control.");
848                         }
849                         Items.Clear ();
850                         IHierarchicalEnumerable e = data.Select ();
851                         FillBoundChildrenRecursive (e, Items);
852
853                         CreateChildControlsForItems ();
854                         ChildControlsCreated = true;
855
856                         EnsureChildControlsDataBound ();
857                 }
858
859                 private void FillBoundChildrenRecursive (IHierarchicalEnumerable hEnumerable, MenuItemCollection itemCollection)
860                 {
861                         if (hEnumerable == null)
862                                 return;
863                         foreach (object obj in hEnumerable) {
864                                 IHierarchyData hdata = hEnumerable.GetHierarchyData (obj);
865                                 MenuItem item = new MenuItem ();
866                                 itemCollection.Add (item);
867                                 item.Bind (hdata);
868
869                                 SiteMapNode siteMapNode = hdata as SiteMapNode;
870                                 if (siteMapNode != null) {
871                                         if (_currSiteMapNode == null)
872                                                 _currSiteMapNode = siteMapNode.Provider.CurrentNode;
873                                         if (siteMapNode == _currSiteMapNode)
874                                                 item.Selected = true;
875                                 }
876                                 
877                                 OnMenuItemDataBound (new MenuEventArgs (item));
878
879                                 if (hdata == null || !hdata.HasChildren)
880                                         continue;
881
882                                 IHierarchicalEnumerable e = hdata.GetChildren ();
883                                 FillBoundChildrenRecursive (e, item.ChildItems);
884                         }
885                 }
886                 
887                 protected void SetItemDataBound (MenuItem node, bool dataBound)
888                 {
889                         node.SetDataBound (dataBound);
890                 }
891                 
892                 protected void SetItemDataPath (MenuItem node, string dataPath)
893                 {
894                         node.SetDataPath (dataPath);
895                 }
896                 
897                 protected void SetItemDataItem (MenuItem node, object dataItem)
898                 {
899                         node.SetDataItem (dataItem);
900                 }
901                 
902                 protected internal virtual void RaisePostBackEvent (string eventArgument)
903                 {
904                         if (!Enabled)
905                                 return;
906
907                         EnsureChildControls();
908                         MenuItem item = FindItemByPos (eventArgument);
909                         if (item == null) return;
910                         item.Selected = true;
911                         OnMenuItemClick (new MenuEventArgs (item));
912                 }
913
914                 void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
915                 {
916                         RaisePostBackEvent (eventArgument);
917                 }
918                 
919                 MenuItem FindItemByPos (string path)
920                 {
921                         string[] indexes = path.Split ('_');
922                         MenuItem item = null;
923                         
924                         foreach (string index in indexes) {
925                                 int i = int.Parse (index);
926                                 if (item == null) {
927                                         if (i >= Items.Count) return null;
928                                         item = Items [i];
929                                 } else {
930                                         if (i >= item.ChildItems.Count) return null;
931                                         item = item.ChildItems [i];
932                                 }
933                         }
934                         return item;
935                 }
936                 
937                 protected override HtmlTextWriterTag TagKey {
938                         get { return HtmlTextWriterTag.Table; }
939                 }
940                 
941                 protected override void TrackViewState()
942                 {
943                         EnsureDataBound ();
944                         
945                         base.TrackViewState();
946                         if (dataBindings != null) {
947                                 ((IStateManager)dataBindings).TrackViewState ();
948                         }
949                         if (items != null) {
950                                 ((IStateManager)items).TrackViewState();
951                         }
952                         if (dynamicMenuItemStyle != null)
953                                 dynamicMenuItemStyle.TrackViewState ();
954                         if (dynamicMenuStyle != null)
955                                 dynamicMenuStyle.TrackViewState ();
956                         if (levelMenuItemStyles != null && levelMenuItemStyles.Count > 0)
957                                 ((IStateManager)levelMenuItemStyles).TrackViewState();
958                         if (levelSelectedStyles != null && levelMenuItemStyles.Count > 0)
959                                 ((IStateManager)levelSelectedStyles).TrackViewState();
960                         if (levelSubMenuStyles != null && levelSubMenuStyles.Count > 0)
961                                 ((IStateManager)levelSubMenuStyles).TrackViewState();
962                         if (dynamicSelectedStyle != null)
963                                 dynamicSelectedStyle.TrackViewState();
964                         if (staticMenuItemStyle != null)
965                                 staticMenuItemStyle.TrackViewState ();
966                         if (staticMenuStyle != null)
967                                 staticMenuStyle.TrackViewState ();
968                         if (staticSelectedStyle != null)
969                                 staticSelectedStyle.TrackViewState();
970                         if (staticHoverStyle != null)
971                                 staticHoverStyle.TrackViewState();
972                         if (dynamicHoverStyle != null)
973                                 dynamicHoverStyle.TrackViewState();
974                 }
975
976                 protected override object SaveViewState()
977                 {
978                         object[] states = new object [14];
979                         states[0] = base.SaveViewState ();
980                         states[1] = dataBindings == null ? null : ((IStateManager)dataBindings).SaveViewState();
981                         states[2] = items == null ? null : ((IStateManager)items).SaveViewState();
982                         states[3] = dynamicMenuItemStyle == null ? null : dynamicMenuItemStyle.SaveViewState();
983                         states[4] = dynamicMenuStyle == null ? null : dynamicMenuStyle.SaveViewState();
984                         states[5] = levelMenuItemStyles == null ? null : ((IStateManager)levelMenuItemStyles).SaveViewState();
985                         states[6] = levelSelectedStyles == null ? null : ((IStateManager)levelSelectedStyles).SaveViewState();
986                         states[7] = dynamicSelectedStyle == null ? null : dynamicSelectedStyle.SaveViewState();
987                         states[8] = (staticMenuItemStyle == null ? null : staticMenuItemStyle.SaveViewState());
988                         states[9] = staticMenuStyle == null ? null : staticMenuStyle.SaveViewState();
989                         states[10] = staticSelectedStyle == null ? null : staticSelectedStyle.SaveViewState();
990                         states[11] = staticHoverStyle == null ? null : staticHoverStyle.SaveViewState();
991                         states[12] = dynamicHoverStyle == null ? null : dynamicHoverStyle.SaveViewState();
992                         states[13] = levelSubMenuStyles == null ? null : ((IStateManager)levelSubMenuStyles).SaveViewState();
993
994                         for (int i = states.Length - 1; i >= 0; i--) {
995                                 if (states [i] != null)
996                                         return states;
997                         }
998
999                         return null;
1000                 }
1001
1002                 protected override void LoadViewState (object savedState)
1003                 {
1004                         if (savedState == null)
1005                                 return;
1006
1007                         object [] states = (object []) savedState;
1008                         base.LoadViewState (states[0]);
1009                         
1010                         if (states[1] != null)
1011                                 ((IStateManager)DataBindings).LoadViewState(states[1]);
1012                         if (states[2] != null)
1013                                 ((IStateManager)Items).LoadViewState(states[2]);
1014                         if (states[3] != null)
1015                                 DynamicMenuItemStyle.LoadViewState (states[3]);
1016                         if (states[4] != null)
1017                                 DynamicMenuStyle.LoadViewState (states[4]);
1018                         if (states[5] != null)
1019                                 ((IStateManager)LevelMenuItemStyles).LoadViewState(states[5]);
1020                         if (states[6] != null)
1021                                 ((IStateManager)LevelSelectedStyles).LoadViewState(states[6]);
1022                         if (states[7] != null)
1023                                 DynamicSelectedStyle.LoadViewState (states[7]);
1024                         if (states[8] != null)
1025                                 StaticMenuItemStyle.LoadViewState (states[8]);
1026                         if (states[9] != null)
1027                                 StaticMenuStyle.LoadViewState (states[9]);
1028                         if (states[10] != null)
1029                                 StaticSelectedStyle.LoadViewState (states[10]);
1030                         if (states[11] != null)
1031                                 StaticHoverStyle.LoadViewState (states[11]);
1032                         if (states[12] != null)
1033                                 DynamicHoverStyle.LoadViewState (states[12]);
1034                         if (states[13] != null)
1035                                 ((IStateManager)LevelSubMenuStyles).LoadViewState(states[13]);
1036                 }
1037                 
1038                 protected internal override void OnInit (EventArgs e)
1039                 {
1040                         Page.RegisterRequiresControlState (this);
1041                         base.OnInit (e);
1042                 }
1043                 
1044                 protected internal override void LoadControlState (object ob)
1045                 {
1046                         if (ob == null) return;
1047                         object[] state = (object[]) ob;
1048                         base.LoadControlState (state[0]);
1049                         selectedItemPath = state[1] as string;
1050                 }
1051                 
1052                 protected internal override object SaveControlState ()
1053                 {
1054                         object bstate = base.SaveControlState ();
1055                         object mstate = selectedItemPath;
1056                         
1057                         if (bstate != null || mstate != null)
1058                                 return new object[] { bstate, mstate };
1059                         else
1060                                 return null;
1061                 }
1062                 
1063                 protected internal override void CreateChildControls ()
1064                 {
1065                         if (!IsBoundUsingDataSourceID && (DataSource == null)) {
1066                                 CreateChildControlsForItems ();
1067                         }
1068                         else {
1069                                 EnsureDataBound ();
1070                         }
1071                 }
1072
1073                 private void CreateChildControlsForItems () {
1074                         Controls.Clear ();
1075                         // Check for HasChildViewState to avoid unnecessary calls to ClearChildViewState.
1076                         if (HasChildViewState)
1077                                 ClearChildViewState ();
1078                         _menuItemControls = new Hashtable ();
1079                         CreateChildControlsForItems (Items);
1080                         _requiresChildControlsDataBinding = true;
1081                 }
1082
1083                 private void CreateChildControlsForItems (MenuItemCollection items ) {
1084                         foreach (MenuItem item in items) {
1085                                 bool isDynamicItem = IsDynamicItem (item);
1086                                 if (isDynamicItem && dynamicItemTemplate != null) {
1087                                         MenuItemTemplateContainer cter = new MenuItemTemplateContainer (item.Index, item);
1088                                         dynamicItemTemplate.InstantiateIn (cter);
1089                                         _menuItemControls [item] = cter;
1090                                         Controls.Add (cter);
1091                                 }
1092                                 else if (!isDynamicItem && staticItemTemplate != null) {
1093                                         MenuItemTemplateContainer cter = new MenuItemTemplateContainer (item.Index, item);
1094                                         staticItemTemplate.InstantiateIn (cter);
1095                                         _menuItemControls [item] = cter;
1096                                         Controls.Add (cter);
1097                                 }
1098                                 if (item.HasChildData)
1099                                         CreateChildControlsForItems (item.ChildItems);
1100                         }
1101                 }
1102
1103                 protected override void EnsureDataBound ()
1104                 {
1105                         base.EnsureDataBound ();
1106                         
1107                         EnsureChildControlsDataBound ();
1108                 }
1109
1110                 private void EnsureChildControlsDataBound () {
1111                         if (!_requiresChildControlsDataBinding)
1112                                 return;
1113                         DataBindChildren ();
1114                         _requiresChildControlsDataBinding = false;
1115                 }
1116
1117                 [MonoTODO ("Not implemented")]
1118                 protected override IDictionary GetDesignModeState ()
1119                 {
1120                         throw new NotImplementedException ();
1121                 }
1122
1123                 [MonoTODO ("Not implemented")]
1124                 protected override void SetDesignModeState (IDictionary data)
1125                 {
1126                         throw new NotImplementedException ();
1127                 }
1128                                 
1129                 public override ControlCollection Controls {
1130                         get { return base.Controls; }
1131                 }
1132                 
1133                 public sealed override void DataBind ()
1134                 {
1135                         base.DataBind ();
1136                 }
1137                 
1138                 protected override bool OnBubbleEvent (object source, EventArgs args)
1139                 {
1140                         if (!(args is CommandEventArgs))
1141                                 return false;
1142
1143                         MenuEventArgs menuArgs = args as MenuEventArgs;
1144                         if (menuArgs != null && string.Equals (menuArgs.CommandName, MenuItemClickCommandName))
1145                                 OnMenuItemClick (menuArgs);
1146                         return true;
1147                 }
1148
1149                 protected override void OnDataBinding (EventArgs e)
1150                 {
1151                         EnsureChildControls ();
1152                         base.OnDataBinding (e);
1153                 }
1154
1155                 const string onPreRenderScript = "var {0} = new Object ();\n{0}.webForm = {1};\n{0}.disappearAfter = {2};\n{0}.vertical = {3};";
1156                 
1157                 protected internal override void OnPreRender (EventArgs e)
1158                 {
1159                         base.OnPreRender (e);
1160                         
1161                         if (!Page.ClientScript.IsClientScriptIncludeRegistered (typeof(Menu), "Menu.js")) {
1162                                 string url = Page.ClientScript.GetWebResourceUrl (typeof(Menu), "Menu.js");
1163                                 Page.ClientScript.RegisterClientScriptInclude (typeof(Menu), "Menu.js", url);
1164                         }
1165                         
1166                         string cmenu = ClientID + "_data";
1167                         string script = String.Format (onPreRenderScript,
1168                                                        cmenu,
1169                                                        Page.IsMultiForm ? Page.theForm : "window",
1170                                                        ClientScriptManager.GetScriptLiteral (DisappearAfter),
1171                                                        ClientScriptManager.GetScriptLiteral (Orientation == Orientation.Vertical));                     
1172
1173                         if (DynamicHorizontalOffset != 0)
1174                                 script += String.Concat (cmenu, ".dho = ", ClientScriptManager.GetScriptLiteral (DynamicHorizontalOffset), ";\n");
1175                         if (DynamicVerticalOffset != 0)
1176                                 script += String.Concat (cmenu, ".dvo = ", ClientScriptManager.GetScriptLiteral (DynamicVerticalOffset), ";\n");
1177                         
1178                         // The order in which styles are defined matters when more than one class
1179                         // is assigned to an element
1180                         RegisterStyle (PopOutBoxStyle);
1181                         RegisterStyle (ControlStyle, ControlLinkStyle);
1182                         
1183                         if (staticMenuItemStyle != null)
1184                                 RegisterStyle (StaticMenuItemStyle, StaticMenuItemLinkStyle);
1185
1186                         if (staticMenuStyle != null)
1187                                 RegisterStyle (StaticMenuStyle);
1188                         
1189                         if (dynamicMenuItemStyle != null)
1190                                 RegisterStyle (DynamicMenuItemStyle, DynamicMenuItemLinkStyle);
1191
1192                         if (dynamicMenuStyle != null)
1193                                 RegisterStyle (DynamicMenuStyle);
1194
1195                         if (levelMenuItemStyles != null && levelMenuItemStyles.Count > 0) {
1196                                 levelMenuItemLinkStyles = new List<Style> (levelMenuItemStyles.Count);
1197                                 foreach (Style style in levelMenuItemStyles) {
1198                                         Style linkStyle = new Style ();
1199                                         levelMenuItemLinkStyles.Add (linkStyle);
1200                                         RegisterStyle (style, linkStyle);
1201                                 }
1202                         }
1203                 
1204                         if (levelSubMenuStyles != null)
1205                                 foreach (Style style in levelSubMenuStyles)
1206                                         RegisterStyle (style);
1207
1208                         if (staticSelectedStyle != null)
1209                                 RegisterStyle (staticSelectedStyle, StaticSelectedLinkStyle);
1210                         
1211                         if (dynamicSelectedStyle != null)
1212                                 RegisterStyle (dynamicSelectedStyle, DynamicSelectedLinkStyle);
1213
1214                         if (levelSelectedStyles != null && levelSelectedStyles.Count > 0) {
1215                                 levelSelectedLinkStyles = new List<Style> (levelSelectedStyles.Count);
1216                                 foreach (Style style in levelSelectedStyles) {
1217                                         Style linkStyle = new Style ();
1218                                         levelSelectedLinkStyles.Add (linkStyle);
1219                                         RegisterStyle (style, linkStyle);
1220                                 }
1221                         }
1222                         
1223                         if (staticHoverStyle != null) {
1224                                 if (Page.Header == null)
1225                                         throw new InvalidOperationException ("Using Menu.StaticHoverStyle requires Page.Header to be non-null (e.g. <head runat=\"server\" />).");
1226                                 RegisterStyle (staticHoverStyle, StaticHoverLinkStyle);
1227                                 script += string.Concat (cmenu, ".staticHover = ", ClientScriptManager.GetScriptLiteral (staticHoverStyle.RegisteredCssClass), ";\n");
1228                                 script += string.Concat (cmenu, ".staticLinkHover = ", ClientScriptManager.GetScriptLiteral (StaticHoverLinkStyle.RegisteredCssClass), ";\n");
1229                         }
1230                         
1231                         if (dynamicHoverStyle != null) {
1232                                 if (Page.Header == null)
1233                                         throw new InvalidOperationException ("Using Menu.DynamicHoverStyle requires Page.Header to be non-null (e.g. <head runat=\"server\" />).");
1234                                 RegisterStyle (dynamicHoverStyle, DynamicHoverLinkStyle);
1235                                 script += string.Concat (cmenu, ".dynamicHover = ", ClientScriptManager.GetScriptLiteral (dynamicHoverStyle.RegisteredCssClass), ";\n");
1236                                 script += string.Concat (cmenu, ".dynamicLinkHover = ", ClientScriptManager.GetScriptLiteral (DynamicHoverLinkStyle.RegisteredCssClass), ";\n");
1237                         }
1238
1239                         Page.ClientScript.RegisterWebFormClientScript ();
1240                         Page.ClientScript.RegisterStartupScript (typeof(Menu), ClientID, script, true);
1241
1242                 }
1243
1244                 void InitializeDataBindings () {
1245                         if (dataBindings != null && dataBindings.Count > 0) {
1246                                 bindings = new Hashtable ();
1247                                 foreach (MenuItemBinding bin in dataBindings) {
1248                                         string key = GetBindingKey (bin.DataMember, bin.Depth);
1249                                         bindings [key] = bin;
1250                                 }
1251                         }
1252                         else
1253                                 bindings = null;
1254                 }
1255
1256                 string IncrementStyleClassName () {
1257                         registeredStylesCounter++;
1258                         return ClientID + "_" + registeredStylesCounter;
1259                 }
1260
1261                 void RegisterStyle (Style baseStyle, Style linkStyle) {
1262                         linkStyle.CopyTextStylesFrom (baseStyle);
1263                         linkStyle.BorderStyle = BorderStyle.None;
1264                         RegisterStyle (linkStyle);
1265                         RegisterStyle (baseStyle);
1266                 }
1267
1268                 void RegisterStyle (Style baseStyle)
1269                 {
1270                         if (Page.Header == null)
1271                                 return;
1272                         string className = IncrementStyleClassName ();
1273                         baseStyle.SetRegisteredCssClass (className);
1274                         Page.Header.StyleSheet.CreateStyleRule (baseStyle, this, "." + className);
1275                 }
1276                 
1277                 protected internal override void Render (HtmlTextWriter writer)
1278                 {
1279                         if (Items.Count > 0)
1280                                 base.Render (writer);
1281                 }
1282                 
1283                 protected override void AddAttributesToRender (HtmlTextWriter writer)
1284                 {
1285                         writer.AddAttribute ("cellpadding", "0", false);
1286                         writer.AddAttribute ("cellspacing", "0", false);
1287                         writer.AddAttribute ("border", "0", false);
1288                         if (Page.Header != null) {
1289                                 // styles are registered
1290                                 if (staticMenuStyle != null) {
1291                                         AddCssClass (ControlStyle, staticMenuStyle.CssClass);
1292                                         AddCssClass (ControlStyle, staticMenuStyle.RegisteredCssClass);
1293                                 }
1294                                 if (levelSubMenuStyles != null && levelSubMenuStyles.Count > 0) {
1295                                         AddCssClass (ControlStyle, levelSubMenuStyles [0].CssClass);
1296                                         AddCssClass (ControlStyle, levelSubMenuStyles [0].RegisteredCssClass);
1297                                 }
1298                         }
1299                         else {
1300                                 // styles are not registered
1301                                 if (staticMenuStyle != null){
1302                                         ControlStyle.CopyFrom (staticMenuStyle);
1303                                 }
1304                                 if (levelSubMenuStyles != null && levelSubMenuStyles.Count > 0) {
1305                                         ControlStyle.CopyFrom (levelSubMenuStyles [0]);
1306                                 }
1307                         }
1308                         base.AddAttributesToRender (writer);
1309                 }
1310
1311                 void AddCssClass (Style style, string cssClass) {
1312                         style.AddCssClass (cssClass);
1313                 }
1314                 
1315                 public override void RenderBeginTag (HtmlTextWriter writer)
1316                 {
1317                         if (SkipLinkText != "") {
1318                                 System.Web.UI.HtmlControls.HtmlAnchor anchor = new System.Web.UI.HtmlControls.HtmlAnchor ();
1319                                 anchor.HRef = "#" + ClientID + "_SkipLink";
1320
1321                                 Image img = new Image ();
1322                                 ClientScriptManager csm = new ClientScriptManager (null);
1323                                 img.ImageUrl = csm.GetWebResourceUrl (typeof (SiteMapPath), "transparent.gif");
1324                                 img.Attributes.Add ("height", "0");
1325                                 img.Attributes.Add ("width", "0");
1326                                 img.AlternateText = SkipLinkText;
1327
1328                                 anchor.Controls.Add (img);
1329                                 anchor.Render (writer);
1330                         }
1331                         base.RenderBeginTag (writer);
1332                 }
1333                 
1334                 public override void RenderEndTag (HtmlTextWriter writer)
1335                 {
1336                         base.RenderEndTag (writer);
1337
1338                         if (StaticDisplayLevels == 1 && MaximumDynamicDisplayLevels > 0)
1339                                 RenderDynamicMenu (writer, Items);
1340
1341                         if (SkipLinkText != "") {
1342                                 System.Web.UI.HtmlControls.HtmlAnchor anchor = new System.Web.UI.HtmlControls.HtmlAnchor ();
1343                                 anchor.ID = ClientID + "_SkipLink";
1344                                 anchor.Render (writer);
1345                         }
1346                 }
1347                 
1348                 protected internal override void RenderContents (HtmlTextWriter writer)
1349                 {
1350                         RenderMenuBody (writer, Items, Orientation == Orientation.Vertical, false, false);
1351                 }
1352
1353                 void RenderDynamicMenu (HtmlTextWriter writer, MenuItemCollection items) {
1354                         for (int n = 0; n < items.Count; n++) {
1355                                 if (DisplayChildren (items [n])) {
1356                                         RenderDynamicMenu (writer, items [n]);
1357                                         RenderDynamicMenu (writer, items [n].ChildItems);
1358                                 }
1359                         }
1360                 }
1361                 
1362                 MenuRenderHtmlTemplate _dynamicTemplate;
1363                 MenuRenderHtmlTemplate GetDynamicMenuTemplate (MenuItem item)
1364                 {
1365                         if (_dynamicTemplate != null) 
1366                                 return _dynamicTemplate;
1367
1368                         _dynamicTemplate = new MenuRenderHtmlTemplate ();
1369                         HtmlTextWriter writer = _dynamicTemplate.GetMenuTemplateWriter ();
1370
1371                         if (Page.Header != null) {
1372                                 writer.AddAttribute (HtmlTextWriterAttribute.Class, MenuRenderHtmlTemplate.GetMarker (0));
1373                         }
1374                         else {
1375                                 writer.AddAttribute (HtmlTextWriterAttribute.Style, MenuRenderHtmlTemplate.GetMarker (0));
1376                         }
1377
1378                         writer.AddStyleAttribute ("visibility", "hidden");
1379                         writer.AddStyleAttribute ("position", "absolute");
1380                         writer.AddStyleAttribute ("z-index", "1");
1381                         writer.AddStyleAttribute ("left", "0px");
1382                         writer.AddStyleAttribute ("top", "0px");
1383                         writer.AddAttribute ("id", MenuRenderHtmlTemplate.GetMarker (1));
1384                         writer.RenderBeginTag (HtmlTextWriterTag.Div);
1385
1386                         // Up button
1387                         writer.AddAttribute ("id", MenuRenderHtmlTemplate.GetMarker (2));
1388                         writer.AddStyleAttribute ("display", "block");
1389                         writer.AddStyleAttribute ("text-align", "center");
1390                         writer.AddAttribute ("onmouseover", string.Concat ("Menu_OverScrollBtn ('", ClientID, "','", MenuRenderHtmlTemplate.GetMarker (3), "','u')"));
1391                         writer.AddAttribute ("onmouseout", string.Concat ("Menu_OutScrollBtn ('", ClientID, "','", MenuRenderHtmlTemplate.GetMarker (4), "','u')")); 
1392                         writer.RenderBeginTag (HtmlTextWriterTag.Div);
1393                         
1394                         writer.AddAttribute ("src", MenuRenderHtmlTemplate.GetMarker (5)); //src
1395                         writer.AddAttribute ("alt", MenuRenderHtmlTemplate.GetMarker (6)); //ScrollUpText
1396                         writer.RenderBeginTag (HtmlTextWriterTag.Img);
1397                         writer.RenderEndTag (); // IMG
1398                         
1399                         writer.RenderEndTag (); // DIV scroll button
1400                 
1401                         writer.AddAttribute ("id", MenuRenderHtmlTemplate.GetMarker (7));
1402                         writer.RenderBeginTag (HtmlTextWriterTag.Div);
1403                         writer.AddAttribute ("id", MenuRenderHtmlTemplate.GetMarker (8));
1404                         writer.RenderBeginTag (HtmlTextWriterTag.Div);
1405                         
1406                         // call of RenderMenu
1407                         writer.Write (MenuRenderHtmlTemplate.GetMarker (9));
1408                         
1409                         writer.RenderEndTag (); // DIV Content
1410                         writer.RenderEndTag (); // DIV Scroll container
1411
1412                         // Down button
1413                         writer.AddAttribute ("id", MenuRenderHtmlTemplate.GetMarker (0));
1414                         writer.AddStyleAttribute ("display", "block");
1415                         writer.AddStyleAttribute ("text-align", "center");
1416                         writer.AddAttribute ("onmouseover", string.Concat ("Menu_OverScrollBtn ('", ClientID, "','", MenuRenderHtmlTemplate.GetMarker (1), "','d')"));
1417                         writer.AddAttribute ("onmouseout", string.Concat ("Menu_OutScrollBtn ('", ClientID, "','", MenuRenderHtmlTemplate.GetMarker (2), "','d')")); 
1418                         writer.RenderBeginTag (HtmlTextWriterTag.Div);
1419                         
1420                         writer.AddAttribute ("src", MenuRenderHtmlTemplate.GetMarker (3)); //src
1421                         writer.AddAttribute ("alt", MenuRenderHtmlTemplate.GetMarker (4)); //ScrollDownText
1422                         writer.RenderBeginTag (HtmlTextWriterTag.Img);
1423                         writer.RenderEndTag (); // IMG
1424                         
1425                         writer.RenderEndTag (); // DIV scroll button
1426                         
1427                         writer.RenderEndTag (); // DIV menu
1428
1429                         _dynamicTemplate.Parse ();
1430                         return _dynamicTemplate;
1431                 }
1432
1433                 void RenderDynamicMenu (HtmlTextWriter writer, MenuItem item)
1434                 {
1435                         _dynamicTemplate = GetDynamicMenuTemplate (item);
1436
1437                         string idPrefix = ClientID + "_" + item.Path;
1438                         string [] param = new string [9];
1439                         param [0] = GetCssMenuStyle (true, item.Depth + 1);
1440                         param [1] = idPrefix + "s";
1441                         param [2] = idPrefix + "cu";
1442                         param [3] = item.Path;
1443                         param [4] = item.Path;
1444                         param [5] = ScrollUpImageUrl != "" ? ScrollUpImageUrl : Page.ClientScript.GetWebResourceUrl (typeof (Menu), "arrow_up.gif");
1445                         param [6] = ScrollUpText;
1446                         param [7] = idPrefix + "cb";
1447                         param [8] = idPrefix + "cc";
1448
1449                         _dynamicTemplate.RenderTemplate (writer, param, 0, param.Length);
1450
1451                         RenderMenu (writer, item.ChildItems, true, true, item.Depth + 1, false);
1452
1453                         string [] param2 = new string [5];
1454                         param2 [0] = idPrefix + "cd";
1455                         param2 [1] = item.Path;
1456                         param2 [2] = item.Path;
1457                         param2 [3] = ScrollDownImageUrl != "" ? ScrollDownImageUrl : Page.ClientScript.GetWebResourceUrl (typeof (Menu), "arrow_down.gif");
1458                         param2 [4] = ScrollDownText;
1459
1460                         _dynamicTemplate.RenderTemplate (writer, param2, param.Length + 1, param2.Length);
1461
1462                 }
1463
1464                 string GetCssMenuStyle (bool dynamic, int menuLevel)
1465                 {
1466                         if (Page.Header != null) {
1467                                 // styles are registered
1468                                 StringBuilder sb = new StringBuilder ();
1469
1470                                 if (!dynamic && staticMenuStyle != null) {
1471                                         sb.Append (staticMenuStyle.CssClass);
1472                                         sb.Append (' ');
1473                                         sb.Append (staticMenuStyle.RegisteredCssClass);
1474                                 }
1475                                 if (dynamic && dynamicMenuStyle != null) {
1476                                         sb.Append (PopOutBoxStyle.RegisteredCssClass);
1477                                         sb.Append (' ');
1478                                         sb.Append (dynamicMenuStyle.CssClass);
1479                                         sb.Append (' ');
1480                                         sb.Append (dynamicMenuStyle.RegisteredCssClass);
1481                                 }
1482                                 if (levelSubMenuStyles != null && levelSubMenuStyles.Count > menuLevel) {
1483                                         sb.Append (levelSubMenuStyles [menuLevel].CssClass);
1484                                         sb.Append (' ');
1485                                         sb.Append (levelSubMenuStyles [menuLevel].RegisteredCssClass); 
1486                                 }
1487                                 return sb.ToString ();
1488                         }
1489                         else {
1490                                 // styles are not registered
1491                                 SubMenuStyle style = new SubMenuStyle ();
1492
1493                                 if (!dynamic && staticMenuStyle != null) {
1494                                         style.CopyFrom (staticMenuStyle);
1495                                 }
1496                                 if (dynamic && dynamicMenuStyle != null) {
1497                                         style.CopyFrom (PopOutBoxStyle);
1498                                         style.CopyFrom (dynamicMenuStyle);
1499                                 }
1500                                 if (levelSubMenuStyles != null && levelSubMenuStyles.Count > menuLevel) {
1501                                         style.CopyFrom (levelSubMenuStyles [menuLevel]);
1502                                 }
1503                                 return style.GetStyleAttributes (null).Value;
1504                         }
1505                 }
1506
1507                 void RenderMenuBeginTagAttributes (HtmlTextWriter writer, bool dynamic, int menuLevel) {
1508                         writer.AddAttribute ("cellpadding", "0", false);
1509                         writer.AddAttribute ("cellspacing", "0", false);
1510                         writer.AddAttribute ("border", "0", false);
1511
1512                         if (!dynamic) {
1513                                 SubMenuStyle style = new SubMenuStyle ();
1514                                 FillMenuStyle (dynamic, menuLevel, style);
1515                                 style.AddAttributesToRender (writer);
1516                         }
1517                 }
1518
1519                 private void FillMenuStyle (bool dynamic, int menuLevel, SubMenuStyle style) {
1520                         if (Page.Header != null) {
1521                                 // styles are registered
1522                                 if (!dynamic && staticMenuStyle != null) {
1523                                         AddCssClass (style, staticMenuStyle.CssClass);
1524                                         AddCssClass (style, staticMenuStyle.RegisteredCssClass);
1525                                 }
1526                                 if (dynamic && dynamicMenuStyle != null) {
1527                                         AddCssClass (style, dynamicMenuStyle.CssClass);
1528                                         AddCssClass (style, dynamicMenuStyle.RegisteredCssClass);
1529                                 }
1530                                 if (levelSubMenuStyles != null && levelSubMenuStyles.Count > menuLevel) {
1531                                         AddCssClass (style, levelSubMenuStyles [menuLevel].CssClass);
1532                                         AddCssClass (style, levelSubMenuStyles [menuLevel].RegisteredCssClass);
1533                                 }
1534                         }
1535                         else {
1536                                 // styles are not registered
1537                                 if (!dynamic && staticMenuStyle != null) {
1538                                         style.CopyFrom (staticMenuStyle);
1539                                 }
1540                                 if (dynamic && dynamicMenuStyle != null) {
1541                                         style.CopyFrom (dynamicMenuStyle);
1542                                 }
1543                                 if (levelSubMenuStyles != null && levelSubMenuStyles.Count > menuLevel) {
1544                                         style.CopyFrom (levelSubMenuStyles [menuLevel]);
1545                                 }
1546                         }
1547                 }
1548
1549                 void RenderMenu (HtmlTextWriter writer, MenuItemCollection items, bool vertical, bool dynamic, int menuLevel, bool notLast)
1550                 {
1551                         RenderMenuBeginTag (writer, dynamic, menuLevel);
1552                         RenderMenuBody (writer, items, vertical, dynamic, notLast);
1553                         RenderMenuEndTag (writer);
1554                 }
1555                 
1556                 void RenderMenuBeginTag (HtmlTextWriter writer, bool dynamic, int menuLevel)
1557                 {
1558                         RenderMenuBeginTagAttributes (writer, dynamic, menuLevel);
1559                         writer.RenderBeginTag (HtmlTextWriterTag.Table);
1560                 }
1561                 
1562                 void RenderMenuEndTag (HtmlTextWriter writer)
1563                 {
1564                         writer.RenderEndTag ();
1565                 }
1566
1567                 void RenderMenuBody (HtmlTextWriter writer, MenuItemCollection items, bool vertical, bool dynamic, bool notLast) {
1568                         if (!vertical)
1569                                 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1570
1571                         int count = items.Count;
1572                         for (int n = 0; n < count; n++) {
1573                                 MenuItem item = items [n];
1574                                 Adapters.MenuAdapter adapter = Adapter as Adapters.MenuAdapter;
1575                                 if (adapter != null)
1576                                         adapter.RenderItem (writer, item, n);
1577                                 else
1578                                         RenderMenuItem (writer, item, (n + 1 == count) ? notLast : true, n == 0);
1579                         }
1580
1581                         if (!vertical)
1582                                 writer.RenderEndTag (); // TR
1583                 }
1584
1585                 void RenderMenuItemSpacing (HtmlTextWriter writer, Unit itemSpacing, bool vertical) {
1586                         if (vertical) {
1587                                 writer.AddStyleAttribute ("height", itemSpacing.ToString ());
1588                                 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1589                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1590                                 writer.RenderEndTag ();
1591                                 writer.RenderEndTag ();
1592                         }
1593                         else {
1594                                 writer.AddStyleAttribute ("width", itemSpacing.ToString ());
1595                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1596                                 writer.RenderEndTag ();
1597                         }
1598                 }
1599                 
1600                 private bool IsDynamicItem (MenuItem item) {
1601                         return item.Depth + 1 > StaticDisplayLevels;
1602                 }
1603
1604                 private bool DisplayChildren (MenuItem item) {
1605                         return (item.Depth + 1 < StaticDisplayLevels + MaximumDynamicDisplayLevels) && item.ChildItems.Count > 0;
1606                 }
1607
1608                 static string MakeHandlerJavaScript (string handlerName, string param1, string param2, string param3)
1609                 {
1610                         return "javascript:Menu_" + handlerName + "('" + param1 + "','" + param2 + "'," + param3 + ")";
1611                 }
1612                 
1613                 internal void RenderItem (HtmlTextWriter writer, MenuItem item, int position) {
1614                         // notLast should be true if item or any of its ancestors is not a
1615                         // last child.
1616                         bool notLast = false;
1617                         MenuItem parent;
1618                         MenuItem child = item;                  
1619                         while (null != (parent = child.Parent)) {
1620                                 if (child.Index != parent.ChildItems.Count - 1) {
1621                                         notLast = true;
1622                                         break;
1623                                 }
1624                                 child = parent;
1625                         }
1626                         
1627                         RenderMenuItem (writer, item, notLast, position == 0);
1628                 }
1629                 
1630                 void RenderMenuItem (HtmlTextWriter writer, MenuItem item, bool notLast, bool isFirst) {
1631                         bool displayChildren = DisplayChildren (item);
1632                         bool dynamicChildren = displayChildren && (item.Depth + 1 >= StaticDisplayLevels);
1633                         bool isDynamicItem = IsDynamicItem (item);
1634                         bool vertical = (Orientation == Orientation.Vertical) || isDynamicItem;
1635                         
1636                         Unit itemSpacing = GetItemSpacing (item, isDynamicItem);
1637
1638                         if (itemSpacing != Unit.Empty && (item.Depth > 0 || !isFirst))
1639                                 RenderMenuItemSpacing (writer, itemSpacing, vertical);
1640
1641                         if(!String.IsNullOrEmpty(item.ToolTip))
1642                                 writer.AddAttribute (HtmlTextWriterAttribute.Title, item.ToolTip);
1643                         if (vertical)
1644                                 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1645
1646                         string parentId = isDynamicItem ? "'" + item.Parent.Path + "'" : "null";
1647                         if (dynamicChildren) {
1648                                 writer.AddAttribute ("onmouseover",
1649                                                      "javascript:Menu_OverItem ('" + ClientID + "','" + item.Path + "'," + parentId + ")");
1650                                 writer.AddAttribute ("onmouseout",
1651                                                      "javascript:Menu_OutItem ('" + ClientID + "','" + item.Path + "')");
1652                         } else if (isDynamicItem) {
1653                                 writer.AddAttribute ("onmouseover",
1654                                                      "javascript:Menu_OverDynamicLeafItem ('" + ClientID + "','" + item.Path + "'," + parentId + ")");
1655                                 writer.AddAttribute ("onmouseout",
1656                                                      "javascript:Menu_OutItem ('" + ClientID + "','" + item.Path + "'," + parentId + ")");
1657                         } else {
1658                                 writer.AddAttribute ("onmouseover",
1659                                                      "javascript:Menu_OverStaticLeafItem ('" + ClientID + "','" + item.Path + "')");
1660                                 writer.AddAttribute ("onmouseout",
1661                                                      "javascript:Menu_OutItem ('" + ClientID + "','" + item.Path + "')");
1662                         }
1663
1664                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
1665
1666                         // Top separator image
1667
1668                         if (isDynamicItem && DynamicTopSeparatorImageUrl != "") {
1669                                 writer.AddAttribute ("src", ResolveClientUrl (DynamicTopSeparatorImageUrl));
1670                                 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1671                                 writer.RenderEndTag (); // IMG
1672                         }
1673                         else if (!isDynamicItem && StaticTopSeparatorImageUrl != "") {
1674                                 writer.AddAttribute ("src", ResolveClientUrl (StaticTopSeparatorImageUrl));
1675                                 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1676                                 writer.RenderEndTag (); // IMG
1677                         }
1678
1679                         // Menu item box
1680                         
1681                         MenuItemStyle style = new MenuItemStyle ();
1682                         if (Page.Header != null) {
1683                                 // styles are registered
1684                                 if (!isDynamicItem && staticMenuItemStyle != null) {
1685                                         AddCssClass (style, staticMenuItemStyle.CssClass);
1686                                         AddCssClass (style, staticMenuItemStyle.RegisteredCssClass);
1687                                 }
1688                                 if (isDynamicItem && dynamicMenuItemStyle != null) {
1689                                         AddCssClass (style, dynamicMenuItemStyle.CssClass);
1690                                         AddCssClass (style, dynamicMenuItemStyle.RegisteredCssClass);
1691                                 }
1692                                 if (levelMenuItemStyles != null && levelMenuItemStyles.Count > item.Depth) {
1693                                         AddCssClass (style, levelMenuItemStyles [item.Depth].CssClass);
1694                                         AddCssClass (style, levelMenuItemStyles [item.Depth].RegisteredCssClass);
1695                                 }
1696                                 if (item == SelectedItem) {
1697                                         if (!isDynamicItem && staticSelectedStyle != null) {
1698                                                 AddCssClass (style, staticSelectedStyle.CssClass);
1699                                                 AddCssClass (style, staticSelectedStyle.RegisteredCssClass);
1700                                         }
1701                                         if (isDynamicItem && dynamicSelectedStyle != null) {
1702                                                 AddCssClass (style, dynamicSelectedStyle.CssClass);
1703                                                 AddCssClass (style, dynamicSelectedStyle.RegisteredCssClass);
1704                                         }
1705                                         if (levelSelectedStyles != null && levelSelectedStyles.Count > item.Depth) {
1706                                                 AddCssClass (style, levelSelectedStyles [item.Depth].CssClass);
1707                                                 AddCssClass (style, levelSelectedStyles [item.Depth].RegisteredCssClass);
1708                                         }
1709                                 }
1710                         }
1711                         else {
1712                                 // styles are not registered
1713                                 if (!isDynamicItem && staticMenuItemStyle != null) {
1714                                         style.CopyFrom (staticMenuItemStyle);
1715                                 }
1716                                 if (isDynamicItem && dynamicMenuItemStyle != null) {
1717                                         style.CopyFrom (dynamicMenuItemStyle);
1718                                 }
1719                                 if (levelMenuItemStyles != null && levelMenuItemStyles.Count > item.Depth) {
1720                                         style.CopyFrom (levelMenuItemStyles [item.Depth]);
1721                                 }
1722                                 if (item == SelectedItem) {
1723                                         if (!isDynamicItem && staticSelectedStyle != null) {
1724                                                 style.CopyFrom (staticSelectedStyle);
1725                                         }
1726                                         if (isDynamicItem && dynamicSelectedStyle != null) {
1727                                                 style.CopyFrom (dynamicSelectedStyle);
1728                                         }
1729                                         if (levelSelectedStyles != null && levelSelectedStyles.Count > item.Depth) {
1730                                                 style.CopyFrom (levelSelectedStyles [item.Depth]);
1731                                         }
1732                                 }
1733                         }
1734                         style.AddAttributesToRender (writer);
1735
1736                         writer.AddAttribute ("id", GetItemClientId (item, "i"));
1737
1738                         writer.AddAttribute ("cellpadding", "0", false);
1739                         writer.AddAttribute ("cellspacing", "0", false);
1740                         writer.AddAttribute ("border", "0", false);
1741                         writer.AddAttribute ("width", "100%", false);
1742                         writer.RenderBeginTag (HtmlTextWriterTag.Table);
1743                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1744
1745                         // Menu item text
1746
1747                         if (vertical)
1748                                 writer.AddStyleAttribute (HtmlTextWriterStyle.Width, "100%");
1749                         if (!ItemWrap)
1750                                 writer.AddStyleAttribute ("white-space", "nowrap");
1751                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
1752
1753                         RenderItemHref (writer, item);
1754                         
1755                         Style linkStyle = new Style ();
1756                         if (Page.Header != null) {
1757                                 // styles are registered
1758                                 AddCssClass (linkStyle, ControlLinkStyle.RegisteredCssClass);
1759
1760                                 if (!isDynamicItem && staticMenuItemStyle != null) {
1761                                         AddCssClass (linkStyle, staticMenuItemStyle.CssClass);
1762                                         AddCssClass (linkStyle, staticMenuItemLinkStyle.RegisteredCssClass);
1763                                 }
1764                                 if (isDynamicItem && dynamicMenuItemStyle != null) {
1765                                         AddCssClass (linkStyle, dynamicMenuItemStyle.CssClass);
1766                                         AddCssClass (linkStyle, dynamicMenuItemLinkStyle.RegisteredCssClass);
1767                                 }
1768                                 if (levelMenuItemStyles != null && levelMenuItemStyles.Count > item.Depth) {
1769                                         AddCssClass (linkStyle, levelMenuItemStyles [item.Depth].CssClass);
1770                                         AddCssClass (linkStyle, levelMenuItemLinkStyles [item.Depth].RegisteredCssClass);
1771                                 }
1772                                 if (item == SelectedItem) {
1773                                         if (!isDynamicItem && staticSelectedStyle != null) {
1774                                                 AddCssClass (linkStyle, staticSelectedStyle.CssClass);
1775                                                 AddCssClass (linkStyle, staticSelectedLinkStyle.RegisteredCssClass);
1776                                         }
1777                                         if (isDynamicItem && dynamicSelectedStyle != null) {
1778                                                 AddCssClass (linkStyle, dynamicSelectedStyle.CssClass);
1779                                                 AddCssClass (linkStyle, dynamicSelectedLinkStyle.RegisteredCssClass);
1780                                         }
1781                                         if (levelSelectedStyles != null && levelSelectedStyles.Count > item.Depth) {
1782                                                 AddCssClass (linkStyle, levelSelectedStyles [item.Depth].CssClass);
1783                                                 AddCssClass (linkStyle, levelSelectedLinkStyles [item.Depth].RegisteredCssClass);
1784                                         }
1785                                 }
1786                         }
1787                         else {
1788                                 // styles are not registered
1789                                 linkStyle.CopyFrom (ControlLinkStyle);
1790
1791                                 if (!isDynamicItem && staticMenuItemStyle != null) {
1792                                         linkStyle.CopyFrom (staticMenuItemLinkStyle);
1793                                 }
1794                                 if (isDynamicItem && dynamicMenuItemStyle != null) {
1795                                         linkStyle.CopyFrom (dynamicMenuItemLinkStyle);
1796                                 }
1797                                 if (levelMenuItemStyles != null && levelMenuItemStyles.Count > item.Depth) {
1798                                         linkStyle.CopyFrom (levelMenuItemLinkStyles [item.Depth]);
1799                                 }
1800                                 if (item == SelectedItem) {
1801                                         if (!isDynamicItem && staticSelectedStyle != null) {
1802                                                 linkStyle.CopyFrom (staticSelectedLinkStyle);
1803                                         }
1804                                         if (isDynamicItem && dynamicSelectedStyle != null) {
1805                                                 linkStyle.CopyFrom (dynamicSelectedLinkStyle);
1806                                         }
1807                                         if (levelSelectedStyles != null && levelSelectedStyles.Count > item.Depth) {
1808                                                 linkStyle.CopyFrom (levelSelectedLinkStyles [item.Depth]);
1809                                         }
1810                                 }
1811
1812                                 linkStyle.AlwaysRenderTextDecoration = true;
1813                         }
1814                         linkStyle.AddAttributesToRender (writer);
1815
1816                         writer.AddAttribute ("id", GetItemClientId (item, "l"));
1817                         
1818                         if (item.Depth > 0 && !isDynamicItem) {
1819                                 Unit indent = new Unit (StaticSubMenuIndent.Value * item.Depth, StaticSubMenuIndent.Type);
1820                                 writer.AddStyleAttribute ("margin-left", indent.ToString ());
1821                         }
1822                         writer.RenderBeginTag (HtmlTextWriterTag.A);
1823                         RenderItemContent (writer, item, isDynamicItem);
1824                         writer.RenderEndTag (); // A
1825
1826                         writer.RenderEndTag (); // TD
1827
1828                         // Popup image
1829
1830                         if (dynamicChildren) {
1831                                 string popOutImage = GetPopOutImage (item, isDynamicItem);
1832                                 if (popOutImage != null) {
1833                                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
1834                                         writer.AddAttribute ("src", ResolveClientUrl (popOutImage));
1835                                         writer.AddAttribute ("border", "0");
1836                                         string toolTip = String.Format (isDynamicItem ? DynamicPopOutImageTextFormatString : StaticPopOutImageTextFormatString, item.Text);
1837                                         writer.AddAttribute (HtmlTextWriterAttribute.Alt, toolTip);
1838                                         writer.RenderBeginTag (HtmlTextWriterTag.Img);
1839                                         writer.RenderEndTag (); // IMG
1840                                         writer.RenderEndTag (); // TD
1841                                 }
1842                         }
1843
1844                         writer.RenderEndTag (); // TR
1845                         writer.RenderEndTag (); // TABLE
1846
1847                         // Bottom separator image
1848
1849                         string separatorImg = item.SeparatorImageUrl;
1850                         if (separatorImg.Length == 0) {
1851                                 if (isDynamicItem)
1852                                         separatorImg = DynamicBottomSeparatorImageUrl;
1853                                 else
1854                                         separatorImg = StaticBottomSeparatorImageUrl;
1855                         }
1856                         if (separatorImg.Length > 0) {
1857                                 writer.AddAttribute ("src", ResolveClientUrl (separatorImg));
1858                                 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1859                                 writer.RenderEndTag (); // IMG
1860                         }
1861
1862                         writer.RenderEndTag (); // TD
1863                         if (vertical)
1864                                 writer.RenderEndTag (); // TR
1865
1866                         if (itemSpacing != Unit.Empty)
1867                                 RenderMenuItemSpacing (writer, itemSpacing, vertical);
1868                         else if (!vertical && (notLast || (displayChildren && !dynamicChildren))) {
1869                                         writer.AddStyleAttribute ("width", "3px");
1870                                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
1871                                         writer.RenderEndTag ();
1872                         }
1873
1874                         // Submenu
1875
1876                         if (displayChildren && !dynamicChildren) {
1877                                 if (vertical)
1878                                         writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1879                                 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1880                                 writer.AddAttribute ("width", "100%");
1881                                 RenderMenu (writer, item.ChildItems, Orientation == Orientation.Vertical, false, item.Depth + 1, notLast);
1882                                 if (item.Depth + 2 == StaticDisplayLevels)
1883                                         RenderDynamicMenu (writer, item.ChildItems);
1884                                 writer.RenderEndTag (); // TD
1885                                 if (vertical)
1886                                         writer.RenderEndTag (); // TR
1887                         }
1888
1889                 }
1890
1891                 void RenderItemContent (HtmlTextWriter writer, MenuItem item, bool isDynamicItem) {
1892                         if (_menuItemControls!=null && _menuItemControls [item] != null) {
1893                                 ((Control) _menuItemControls [item]).Render (writer);
1894                         }
1895                         else {
1896
1897                                 if (!String.IsNullOrEmpty (item.ImageUrl)) {
1898                                         writer.AddAttribute (HtmlTextWriterAttribute.Src, ResolveClientUrl (item.ImageUrl));
1899                                         writer.AddAttribute (HtmlTextWriterAttribute.Alt, item.ToolTip);
1900                                         writer.AddStyleAttribute (HtmlTextWriterStyle.BorderStyle, "none");
1901                                         writer.AddStyleAttribute (HtmlTextWriterStyle.VerticalAlign, "middle");
1902                                         writer.RenderBeginTag (HtmlTextWriterTag.Img);
1903                                         writer.RenderEndTag (); // IMG
1904                                 }
1905
1906                                 if (isDynamicItem && DynamicItemFormatString.Length > 0) {
1907                                         writer.Write (String.Format (DynamicItemFormatString, item.Text));
1908                                 }
1909                                 else if (!isDynamicItem && StaticItemFormatString.Length > 0) {
1910                                         writer.Write (String.Format (StaticItemFormatString, item.Text));
1911                                 }
1912                                 else {
1913                                         writer.Write (item.Text);
1914                                 }
1915                         }
1916                 }
1917                         
1918                 Unit GetItemSpacing (MenuItem item, bool dynamic)
1919                 {
1920                         Unit itemSpacing = Unit.Empty;
1921                         
1922                         if (item.Selected) {
1923                                 if (levelSelectedStyles != null && item.Depth < levelSelectedStyles.Count) {
1924                                         itemSpacing = levelSelectedStyles [item.Depth].ItemSpacing;
1925                                         if (itemSpacing != Unit.Empty) return itemSpacing;
1926                                 }
1927
1928                                 if (dynamic && dynamicSelectedStyle != null)
1929                                         itemSpacing = dynamicSelectedStyle.ItemSpacing;
1930                                 else if (!dynamic && staticSelectedStyle != null)
1931                                         itemSpacing = staticSelectedStyle.ItemSpacing;
1932                                 if (itemSpacing != Unit.Empty)
1933                                         return itemSpacing;
1934                         }
1935                         
1936                         if (levelMenuItemStyles != null && item.Depth < levelMenuItemStyles.Count) {
1937                                 itemSpacing = levelMenuItemStyles [item.Depth].ItemSpacing;
1938                                 if (itemSpacing != Unit.Empty) return itemSpacing;
1939                         }
1940
1941                         if (dynamic && dynamicMenuItemStyle != null)
1942                                 return dynamicMenuItemStyle.ItemSpacing;
1943                         else if (!dynamic && staticMenuItemStyle != null)
1944                                 return staticMenuItemStyle.ItemSpacing;
1945                         else
1946                                 return Unit.Empty;
1947                 }
1948                 
1949                 string GetPopOutImage (MenuItem item, bool isDynamicItem)
1950                 {
1951                         if (item.PopOutImageUrl != "")
1952                                 return item.PopOutImageUrl;
1953
1954                         if (isDynamicItem) {
1955                                 if (DynamicPopOutImageUrl != "")
1956                                         return DynamicPopOutImageUrl;
1957                                 if (DynamicEnableDefaultPopOutImage)
1958                                         return Page.ClientScript.GetWebResourceUrl (typeof (Menu), "arrow_plus.gif");
1959                         } else {
1960                                 if (StaticPopOutImageUrl != "")
1961                                         return StaticPopOutImageUrl;
1962                                 if (StaticEnableDefaultPopOutImage)
1963                                         return Page.ClientScript.GetWebResourceUrl (typeof (Menu), "arrow_plus.gif");
1964                         }
1965                         return null;
1966                 }
1967                         
1968                 void RenderItemHref (HtmlTextWriter writer, MenuItem item)
1969                 {
1970                         if (!item.BranchEnabled) {
1971                                 writer.AddAttribute ("disabled", "true", false);
1972                         }
1973                         else if (!item.Selectable) {
1974                                 writer.AddAttribute ("href", "#", false);
1975                                 writer.AddStyleAttribute ("cursor", "text");
1976                         }
1977                         else if (item.NavigateUrl != "") {
1978                                 string target = item.Target != "" ? item.Target : Target;
1979 #if TARGET_J2EE
1980                                 string navUrl = ResolveClientUrl (item.NavigateUrl, String.Compare (target, "_blank", StringComparison.InvariantCultureIgnoreCase) != 0);
1981 #else
1982                                 string navUrl = ResolveClientUrl (item.NavigateUrl);
1983 #endif
1984                                 writer.AddAttribute ("href", navUrl);
1985                                 if (target != "")
1986                                         writer.AddAttribute ("target", target);
1987                         }
1988                         else {
1989                                 writer.AddAttribute ("href", GetClientEvent (item));
1990                         }
1991
1992                 }
1993                 
1994                 string GetItemClientId (MenuItem item, string sufix)
1995                 {
1996                         return ClientID + "_" + item.Path + sufix;
1997                 }
1998                                                         
1999                 string GetClientEvent (MenuItem item)
2000                 {
2001                         return Page.ClientScript.GetPostBackClientHyperlink (this, item.Path);
2002                 }
2003
2004                 class MenuTemplateWriter : TextWriter
2005                 {
2006                         char [] _buffer;
2007                         int _ptr = 0;
2008                         
2009                         public MenuTemplateWriter (char [] buffer)
2010                         {
2011                                 _buffer = buffer;
2012                         }
2013
2014                         public override Encoding Encoding
2015                         {
2016                                 get { return Encoding.Unicode; }
2017                         }
2018
2019                         public override void Write (char value)
2020                         {
2021                                 if (_ptr == _buffer.Length)
2022                                         EnsureCapacity ();
2023                                 
2024                                 _buffer [_ptr++] = value;
2025                         }
2026
2027                         public override void Write (string value)
2028                         {
2029                                 if (value == null)
2030                                         return;
2031
2032                                 if (_ptr + value.Length >= _buffer.Length)
2033                                         EnsureCapacity ();
2034
2035                                 for (int i = 0; i < value.Length; i++)
2036                                         _buffer [_ptr++] = value [i];
2037                         }
2038
2039                         private void EnsureCapacity ()
2040                         {
2041                                 char [] tmpBuffer = new char [_buffer.Length * 2];
2042                                 Array.Copy (_buffer, tmpBuffer, _buffer.Length);
2043
2044                                 _buffer = tmpBuffer;
2045                         }
2046                 }
2047
2048                 class MenuRenderHtmlTemplate
2049                 {
2050                         public const string Marker = "\u093a\u093b\u0971";
2051                         char [] _templateHtml;
2052
2053                         MenuTemplateWriter _templateWriter;
2054                         ArrayList idxs = new ArrayList (32);
2055
2056                         public MenuRenderHtmlTemplate ()
2057                         {
2058                                 _templateHtml = new char [1024];
2059                                 _templateWriter = new MenuTemplateWriter (_templateHtml);
2060                         }
2061
2062                         public static string GetMarker (int num)
2063                         {
2064                                 char charNum = (char) ((int) '\u0971' + num);
2065                                 return string.Concat (Marker, charNum);
2066                         }
2067
2068                         public HtmlTextWriter GetMenuTemplateWriter()
2069                         {
2070                                 return new HtmlTextWriter (_templateWriter);
2071                         }
2072
2073                         public void Parse ()
2074                         {
2075                                 int mpos = 0;
2076                                 for (int i = 0; i < _templateHtml.Length; i++) {
2077                                         if (_templateHtml [i] == '\0') {
2078                                                 idxs.Add (i);
2079                                                 break;
2080                                         }
2081
2082                                         if (_templateHtml [i] != Marker [mpos]) {
2083                                                 mpos = 0;
2084                                                 continue;
2085                                         }
2086
2087                                         mpos++;
2088                                         if (mpos == Marker.Length) {
2089                                                 mpos = 0;
2090                                                 idxs.Add (i - Marker.Length + 1);
2091                                         }
2092                                 }
2093                         }
2094
2095                         public void RenderTemplate (HtmlTextWriter writer, string [] dynamicParts, int start, int count)
2096                         {
2097                                 if (idxs.Count == 0)
2098                                         return;
2099
2100                                 int partStart = 0;
2101                                 int partEnd = (start == 0) ? -Marker.Length - 1 : (int) idxs [start - 1];
2102                                 int di = 0;
2103
2104                                 int i = start;
2105                                 int total = start + count;
2106                                 for (; i < total; i++) {
2107
2108                                         partStart = partEnd + Marker.Length + 1;
2109                                         partEnd = (int) idxs [i];
2110                                         
2111                                         // write static part
2112                                         writer.Write (_templateHtml, partStart, partEnd - partStart);
2113
2114                                         // write synamic part
2115                                         di = (int) _templateHtml [partEnd + Marker.Length] - 0x971;
2116                                         writer.Write (dynamicParts [di]);
2117                                 }
2118
2119                                 partStart = partEnd + Marker.Length + 1;
2120                                 partEnd = (int) idxs [i];
2121
2122                                 writer.Write (_templateHtml, partStart, partEnd - partStart);
2123                         }
2124                 
2125                 }
2126         }
2127 }
2128
2129 #endif