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