Merge pull request #5714 from alexischr/update_bockbuild
[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-2010 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
33 using System;
34 using System.Collections;
35 using System.Text;
36 using System.ComponentModel;
37 using System.Web.UI;
38 using System.Web.UI.HtmlControls;
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                 IMenuRenderer renderer;
54                 
55                 MenuItemStyle dynamicMenuItemStyle;
56                 SubMenuStyle dynamicMenuStyle;
57                 MenuItemStyle dynamicSelectedStyle;
58                 MenuItemStyle staticMenuItemStyle;
59                 SubMenuStyle staticMenuStyle;
60                 MenuItemStyle staticSelectedStyle;
61                 Style staticHoverStyle;
62                 Style dynamicHoverStyle;
63
64                 MenuItemStyleCollection levelMenuItemStyles;
65                 MenuItemStyleCollection levelSelectedStyles;
66                 SubMenuStyleCollection levelSubMenuStyles;
67                 ITemplate staticItemTemplate;
68                 ITemplate dynamicItemTemplate;
69                 
70                 MenuItemCollection items;
71                 MenuItemBindingCollection dataBindings;
72                 MenuItem selectedItem;
73                 string selectedItemPath;
74                 Hashtable bindings;
75
76                 Hashtable _menuItemControls;
77                 bool _requiresChildControlsDataBinding;
78                 SiteMapNode _currSiteMapNode;
79                 Style popOutBoxStyle;
80                 Style controlLinkStyle;
81                 Style dynamicMenuItemLinkStyle;
82                 Style staticMenuItemLinkStyle;
83                 Style dynamicSelectedLinkStyle;
84                 Style staticSelectedLinkStyle;
85                 Style dynamicHoverLinkStyle;
86                 Style staticHoverLinkStyle;
87                 bool? renderList;
88                 bool includeStyleBlock = true;
89                 MenuRenderingMode renderingMode = MenuRenderingMode.Default;
90                 static readonly object MenuItemClickEvent = new object();
91                 static readonly object MenuItemDataBoundEvent = new object();
92                 
93                 public static readonly string MenuItemClickCommandName = "Click";
94                 
95                 public event MenuEventHandler MenuItemClick {
96                         add { Events.AddHandler (MenuItemClickEvent, value); }
97                         remove { Events.RemoveHandler (MenuItemClickEvent, value); }
98                 }
99                 
100                 public event MenuEventHandler MenuItemDataBound {
101                         add { Events.AddHandler (MenuItemDataBoundEvent, value); }
102                         remove { Events.RemoveHandler (MenuItemDataBoundEvent, value); }
103                 }
104                 
105                 protected virtual void OnMenuItemClick (MenuEventArgs e)
106                 {
107                         if (Events != null) {
108                                 MenuEventHandler eh = (MenuEventHandler) Events [MenuItemClickEvent];
109                                 if (eh != null) eh (this, e);
110                         }
111                 }
112                 
113                 protected virtual void OnMenuItemDataBound (MenuEventArgs e)
114                 {
115                         if (Events != null) {
116                                 MenuEventHandler eh = (MenuEventHandler) Events [MenuItemDataBoundEvent];
117                                 if (eh != null) eh (this, e);
118                         }
119                 }
120
121                 IMenuRenderer Renderer {
122                         get {
123                                 if (renderer == null)
124                                         renderer = CreateRenderer (null);
125                                 
126                                 return renderer;
127                         }
128                 }
129                 bool RenderList {
130                         get {
131                                 if (renderList == null) {
132                                         switch (RenderingMode) {
133                                                 case MenuRenderingMode.List:
134                                                         renderList = true;
135                                                         break;
136
137                                                 case MenuRenderingMode.Table:
138                                                         renderList = false;
139                                                         break;
140
141                                                 default:
142                                                         if (RenderingCompatibilityLessThan40)
143                                                                 renderList = false;
144                                                         else
145                                                                 renderList = true;
146                                                         break;
147                                         }
148                                 }
149
150                                 return renderList.Value;
151                         }
152                 }
153                 
154                 [DefaultValue (true)]
155                 [Description ("Determines whether or not to render the inline style block (only used in standards compliance mode)")]
156                 public bool IncludeStyleBlock {
157                         get { return includeStyleBlock; }
158                         set { includeStyleBlock = value; }
159                 }
160
161                 [DefaultValue (MenuRenderingMode.Default)]
162                 public MenuRenderingMode RenderingMode {
163                         get { return renderingMode; }
164                         set {
165                                 if (value < MenuRenderingMode.Default || value > MenuRenderingMode.List)
166                                         throw new ArgumentOutOfRangeException ("value");
167
168                                 renderingMode = value;
169                                 renderer = CreateRenderer (renderer);
170                         }
171                 }
172                 [DefaultValueAttribute (null)]
173                 [PersistenceMode (PersistenceMode.InnerProperty)]
174                 [EditorAttribute ("System.Web.UI.Design.WebControls.MenuBindingsEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
175                 [MergablePropertyAttribute (false)]
176                 public MenuItemBindingCollection DataBindings {
177                         get {
178                                 if (dataBindings == null) {
179                                         dataBindings = new MenuItemBindingCollection ();
180                                         if (IsTrackingViewState)
181                                                 ((IStateManager)dataBindings).TrackViewState();
182                                 }
183                                 return dataBindings;
184                         }
185                 }
186
187                 [DefaultValue (500)]
188                 [ThemeableAttribute (false)]
189                 public int DisappearAfter {
190                         get {
191                                 object o = ViewState ["DisappearAfter"];
192                                 if (o != null) return (int)o;
193                                 return 500;
194                         }
195                         set {
196                                 ViewState["DisappearAfter"] = value;
197                         }
198                 }
199
200                 [ThemeableAttribute (true)]
201                 [DefaultValue ("")]
202                 [UrlProperty]
203                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
204                 public string DynamicBottomSeparatorImageUrl {
205                         get {
206                                 object o = ViewState ["dbsiu"];
207                                 if (o != null)
208                                         return (string)o;
209                                 return String.Empty;
210                         }
211                         set {
212                                 ViewState["dbsiu"] = value;
213                         }
214                 }
215
216                 [DefaultValueAttribute ("")]
217                 public string DynamicItemFormatString {
218                         get {
219                                 object o = ViewState ["DynamicItemFormatString"];
220                                 if (o != null) return (string)o;
221                                 return "";
222                         }
223                         set {
224                                 ViewState["DynamicItemFormatString"] = value;
225                         }
226                 }
227
228                 [DefaultValue ("")]
229                 [UrlProperty]
230                 [WebCategory ("Appearance")]
231                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
232                 public string DynamicTopSeparatorImageUrl {
233                         get {
234                                 object o = ViewState ["dtsiu"];
235                                 if (o != null) return (string)o;
236                                 return "";
237                         }
238                         set {
239                                 ViewState["dtsiu"] = value;
240                         }
241                 }
242
243                 [DefaultValue ("")]
244                 [UrlProperty]
245                 [WebCategory ("Appearance")]
246                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
247                 public string StaticBottomSeparatorImageUrl {
248                         get {
249                                 object o = ViewState ["sbsiu"];
250                                 if (o != null) return (string)o;
251                                 return "";
252                         }
253                         set {
254                                 ViewState["sbsiu"] = value;
255                         }
256                 }
257
258                 [DefaultValue ("")]
259                 [UrlProperty]
260                 [WebCategory ("Appearance")]
261                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
262                 public string StaticTopSeparatorImageUrl {
263                         get {
264                                 object o = ViewState ["stsiu"];
265                                 if (o != null) return (string)o;
266                                 return "";
267                         }
268                         set {
269                                 ViewState["stsiu"] = value;
270                         }
271                 }
272
273                 [DefaultValue (Orientation.Vertical)]
274                 public Orientation Orientation {
275                         get {
276                                 object o = ViewState ["Orientation"];
277                                 if (o != null) return (Orientation) o;
278                                 return Orientation.Vertical;
279                         }
280                         set {
281                                 ViewState["Orientation"] = value;
282                         }
283                 }
284
285                 [DefaultValue (1)]
286                 [ThemeableAttribute (true)]
287                 public int StaticDisplayLevels {
288                         get {
289                                 object o = ViewState ["StaticDisplayLevels"];
290                                 if (o != null) return (int)o;
291                                 return 1;
292                         }
293                         set {
294                                 if (value < 1) throw new ArgumentOutOfRangeException ();
295                                 ViewState["StaticDisplayLevels"] = value;
296                         }
297                 }
298
299                 [DefaultValueAttribute ("")]
300                 public string StaticItemFormatString {
301                         get {
302                                 object o = ViewState ["StaticItemFormatString"];
303                                 if (o != null) return (string)o;
304                                 return "";
305                         }
306                         set {
307                                 ViewState["StaticItemFormatString"] = value;
308                         }
309                 }
310
311                 [DefaultValue (typeof (Unit), "16px")]
312                 [ThemeableAttribute (true)]
313                 public Unit StaticSubMenuIndent {
314                         get {
315                                 object o = ViewState ["StaticSubMenuIndent"];
316                                 if (o != null)
317                                         return (Unit)o;
318                                 // LAMESPEC: on 4.0 it returns Unit.Empty and on 3.5 16px
319                                 return Unit.Empty;
320                         }
321                         set {
322                                 ViewState["StaticSubMenuIndent"] = value;
323                         }
324                 }
325
326                 [ThemeableAttribute (true)]
327                 [DefaultValue (3)]
328                 public int MaximumDynamicDisplayLevels {
329                         get {
330                                 object o = ViewState ["MaximumDynamicDisplayLevels"];
331                                 if (o != null) return (int)o;
332                                 return 3;
333                         }
334                         set {
335                                 if (value < 0) throw new ArgumentOutOfRangeException ();
336                                 ViewState["MaximumDynamicDisplayLevels"] = value;
337                         }
338                 }
339
340                 [DefaultValue (0)]
341                 public int DynamicVerticalOffset {
342                         get {
343                                 object o = ViewState ["DynamicVerticalOffset"];
344                                 if (o != null) return (int)o;
345                                 return 0;
346                         }
347                         set {
348                                 ViewState["DynamicVerticalOffset"] = value;
349                         }
350                 }
351
352                 [DefaultValue (0)]
353                 public int DynamicHorizontalOffset {
354                         get {
355                                 object o = ViewState ["DynamicHorizontalOffset"];
356                                 if (o != null) return (int)o;
357                                 return 0;
358                         }
359                         set {
360                                 ViewState["DynamicHorizontalOffset"] = value;
361                         }
362                 }
363
364                 [DefaultValue (true)]
365                 public bool DynamicEnableDefaultPopOutImage {
366                         get {
367                                 object o = ViewState ["dedpoi"];
368                                 if (o != null) return (bool)o;
369                                 return true;
370                         }
371                         set {
372                                 ViewState["dedpoi"] = value;
373                         }
374                 }
375
376                 [DefaultValue (true)]
377                 public bool StaticEnableDefaultPopOutImage {
378                         get {
379                                 object o = ViewState ["sedpoi"];
380                                 if (o != null) return (bool)o;
381                                 return true;
382                         }
383                         set {
384                                 ViewState["sedpoi"] = value;
385                         }
386                 }
387
388                 [DefaultValueAttribute (null)]
389                 [PersistenceMode (PersistenceMode.InnerProperty)]
390                 [Editor ("System.Web.UI.Design.MenuItemCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
391                 [MergablePropertyAttribute (false)]
392                 public MenuItemCollection Items {
393                         get {
394                                 if (items == null) {
395                                         items = new MenuItemCollection (this);
396                                         if (IsTrackingViewState)
397                                                 ((IStateManager)items).TrackViewState();
398                                 }
399                                 return items;
400                         }
401                 }
402
403                 [DefaultValue ('/')]
404                 public char PathSeparator {
405                         get {
406                                 object o = ViewState ["PathSeparator"];
407                                 if(o != null) return (char)o;
408                                 return '/';
409                         }
410                         set {
411                                 ViewState ["PathSeparator"] = value;
412                         }
413                 }
414
415                 [DefaultValue (false)]
416                 public bool ItemWrap {
417                         get {
418                                 object o = ViewState ["ItemWrap"];
419                                 if(o != null) return (bool)o;
420                                 return false;
421                         }
422                         set {
423                                 ViewState ["ItemWrap"] = value;
424                         }
425                 }
426
427                 internal Style PopOutBoxStyle {
428                         get {
429                                 if (popOutBoxStyle == null) {
430                                         popOutBoxStyle = new Style ();
431                                         popOutBoxStyle.BackColor = Color.White;
432                                 }
433                                 return popOutBoxStyle;
434                         }
435                 }
436
437                 internal Style ControlLinkStyle {
438                         get {
439                                 if (controlLinkStyle == null) {
440                                         controlLinkStyle = new Style ();
441                                         controlLinkStyle.AlwaysRenderTextDecoration = true;
442                                 }
443                                 return controlLinkStyle;
444                         }
445                 }
446
447                 internal Style DynamicMenuItemLinkStyle {
448                         get {
449                                 if (dynamicMenuItemLinkStyle == null) {
450                                         dynamicMenuItemLinkStyle = new Style ();
451                                 }
452                                 return dynamicMenuItemLinkStyle;
453                         }
454                 }
455
456                 internal Style StaticMenuItemLinkStyle {
457                         get {
458                                 if (staticMenuItemLinkStyle == null) {
459                                         staticMenuItemLinkStyle = new Style ();
460                                 }
461                                 return staticMenuItemLinkStyle;
462                         }
463                 }
464
465                 internal Style DynamicSelectedLinkStyle {
466                         get {
467                                 if (dynamicSelectedLinkStyle == null) {
468                                         dynamicSelectedLinkStyle = new Style ();
469                                 }
470                                 return dynamicSelectedLinkStyle;
471                         }
472                 }
473
474                 internal Style StaticSelectedLinkStyle {
475                         get {
476                                 if (staticSelectedLinkStyle == null) {
477                                         staticSelectedLinkStyle = new Style ();
478                                 }
479                                 return staticSelectedLinkStyle;
480                         }
481                 }
482
483                 internal Style DynamicHoverLinkStyle {
484                         get {
485                                 if (dynamicHoverLinkStyle == null) {
486                                         dynamicHoverLinkStyle = new Style ();
487                                 }
488                                 return dynamicHoverLinkStyle;
489                         }
490                 }
491
492                 internal Style StaticHoverLinkStyle {
493                         get {
494                                 if (staticHoverLinkStyle == null) {
495                                         staticHoverLinkStyle = new Style ();
496                                 }
497                                 return staticHoverLinkStyle;
498                         }
499                 }
500
501                 internal MenuItemStyle StaticMenuItemStyleInternal {
502                         get { return staticMenuItemStyle; }
503                 }
504
505                 internal SubMenuStyle StaticMenuStyleInternal {
506                         get { return staticMenuStyle; }
507                 }
508
509                 internal MenuItemStyle DynamicMenuItemStyleInternal {
510                         get { return dynamicMenuItemStyle; }
511                 }
512
513                 internal SubMenuStyle DynamicMenuStyleInternal {
514                         get { return dynamicMenuStyle; }
515                 }
516
517                 internal MenuItemStyleCollection LevelMenuItemStylesInternal {
518                         get { return levelMenuItemStyles; }
519                 }
520
521                 internal List<Style> LevelMenuItemLinkStyles {
522                         get { return null; }
523                 }
524
525                 internal SubMenuStyleCollection LevelSubMenuStylesInternal {
526                         get { return levelSubMenuStyles; }
527                 }
528
529                 internal MenuItemStyle StaticSelectedStyleInternal {
530                         get { return staticSelectedStyle; }
531                 }
532
533                 internal MenuItemStyle DynamicSelectedStyleInternal {
534                         get { return dynamicSelectedStyle; }
535                 }
536
537                 internal MenuItemStyleCollection LevelSelectedStylesInternal {
538                         get { return levelSelectedStyles; }
539                 }
540
541                 internal List<Style> LevelSelectedLinkStyles {
542                         get { return null; }
543                 }
544
545                 internal Style StaticHoverStyleInternal {
546                         get { return staticHoverStyle; }
547                 }
548
549                 internal Style DynamicHoverStyleInternal {
550                         get { return dynamicHoverStyle; }
551                 }
552                 
553                 [PersistenceMode (PersistenceMode.InnerProperty)]
554                 [NotifyParentProperty (true)]
555                 [DefaultValue (null)]
556                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
557                 public MenuItemStyle DynamicMenuItemStyle {
558                         get {
559                                 if (dynamicMenuItemStyle == null) {
560                                         dynamicMenuItemStyle = new MenuItemStyle ();
561                                         if (IsTrackingViewState)
562                                                 dynamicMenuItemStyle.TrackViewState();
563                                 }
564                                 return dynamicMenuItemStyle;
565                         }
566                 }
567                 
568                 [PersistenceMode (PersistenceMode.InnerProperty)]
569                 [NotifyParentProperty (true)]
570                 [DefaultValue (null)]
571                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
572                 public MenuItemStyle DynamicSelectedStyle {
573                         get {
574                                 if (dynamicSelectedStyle == null) {
575                                         dynamicSelectedStyle = new MenuItemStyle ();
576                                         if (IsTrackingViewState)
577                                                 dynamicSelectedStyle.TrackViewState();
578                                 }
579                                 return dynamicSelectedStyle;
580                         }
581                 }
582                 
583                 [PersistenceMode (PersistenceMode.InnerProperty)]
584                 [NotifyParentProperty (true)]
585                 [DefaultValue (null)]
586                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
587                 public SubMenuStyle DynamicMenuStyle {
588                         get {
589                                 if (dynamicMenuStyle == null) {
590                                         dynamicMenuStyle = new SubMenuStyle ();
591                                         if (IsTrackingViewState)
592                                                 dynamicMenuStyle.TrackViewState();
593                                 }
594                                 return dynamicMenuStyle;
595                         }
596                 }
597                 
598                 [PersistenceMode (PersistenceMode.InnerProperty)]
599                 [NotifyParentProperty (true)]
600                 [DefaultValue (null)]
601                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
602                 public MenuItemStyle StaticMenuItemStyle {
603                         get {
604                                 if (staticMenuItemStyle == null) {
605                                         staticMenuItemStyle = new MenuItemStyle ();
606                                         if (IsTrackingViewState)
607                                                 staticMenuItemStyle.TrackViewState();
608                                 }
609                                 return staticMenuItemStyle;
610                         }
611                 }
612                 
613                 [PersistenceMode (PersistenceMode.InnerProperty)]
614                 [NotifyParentProperty (true)]
615                 [DefaultValue (null)]
616                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
617                 public MenuItemStyle StaticSelectedStyle {
618                         get {
619                                 if (staticSelectedStyle == null) {
620                                         staticSelectedStyle = new MenuItemStyle ();
621                                         if (IsTrackingViewState)
622                                                 staticSelectedStyle.TrackViewState();
623                                 }
624                                 return staticSelectedStyle;
625                         }
626                 }
627                 
628                 [PersistenceMode (PersistenceMode.InnerProperty)]
629                 [NotifyParentProperty (true)]
630                 [DefaultValue (null)]
631                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
632                 public SubMenuStyle StaticMenuStyle {
633                         get {
634                                 if (staticMenuStyle == null) {
635                                         staticMenuStyle = new SubMenuStyle ();
636                                         if (IsTrackingViewState)
637                                                 staticMenuStyle.TrackViewState();
638                                 }
639                                 return staticMenuStyle;
640                         }
641                 }
642
643                 [DefaultValue (null)]
644                 [PersistenceMode (PersistenceMode.InnerProperty)]
645                 [Editor ("System.Web.UI.Design.WebControls.MenuItemStyleCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
646                 public MenuItemStyleCollection LevelMenuItemStyles {
647                         get {
648                                 if (levelMenuItemStyles == null) {
649                                         levelMenuItemStyles = new MenuItemStyleCollection ();
650                                         if (IsTrackingViewState)
651                                                 ((IStateManager)levelMenuItemStyles).TrackViewState();
652                                 }
653                                 return levelMenuItemStyles;
654                         }
655                 }
656
657                 [DefaultValue (null)]
658                 [PersistenceMode (PersistenceMode.InnerProperty)]
659                 [Editor ("System.Web.UI.Design.WebControls.MenuItemStyleCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
660                 public MenuItemStyleCollection LevelSelectedStyles {
661                         get {
662                                 if (levelSelectedStyles == null) {
663                                         levelSelectedStyles = new MenuItemStyleCollection ();
664                                         if (IsTrackingViewState)
665                                                 ((IStateManager)levelSelectedStyles).TrackViewState();
666                                 }
667                                 return levelSelectedStyles;
668                         }
669                 }
670
671                 [DefaultValue (null)]
672                 [PersistenceMode (PersistenceMode.InnerProperty)]
673                 [Editor ("System.Web.UI.Design.WebControls.SubMenuStyleCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
674                 public SubMenuStyleCollection LevelSubMenuStyles {
675                         get {
676                                 if (levelSubMenuStyles == null) {
677                                         levelSubMenuStyles = new SubMenuStyleCollection ();
678                                         if (IsTrackingViewState)
679                                                 ((IStateManager)levelSubMenuStyles).TrackViewState();
680                                 }
681                                 return levelSubMenuStyles;
682                         }
683                 }
684
685                 [PersistenceMode (PersistenceMode.InnerProperty)]
686                 [NotifyParentProperty (true)]
687                 [DefaultValue (null)]
688                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
689                 public Style DynamicHoverStyle {
690                         get {
691                                 if (dynamicHoverStyle == null) {
692                                         dynamicHoverStyle = new Style ();
693                                         if (IsTrackingViewState)
694                                                 dynamicHoverStyle.TrackViewState();
695                                 }
696                                 return dynamicHoverStyle;
697                         }
698                 }
699                 
700                 [PersistenceMode (PersistenceMode.InnerProperty)]
701                 [NotifyParentProperty (true)]
702                 [DefaultValue (null)]
703                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
704                 public Style StaticHoverStyle {
705                         get {
706                                 if (staticHoverStyle == null) {
707                                         staticHoverStyle = new Style ();
708                                         if (IsTrackingViewState)
709                                                 staticHoverStyle.TrackViewState();
710                                 }
711                                 return staticHoverStyle;
712                         }
713                 }
714                 
715                 [DefaultValue ("")]
716                 [UrlProperty]
717                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
718                 public string ScrollDownImageUrl {
719                         get {
720                                 object o = ViewState ["sdiu"];
721                                 if (o != null) return (string)o;
722                                 return "";
723                         }
724                         set {
725                                 ViewState["sdiu"] = value;
726                         }
727                 }
728
729                 [DefaultValue ("")]
730                 [UrlProperty]
731                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
732                 public string ScrollUpImageUrl {
733                         get {
734                                 object o = ViewState ["suiu"];
735                                 if (o != null) return (string)o;
736                                 return "";
737                         }
738                         set {
739                                 ViewState["suiu"] = value;
740                         }
741                 }
742
743                 [Localizable (true)]
744                 public string ScrollDownText {
745                         get {
746                                 object o = ViewState ["ScrollDownText"];
747                                 if (o != null) return (string) o;
748                                 return Locale.GetText ("Scroll down");
749                         }
750                         set {
751                                 ViewState["ScrollDownText"] = value;
752                         }
753                 }
754
755                 [Localizable (true)]
756                 public string ScrollUpText {
757                         get {
758                                 object o = ViewState ["ScrollUpText"];
759                                 if (o != null) return (string) o;
760                                 return Locale.GetText ("Scroll up");
761                         }
762                         set {
763                                 ViewState["ScrollUpText"] = value;
764                         }
765                 }
766
767                 public string DynamicPopOutImageTextFormatString 
768                 {
769                         get
770                         {
771                                 object o = ViewState ["dpoitf"];
772                                 if (o != null) return (string) o;
773                                 return Locale.GetText ("Expand {0}");
774                         }
775                         set
776                         {
777                                 ViewState ["dpoitf"] = value;
778                         }
779                 }
780                 
781
782                 [DefaultValue ("")]
783                 [UrlProperty]
784                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
785                 public string DynamicPopOutImageUrl {
786                         get {
787                                 object o = ViewState ["dpoiu"];
788                                 if (o != null) return (string)o;
789                                 return "";
790                         }
791                         set {
792                                 ViewState["dpoiu"] = value;
793                         }
794                 }
795
796                 public string StaticPopOutImageTextFormatString
797                 {
798                         get
799                         {
800                                 object o = ViewState ["spoitf"];
801                                 if (o != null) return (string) o;
802                                 return Locale.GetText ("Expand {0}");
803                         }
804                         set
805                         {
806                                 ViewState ["spoitf"] = value;
807                         }
808                 }
809
810
811                 [DefaultValue ("")]
812                 [UrlProperty]
813                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
814                 public string StaticPopOutImageUrl {
815                         get {
816                                 object o = ViewState ["spoiu"];
817                                 if (o != null) return (string)o;
818                                 return "";
819                         }
820                         set {
821                                 ViewState["spoiu"] = value;
822                         }
823                 }
824
825                 [DefaultValue ("")]
826                 public string Target {
827                         get {
828                                 object o = ViewState ["Target"];
829                                 if (o != null) return (string) o;
830                                 return "";
831                         }
832                         set {
833                                 ViewState["Target"] = value;
834                         }
835                 }
836
837                 [DefaultValue (null)]
838                 [TemplateContainer (typeof(MenuItemTemplateContainer), BindingDirection.OneWay)]
839                 [PersistenceMode (PersistenceMode.InnerProperty)]
840                 [Browsable (false)]
841                 public ITemplate StaticItemTemplate {
842                         get { return staticItemTemplate; }
843                         set { staticItemTemplate = value; }
844                 }
845                 
846                 [DefaultValue (null)]
847                 [TemplateContainer (typeof(MenuItemTemplateContainer), BindingDirection.OneWay)]
848                 [PersistenceMode (PersistenceMode.InnerProperty)]
849                 [Browsable (false)]
850                 public ITemplate DynamicItemTemplate {
851                         get { return dynamicItemTemplate; }
852                         set { dynamicItemTemplate = value; }
853                 }
854                 
855                 [Browsable (false)]
856                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
857                 public MenuItem SelectedItem {
858                         get {
859                                 if (selectedItem == null && selectedItemPath != null) {
860                                         selectedItem = FindItemByPos (selectedItemPath);
861                                 }
862                                 
863                                 return selectedItem;
864                         }
865                 }
866
867                 [Browsable (false)]
868                 [DefaultValue ("")]
869                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
870                 public string SelectedValue {
871                         get { return selectedItem != null ? selectedItem.Value : ""; }
872                 }
873
874                 [Localizable (true)]
875                 public string SkipLinkText 
876                 {
877                         get {
878                                 object o = ViewState ["SkipLinkText"];
879                                 if (o != null)
880                                         return (string) o;
881                                 return "Skip Navigation Links";
882                         }
883                         set {
884                                 ViewState ["SkipLinkText"] = value;
885                         }
886                 }
887                 
888                 IMenuRenderer CreateRenderer (IMenuRenderer current)
889                 {
890                         Type newType = null;
891                         
892                         switch (RenderingMode) {
893                                 case MenuRenderingMode.Default:
894                                         if (RenderingCompatibilityLessThan40)
895                                                 newType = typeof (MenuTableRenderer);
896                                         else
897                                                 newType = typeof (MenuListRenderer);
898                                         break;
899                                         
900                                 case MenuRenderingMode.Table:
901                                         newType = typeof (MenuTableRenderer);
902                                         break;
903
904                                 case MenuRenderingMode.List:
905                                         newType = typeof (MenuListRenderer);
906                                         break;
907                         }
908
909                         if (newType == null)
910                                 return null;
911
912                         if (current == null || current.GetType () != newType)
913                                 return Activator.CreateInstance (newType, this) as IMenuRenderer;
914                         return current;
915                 }
916                 
917                 internal void SetSelectedItem (MenuItem item)
918                 {
919                         if (selectedItem == item) return;
920                         selectedItem = item;
921                         selectedItemPath = item.Path;
922                 }
923                 
924                 public MenuItem FindItem (string valuePath)
925                 {
926                         if (valuePath == null) throw new ArgumentNullException ("valuePath");
927                         string[] path = valuePath.Split (PathSeparator);
928                         int n = 0;
929                         MenuItemCollection col = Items;
930                         bool foundBranch = true;
931                         while (col.Count > 0 && foundBranch) {
932                                 foundBranch = false;
933                                 foreach (MenuItem item in col) {
934                                         if (item.Value == path [n]) {
935                                                 if (++n == path.Length) return item;
936                                                 col = item.ChildItems;
937                                                 foundBranch = true;
938                                                 break;
939                                         }
940                                 }
941                         }
942                         return null;
943                 }
944                 
945                 string GetBindingKey (string dataMember, int depth)
946                 {
947                         return dataMember + " " + depth;
948                 }
949                 
950                 internal MenuItemBinding FindBindingForItem (string type, int depth)
951                 {
952                         if (bindings == null) return null;
953
954                         MenuItemBinding bin = (MenuItemBinding) bindings [GetBindingKey (type, depth)];
955                         if (bin != null) return bin;
956                         
957                         bin = (MenuItemBinding) bindings [GetBindingKey (type, -1)];
958                         if (bin != null) return bin;
959                         
960                         bin = (MenuItemBinding) bindings [GetBindingKey ("", depth)];
961                         if (bin != null) return bin;
962                         
963                         bin = (MenuItemBinding) bindings [GetBindingKey ("", -1)];
964                         return bin;
965                 }
966                 
967                 protected internal override void PerformDataBinding ()
968                 {
969                         base.PerformDataBinding ();
970
971                         // Do not attempt to bind data if there is no
972                         // data source set.
973                         if (!IsBoundUsingDataSourceID && (DataSource == null)) {
974                                 EnsureChildControlsDataBound ();
975                                 return;
976                         }
977
978                         InitializeDataBindings ();
979
980                         HierarchicalDataSourceView data = GetData ("");
981
982                         if (data == null) {
983                                 throw new InvalidOperationException ("No view returned by data source control.");
984                         }
985                         Items.Clear ();
986                         IHierarchicalEnumerable e = data.Select ();
987                         FillBoundChildrenRecursive (e, Items);
988
989                         CreateChildControlsForItems ();
990                         ChildControlsCreated = true;
991
992                         EnsureChildControlsDataBound ();
993                 }
994
995                 void FillBoundChildrenRecursive (IHierarchicalEnumerable hEnumerable, MenuItemCollection itemCollection)
996                 {
997                         if (hEnumerable == null)
998                                 return;
999                         foreach (object obj in hEnumerable) {
1000                                 IHierarchyData hdata = hEnumerable.GetHierarchyData (obj);
1001                                 MenuItem item = new MenuItem ();
1002                                 itemCollection.Add (item);
1003                                 item.Bind (hdata);
1004
1005                                 SiteMapNode siteMapNode = hdata as SiteMapNode;
1006                                 if (siteMapNode != null) {
1007                                         if (_currSiteMapNode == null)
1008                                                 _currSiteMapNode = siteMapNode.Provider.CurrentNode;
1009                                         if (siteMapNode == _currSiteMapNode)
1010                                                 item.Selected = true;
1011                                 }
1012                                 
1013                                 OnMenuItemDataBound (new MenuEventArgs (item));
1014
1015                                 if (hdata == null || !hdata.HasChildren)
1016                                         continue;
1017
1018                                 IHierarchicalEnumerable e = hdata.GetChildren ();
1019                                 FillBoundChildrenRecursive (e, item.ChildItems);
1020                         }
1021                 }
1022                 
1023                 protected void SetItemDataBound (MenuItem node, bool dataBound)
1024                 {
1025                         node.SetDataBound (dataBound);
1026                 }
1027                 
1028                 protected void SetItemDataPath (MenuItem node, string dataPath)
1029                 {
1030                         node.SetDataPath (dataPath);
1031                 }
1032                 
1033                 protected void SetItemDataItem (MenuItem node, object dataItem)
1034                 {
1035                         node.SetDataItem (dataItem);
1036                 }
1037                 
1038                 protected internal virtual void RaisePostBackEvent (string eventArgument)
1039                 {
1040                         ValidateEvent (UniqueID, eventArgument);
1041                         if (!IsEnabled)
1042                                 return;
1043
1044                         EnsureChildControls();
1045                         MenuItem item = FindItemByPos (eventArgument);
1046                         if (item == null) return;
1047                         item.Selected = true;
1048                         OnMenuItemClick (new MenuEventArgs (item));
1049                 }
1050
1051                 void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
1052                 {
1053                         RaisePostBackEvent (eventArgument);
1054                 }
1055                 
1056                 MenuItem FindItemByPos (string path)
1057                 {
1058                         string[] indexes = path.Split ('_');
1059                         MenuItem item = null;
1060                         
1061                         foreach (string index in indexes) {
1062                                 int i = int.Parse (index);
1063                                 if (item == null) {
1064                                         if (i >= Items.Count) return null;
1065                                         item = Items [i];
1066                                 } else {
1067                                         if (i >= item.ChildItems.Count) return null;
1068                                         item = item.ChildItems [i];
1069                                 }
1070                         }
1071                         return item;
1072                 }
1073                 
1074                 protected override HtmlTextWriterTag TagKey {
1075                         get { return Renderer.Tag; }
1076                 }
1077                 
1078                 protected override void TrackViewState()
1079                 {
1080                         EnsureDataBound ();
1081                         
1082                         base.TrackViewState();
1083                         if (dataBindings != null) {
1084                                 ((IStateManager)dataBindings).TrackViewState ();
1085                         }
1086                         if (items != null) {
1087                                 ((IStateManager)items).TrackViewState();
1088                         }
1089                         if (dynamicMenuItemStyle != null)
1090                                 dynamicMenuItemStyle.TrackViewState ();
1091                         if (dynamicMenuStyle != null)
1092                                 dynamicMenuStyle.TrackViewState ();
1093                         if (levelMenuItemStyles != null && levelMenuItemStyles.Count > 0)
1094                                 ((IStateManager)levelMenuItemStyles).TrackViewState();
1095                         if (levelSelectedStyles != null && levelMenuItemStyles.Count > 0)
1096                                 ((IStateManager)levelSelectedStyles).TrackViewState();
1097                         if (levelSubMenuStyles != null && levelSubMenuStyles.Count > 0)
1098                                 ((IStateManager)levelSubMenuStyles).TrackViewState();
1099                         if (dynamicSelectedStyle != null)
1100                                 dynamicSelectedStyle.TrackViewState();
1101                         if (staticMenuItemStyle != null)
1102                                 staticMenuItemStyle.TrackViewState ();
1103                         if (staticMenuStyle != null)
1104                                 staticMenuStyle.TrackViewState ();
1105                         if (staticSelectedStyle != null)
1106                                 staticSelectedStyle.TrackViewState();
1107                         if (staticHoverStyle != null)
1108                                 staticHoverStyle.TrackViewState();
1109                         if (dynamicHoverStyle != null)
1110                                 dynamicHoverStyle.TrackViewState();
1111                 }
1112
1113                 protected override object SaveViewState()
1114                 {
1115                         object[] states = new object [14];
1116                         states[0] = base.SaveViewState ();
1117                         states[1] = dataBindings == null ? null : ((IStateManager)dataBindings).SaveViewState();
1118                         states[2] = items == null ? null : ((IStateManager)items).SaveViewState();
1119                         states[3] = dynamicMenuItemStyle == null ? null : dynamicMenuItemStyle.SaveViewState();
1120                         states[4] = dynamicMenuStyle == null ? null : dynamicMenuStyle.SaveViewState();
1121                         states[5] = levelMenuItemStyles == null ? null : ((IStateManager)levelMenuItemStyles).SaveViewState();
1122                         states[6] = levelSelectedStyles == null ? null : ((IStateManager)levelSelectedStyles).SaveViewState();
1123                         states[7] = dynamicSelectedStyle == null ? null : dynamicSelectedStyle.SaveViewState();
1124                         states[8] = (staticMenuItemStyle == null ? null : staticMenuItemStyle.SaveViewState());
1125                         states[9] = staticMenuStyle == null ? null : staticMenuStyle.SaveViewState();
1126                         states[10] = staticSelectedStyle == null ? null : staticSelectedStyle.SaveViewState();
1127                         states[11] = staticHoverStyle == null ? null : staticHoverStyle.SaveViewState();
1128                         states[12] = dynamicHoverStyle == null ? null : dynamicHoverStyle.SaveViewState();
1129                         states[13] = levelSubMenuStyles == null ? null : ((IStateManager)levelSubMenuStyles).SaveViewState();
1130
1131                         for (int i = states.Length - 1; i >= 0; i--) {
1132                                 if (states [i] != null)
1133                                         return states;
1134                         }
1135
1136                         return null;
1137                 }
1138
1139                 protected override void LoadViewState (object state)
1140                 {
1141                         if (state == null)
1142                                 return;
1143
1144                         object [] states = (object []) state;
1145                         base.LoadViewState (states[0]);
1146                         
1147                         if (states[1] != null)
1148                                 ((IStateManager)DataBindings).LoadViewState(states[1]);
1149                         if (states[2] != null)
1150                                 ((IStateManager)Items).LoadViewState(states[2]);
1151                         if (states[3] != null)
1152                                 DynamicMenuItemStyle.LoadViewState (states[3]);
1153                         if (states[4] != null)
1154                                 DynamicMenuStyle.LoadViewState (states[4]);
1155                         if (states[5] != null)
1156                                 ((IStateManager)LevelMenuItemStyles).LoadViewState(states[5]);
1157                         if (states[6] != null)
1158                                 ((IStateManager)LevelSelectedStyles).LoadViewState(states[6]);
1159                         if (states[7] != null)
1160                                 DynamicSelectedStyle.LoadViewState (states[7]);
1161                         if (states[8] != null)
1162                                 StaticMenuItemStyle.LoadViewState (states[8]);
1163                         if (states[9] != null)
1164                                 StaticMenuStyle.LoadViewState (states[9]);
1165                         if (states[10] != null)
1166                                 StaticSelectedStyle.LoadViewState (states[10]);
1167                         if (states[11] != null)
1168                                 StaticHoverStyle.LoadViewState (states[11]);
1169                         if (states[12] != null)
1170                                 DynamicHoverStyle.LoadViewState (states[12]);
1171                         if (states[13] != null)
1172                                 ((IStateManager)LevelSubMenuStyles).LoadViewState(states[13]);
1173                 }
1174                 
1175                 protected internal override void OnInit (EventArgs e)
1176                 {
1177                         Page.RegisterRequiresControlState (this);
1178                         base.OnInit (e);
1179                 }
1180                 
1181                 protected internal override void LoadControlState (object savedState)
1182                 {
1183                         if (savedState == null) return;
1184                         object[] state = (object[]) savedState;
1185                         base.LoadControlState (state[0]);
1186                         selectedItemPath = state[1] as string;
1187                 }
1188                 
1189                 protected internal override object SaveControlState ()
1190                 {
1191                         object bstate = base.SaveControlState ();
1192                         object mstate = selectedItemPath;
1193                         
1194                         if (bstate != null || mstate != null)
1195                                 return new object[] { bstate, mstate };
1196                         else
1197                                 return null;
1198                 }
1199                 
1200                 protected internal override void CreateChildControls ()
1201                 {
1202                         if (!IsBoundUsingDataSourceID && (DataSource == null)) {
1203                                 CreateChildControlsForItems ();
1204                         }
1205                         else {
1206                                 EnsureDataBound ();
1207                         }
1208                 }
1209
1210                 void CreateChildControlsForItems () {
1211                         Controls.Clear ();
1212                         // Check for HasChildViewState to avoid unnecessary calls to ClearChildViewState.
1213                         if (HasChildViewState)
1214                                 ClearChildViewState ();
1215                         _menuItemControls = new Hashtable ();
1216                         CreateChildControlsForItems (Items);
1217                         _requiresChildControlsDataBinding = true;
1218                 }
1219
1220                 void CreateChildControlsForItems (MenuItemCollection items )
1221                 {
1222                         IMenuRenderer renderer = Renderer;
1223                         foreach (MenuItem item in items) {
1224                                 bool isDynamicItem = renderer.IsDynamicItem (this, item);
1225                                 if (isDynamicItem && dynamicItemTemplate != null) {
1226                                         MenuItemTemplateContainer cter = new MenuItemTemplateContainer (item.Index, item);
1227                                         dynamicItemTemplate.InstantiateIn (cter);
1228                                         _menuItemControls [item] = cter;
1229                                         Controls.Add (cter);
1230                                 }
1231                                 else if (!isDynamicItem && staticItemTemplate != null) {
1232                                         MenuItemTemplateContainer cter = new MenuItemTemplateContainer (item.Index, item);
1233                                         staticItemTemplate.InstantiateIn (cter);
1234                                         _menuItemControls [item] = cter;
1235                                         Controls.Add (cter);
1236                                 }
1237                                 if (item.HasChildData)
1238                                         CreateChildControlsForItems (item.ChildItems);
1239                         }
1240                 }
1241
1242                 protected override void EnsureDataBound ()
1243                 {
1244                         base.EnsureDataBound ();
1245                         
1246                         EnsureChildControlsDataBound ();
1247                 }
1248
1249                 void EnsureChildControlsDataBound () {
1250                         if (!_requiresChildControlsDataBinding)
1251                                 return;
1252                         DataBindChildren ();
1253                         _requiresChildControlsDataBinding = false;
1254                 }
1255
1256                 [MonoTODO ("Not implemented")]
1257                 protected override IDictionary GetDesignModeState ()
1258                 {
1259                         throw new NotImplementedException ();
1260                 }
1261
1262                 [MonoTODO ("Not implemented")]
1263                 protected override void SetDesignModeState (IDictionary data)
1264                 {
1265                         throw new NotImplementedException ();
1266                 }
1267                                 
1268                 public override ControlCollection Controls {
1269                         get { return base.Controls; }
1270                 }
1271                 
1272                 public sealed override void DataBind ()
1273                 {
1274                         base.DataBind ();
1275                 }
1276                 
1277                 protected override bool OnBubbleEvent (object source, EventArgs e)
1278                 {
1279                         if (!(e is CommandEventArgs))
1280                                 return false;
1281
1282                         MenuEventArgs menuArgs = e as MenuEventArgs;
1283                         if (menuArgs != null && string.Equals (menuArgs.CommandName, MenuItemClickCommandName))
1284                                 OnMenuItemClick (menuArgs);
1285                         return true;
1286                 }
1287
1288                 protected override void OnDataBinding (EventArgs e)
1289                 {
1290                         EnsureChildControls ();
1291                         base.OnDataBinding (e);
1292                 }
1293                 
1294                 protected internal override void OnPreRender (EventArgs e)
1295                 {
1296                         base.OnPreRender (e);
1297
1298                         string cmenu = ClientID + "_data";
1299                         StringBuilder script = new StringBuilder ();
1300                         Page page = Page;
1301                         HtmlHead header;
1302                         ClientScriptManager csm;
1303
1304                         if (page != null) {
1305                                 header = page.Header;
1306                                 csm = page.ClientScript;
1307                         } else {
1308                                 header = null;
1309                                 csm = null;
1310                         }
1311                         
1312                         Renderer.PreRender (page, header, csm, cmenu, script);
1313
1314                         if (csm != null) {
1315                                 csm.RegisterWebFormClientScript ();
1316                                 csm.RegisterStartupScript (typeof(Menu), ClientID, script.ToString (), true);
1317                         }
1318                 }
1319
1320                 void InitializeDataBindings () {
1321                         if (dataBindings != null && dataBindings.Count > 0) {
1322                                 bindings = new Hashtable ();
1323                                 foreach (MenuItemBinding bin in dataBindings) {
1324                                         string key = GetBindingKey (bin.DataMember, bin.Depth);
1325                                         bindings [key] = bin;
1326                                 }
1327                         }
1328                         else
1329                                 bindings = null;
1330                 }
1331                 
1332                 protected internal override void Render (HtmlTextWriter writer)
1333                 {
1334                         if (Items.Count > 0)
1335                                 base.Render (writer);
1336                 }
1337                 
1338                 protected override void AddAttributesToRender (HtmlTextWriter writer)
1339                 {
1340                         Renderer.AddAttributesToRender (writer);
1341                         base.AddAttributesToRender (writer);
1342                 }
1343                 
1344                 public override void RenderBeginTag (HtmlTextWriter writer)
1345                 {
1346                         string skipLinkText = SkipLinkText;
1347                         if (!String.IsNullOrEmpty (skipLinkText))
1348                                 Renderer.RenderBeginTag (writer, skipLinkText);
1349                         base.RenderBeginTag (writer);
1350                 }
1351                 
1352                 public override void RenderEndTag (HtmlTextWriter writer)
1353                 {
1354                         base.RenderEndTag (writer);
1355
1356                         Renderer.RenderEndTag (writer);
1357                         
1358                         string skipLinkText = SkipLinkText;
1359                         if (!String.IsNullOrEmpty (skipLinkText)) {
1360                                 writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID + "_SkipLink");
1361                                 writer.RenderBeginTag (HtmlTextWriterTag.A);
1362                                 writer.RenderEndTag ();
1363                         }
1364                 }
1365                 
1366                 protected internal override void RenderContents (HtmlTextWriter writer)
1367                 {
1368                         Renderer.RenderContents (writer);
1369                 }
1370
1371                 internal void RenderDynamicMenu (HtmlTextWriter writer, MenuItemCollection items)
1372                 {
1373                         for (int n = 0; n < items.Count; n++) {
1374                                 if (DisplayChildren (items [n])) {
1375                                         RenderDynamicMenu (writer, items [n]);
1376                                         RenderDynamicMenu (writer, items [n].ChildItems);
1377                                 }
1378                         }
1379                 }
1380                 
1381                 MenuRenderHtmlTemplate _dynamicTemplate;
1382                 MenuRenderHtmlTemplate GetDynamicMenuTemplate (MenuItem item)
1383                 {
1384                         if (_dynamicTemplate != null) 
1385                                 return _dynamicTemplate;
1386
1387                         _dynamicTemplate = new MenuRenderHtmlTemplate ();
1388                         HtmlTextWriter writer = _dynamicTemplate.GetMenuTemplateWriter ();
1389
1390                         if (Page.Header != null) {
1391                                 writer.AddAttribute (HtmlTextWriterAttribute.Class, MenuRenderHtmlTemplate.GetMarker (0));
1392                         }
1393                         else {
1394                                 writer.AddAttribute (HtmlTextWriterAttribute.Style, MenuRenderHtmlTemplate.GetMarker (0));
1395                         }
1396
1397                         writer.AddStyleAttribute ("visibility", "hidden");
1398                         writer.AddStyleAttribute ("position", "absolute");
1399                         writer.AddStyleAttribute ("z-index", "1");
1400                         writer.AddStyleAttribute ("left", "0px");
1401                         writer.AddStyleAttribute ("top", "0px");
1402                         writer.AddAttribute ("id", MenuRenderHtmlTemplate.GetMarker (1));
1403                         writer.RenderBeginTag (HtmlTextWriterTag.Div);
1404
1405                         // Up button
1406                         writer.AddAttribute ("id", MenuRenderHtmlTemplate.GetMarker (2));
1407                         writer.AddStyleAttribute ("display", "block");
1408                         writer.AddStyleAttribute ("text-align", "center");
1409                         writer.AddAttribute ("onmouseover", string.Concat ("Menu_OverScrollBtn ('", ClientID, "','", MenuRenderHtmlTemplate.GetMarker (3), "','u')"));
1410                         writer.AddAttribute ("onmouseout", string.Concat ("Menu_OutScrollBtn ('", ClientID, "','", MenuRenderHtmlTemplate.GetMarker (4), "','u')")); 
1411                         writer.RenderBeginTag (HtmlTextWriterTag.Div);
1412                         
1413                         writer.AddAttribute ("src", MenuRenderHtmlTemplate.GetMarker (5)); //src
1414                         writer.AddAttribute ("alt", MenuRenderHtmlTemplate.GetMarker (6)); //ScrollUpText
1415                         writer.RenderBeginTag (HtmlTextWriterTag.Img);
1416                         writer.RenderEndTag (); // IMG
1417                         
1418                         writer.RenderEndTag (); // DIV scroll button
1419                 
1420                         writer.AddAttribute ("id", MenuRenderHtmlTemplate.GetMarker (7));
1421                         writer.RenderBeginTag (HtmlTextWriterTag.Div);
1422                         writer.AddAttribute ("id", MenuRenderHtmlTemplate.GetMarker (8));
1423                         writer.RenderBeginTag (HtmlTextWriterTag.Div);
1424                         
1425                         // call of RenderMenu
1426                         writer.Write (MenuRenderHtmlTemplate.GetMarker (9));
1427                         
1428                         writer.RenderEndTag (); // DIV Content
1429                         writer.RenderEndTag (); // DIV Scroll container
1430
1431                         // Down button
1432                         writer.AddAttribute ("id", MenuRenderHtmlTemplate.GetMarker (0));
1433                         writer.AddStyleAttribute ("display", "block");
1434                         writer.AddStyleAttribute ("text-align", "center");
1435                         writer.AddAttribute ("onmouseover", string.Concat ("Menu_OverScrollBtn ('", ClientID, "','", MenuRenderHtmlTemplate.GetMarker (1), "','d')"));
1436                         writer.AddAttribute ("onmouseout", string.Concat ("Menu_OutScrollBtn ('", ClientID, "','", MenuRenderHtmlTemplate.GetMarker (2), "','d')")); 
1437                         writer.RenderBeginTag (HtmlTextWriterTag.Div);
1438                         
1439                         writer.AddAttribute ("src", MenuRenderHtmlTemplate.GetMarker (3)); //src
1440                         writer.AddAttribute ("alt", MenuRenderHtmlTemplate.GetMarker (4)); //ScrollDownText
1441                         writer.RenderBeginTag (HtmlTextWriterTag.Img);
1442                         writer.RenderEndTag (); // IMG
1443                         
1444                         writer.RenderEndTag (); // DIV scroll button
1445                         
1446                         writer.RenderEndTag (); // DIV menu
1447
1448                         _dynamicTemplate.Parse ();
1449                         return _dynamicTemplate;
1450                 }
1451
1452                 void RenderDynamicMenu (HtmlTextWriter writer, MenuItem item)
1453                 {
1454                         _dynamicTemplate = GetDynamicMenuTemplate (item);
1455
1456                         string idPrefix = ClientID + "_" + item.Path;
1457                         string [] param = new string [9];
1458                         param [0] = GetCssMenuStyle (true, item.Depth + 1);
1459                         param [1] = idPrefix + "s";
1460                         param [2] = idPrefix + "cu";
1461                         param [3] = item.Path;
1462                         param [4] = item.Path;
1463                         param [5] = ScrollUpImageUrl != "" ? ScrollUpImageUrl : Page.ClientScript.GetWebResourceUrl (typeof (Menu), "arrow_up.gif");
1464                         param [6] = ScrollUpText;
1465                         param [7] = idPrefix + "cb";
1466                         param [8] = idPrefix + "cc";
1467
1468                         _dynamicTemplate.RenderTemplate (writer, param, 0, param.Length);
1469
1470                         RenderMenu (writer, item.ChildItems, true, true, item.Depth + 1, false);
1471
1472                         string [] param2 = new string [5];
1473                         param2 [0] = idPrefix + "cd";
1474                         param2 [1] = item.Path;
1475                         param2 [2] = item.Path;
1476                         param2 [3] = ScrollDownImageUrl != "" ? ScrollDownImageUrl : Page.ClientScript.GetWebResourceUrl (typeof (Menu), "arrow_down.gif");
1477                         param2 [4] = ScrollDownText;
1478
1479                         _dynamicTemplate.RenderTemplate (writer, param2, param.Length + 1, param2.Length);
1480
1481                 }
1482
1483                 string GetCssMenuStyle (bool dynamic, int menuLevel)
1484                 {
1485                         if (Page.Header != null) {
1486                                 // styles are registered
1487                                 StringBuilder sb = new StringBuilder ();
1488
1489                                 if (!dynamic && staticMenuStyle != null) {
1490                                         sb.Append (staticMenuStyle.CssClass);
1491                                         sb.Append (' ');
1492                                         sb.Append (staticMenuStyle.RegisteredCssClass);
1493                                 }
1494                                 if (dynamic && dynamicMenuStyle != null) {
1495                                         sb.Append (PopOutBoxStyle.RegisteredCssClass);
1496                                         sb.Append (' ');
1497                                         sb.Append (dynamicMenuStyle.CssClass);
1498                                         sb.Append (' ');
1499                                         sb.Append (dynamicMenuStyle.RegisteredCssClass);
1500                                 }
1501                                 if (levelSubMenuStyles != null && levelSubMenuStyles.Count > menuLevel) {
1502                                         sb.Append (levelSubMenuStyles [menuLevel].CssClass);
1503                                         sb.Append (' ');
1504                                         sb.Append (levelSubMenuStyles [menuLevel].RegisteredCssClass); 
1505                                 }
1506                                 return sb.ToString ();
1507                         }
1508                         else {
1509                                 // styles are not registered
1510                                 SubMenuStyle style = new SubMenuStyle ();
1511
1512                                 if (!dynamic && staticMenuStyle != null) {
1513                                         style.CopyFrom (staticMenuStyle);
1514                                 }
1515                                 if (dynamic && dynamicMenuStyle != null) {
1516                                         style.CopyFrom (PopOutBoxStyle);
1517                                         style.CopyFrom (dynamicMenuStyle);
1518                                 }
1519                                 if (levelSubMenuStyles != null && levelSubMenuStyles.Count > menuLevel) {
1520                                         style.CopyFrom (levelSubMenuStyles [menuLevel]);
1521                                 }
1522                                 return style.GetStyleAttributes (null).Value;
1523                         }
1524                 }
1525
1526                 internal void RenderMenu (HtmlTextWriter writer, MenuItemCollection items, bool vertical, bool dynamic, int menuLevel, bool notLast)
1527                 {
1528                         IMenuRenderer renderer = Renderer;
1529                         
1530                         renderer.RenderMenuBeginTag (writer, dynamic, menuLevel);
1531                         renderer.RenderMenuBody (writer, items, vertical, dynamic, notLast);
1532                         renderer.RenderMenuEndTag (writer, dynamic, menuLevel);
1533                 }
1534
1535                 internal bool DisplayChildren (MenuItem item)
1536                 {
1537                         return (item.Depth + 1 < StaticDisplayLevels + MaximumDynamicDisplayLevels) && item.ChildItems.Count > 0;
1538                 }
1539                 
1540                 internal void RenderItem (HtmlTextWriter writer, MenuItem item, int position)
1541                 {
1542                         // notLast should be true if item or any of its ancestors is not a
1543                         // last child.
1544                         bool notLast = false;
1545                         MenuItem parent;
1546                         MenuItem child = item;                  
1547                         while (null != (parent = child.Parent)) {
1548                                 if (child.Index != parent.ChildItems.Count - 1) {
1549                                         notLast = true;
1550                                         break;
1551                                 }
1552                                 child = parent;
1553                         }
1554                         Renderer.RenderMenuItem (writer, item, notLast, position == 0);
1555                 }
1556
1557                 internal void RenderItemContent (HtmlTextWriter writer, MenuItem item, bool isDynamicItem)
1558                 {
1559                         if (_menuItemControls!=null && _menuItemControls [item] != null)
1560                                 ((Control) _menuItemControls [item]).Render (writer);
1561
1562                         Renderer.RenderItemContent (writer, item, isDynamicItem);
1563                 }
1564                         
1565                 internal Unit GetItemSpacing (MenuItem item, bool dynamic)
1566                 {
1567                         Unit itemSpacing = Unit.Empty;
1568                         
1569                         if (item.Selected) {
1570                                 if (levelSelectedStyles != null && item.Depth < levelSelectedStyles.Count) {
1571                                         itemSpacing = levelSelectedStyles [item.Depth].ItemSpacing;
1572                                         if (itemSpacing != Unit.Empty) return itemSpacing;
1573                                 }
1574
1575                                 if (dynamic && dynamicSelectedStyle != null)
1576                                         itemSpacing = dynamicSelectedStyle.ItemSpacing;
1577                                 else if (!dynamic && staticSelectedStyle != null)
1578                                         itemSpacing = staticSelectedStyle.ItemSpacing;
1579                                 if (itemSpacing != Unit.Empty)
1580                                         return itemSpacing;
1581                         }
1582                         
1583                         if (levelMenuItemStyles != null && item.Depth < levelMenuItemStyles.Count) {
1584                                 itemSpacing = levelMenuItemStyles [item.Depth].ItemSpacing;
1585                                 if (itemSpacing != Unit.Empty) return itemSpacing;
1586                         }
1587
1588                         if (dynamic && dynamicMenuItemStyle != null)
1589                                 return dynamicMenuItemStyle.ItemSpacing;
1590                         else if (!dynamic && staticMenuItemStyle != null)
1591                                 return staticMenuItemStyle.ItemSpacing;
1592                         else
1593                                 return Unit.Empty;
1594                 }
1595
1596                 class MenuTemplateWriter : TextWriter
1597                 {
1598                         char [] _buffer;
1599                         int _ptr = 0;
1600                         
1601                         public MenuTemplateWriter (char [] buffer)
1602                         {
1603                                 _buffer = buffer;
1604                         }
1605
1606                         public override Encoding Encoding
1607                         {
1608                                 get { return Encoding.Unicode; }
1609                         }
1610
1611                         public override void Write (char value)
1612                         {
1613                                 if (_ptr == _buffer.Length)
1614                                         EnsureCapacity ();
1615                                 
1616                                 _buffer [_ptr++] = value;
1617                         }
1618
1619                         public override void Write (string value)
1620                         {
1621                                 if (value == null)
1622                                         return;
1623
1624                                 if (_ptr + value.Length >= _buffer.Length)
1625                                         EnsureCapacity ();
1626
1627                                 for (int i = 0; i < value.Length; i++)
1628                                         _buffer [_ptr++] = value [i];
1629                         }
1630
1631                         void EnsureCapacity ()
1632                         {
1633                                 char [] tmpBuffer = new char [_buffer.Length * 2];
1634                                 Array.Copy (_buffer, tmpBuffer, _buffer.Length);
1635
1636                                 _buffer = tmpBuffer;
1637                         }
1638                 }
1639
1640                 class MenuRenderHtmlTemplate
1641                 {
1642                         public const string Marker = "\u093a\u093b\u0971";
1643                         char [] _templateHtml;
1644
1645                         MenuTemplateWriter _templateWriter;
1646                         ArrayList idxs = new ArrayList (32);
1647
1648                         public MenuRenderHtmlTemplate ()
1649                         {
1650                                 _templateHtml = new char [1024];
1651                                 _templateWriter = new MenuTemplateWriter (_templateHtml);
1652                         }
1653
1654                         public static string GetMarker (int num)
1655                         {
1656                                 char charNum = (char) ((int) '\u0971' + num);
1657                                 return string.Concat (Marker, charNum);
1658                         }
1659
1660                         public HtmlTextWriter GetMenuTemplateWriter()
1661                         {
1662                                 return new HtmlTextWriter (_templateWriter);
1663                         }
1664
1665                         public void Parse ()
1666                         {
1667                                 int mpos = 0;
1668                                 for (int i = 0; i < _templateHtml.Length; i++) {
1669                                         if (_templateHtml [i] == '\0') {
1670                                                 idxs.Add (i);
1671                                                 break;
1672                                         }
1673
1674                                         if (_templateHtml [i] != Marker [mpos]) {
1675                                                 mpos = 0;
1676                                                 continue;
1677                                         }
1678
1679                                         mpos++;
1680                                         if (mpos == Marker.Length) {
1681                                                 mpos = 0;
1682                                                 idxs.Add (i - Marker.Length + 1);
1683                                         }
1684                                 }
1685                         }
1686
1687                         public void RenderTemplate (HtmlTextWriter writer, string [] dynamicParts, int start, int count)
1688                         {
1689                                 if (idxs.Count == 0)
1690                                         return;
1691
1692                                 int partStart = 0;
1693                                 int partEnd = (start == 0) ? -Marker.Length - 1 : (int) idxs [start - 1];
1694                                 int di = 0;
1695
1696                                 int i = start;
1697                                 int total = start + count;
1698                                 for (; i < total; i++) {
1699
1700                                         partStart = partEnd + Marker.Length + 1;
1701                                         partEnd = (int) idxs [i];
1702                                         
1703                                         // write static part
1704                                         writer.Write (_templateHtml, partStart, partEnd - partStart);
1705
1706                                         // write synamic part
1707                                         di = (int) _templateHtml [partEnd + Marker.Length] - 0x971;
1708                                         writer.Write (dynamicParts [di]);
1709                                 }
1710
1711                                 partStart = partEnd + Marker.Length + 1;
1712                                 partEnd = (int) idxs [i];
1713
1714                                 writer.Write (_templateHtml, partStart, partEnd - partStart);
1715                         }
1716                 
1717                 }
1718         }
1719 }
1720