Page.Validate() is called when CausesValidation=true
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / MenuItem.cs
1 //
2 // System.Web.UI.WebControls.MenuItem.cs
3 //
4 // Authors:
5 //      Lluis Sanchez Gual (lluis@novell.com)
6 //
7 // (C) 2004 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
29 //
30
31 #if NET_2_0
32
33 using System;
34 using System.Collections;
35 using System.Text;
36 using System.ComponentModel;
37 using System.Web.UI;
38
39 namespace System.Web.UI.WebControls
40 {
41         [ParseChildrenAttribute (true, "ChildItems")]
42         public sealed class MenuItem: IStateManager, ICloneable
43         {
44                 StateBag ViewState = new StateBag ();
45                 MenuItemCollection items;
46                 bool marked;
47                 Menu menu;
48                 MenuItem parent;
49                 int index;
50                 string path;
51                 int depth = -1;
52                 
53                 object dataItem;
54                 IHierarchyData hierarchyData;
55                 
56                 bool gotBinding;
57                 MenuItemBinding binding;
58                 PropertyDescriptorCollection boundProperties;
59                 
60                 public MenuItem ()
61                 {
62                 }
63                 
64                 public MenuItem (string text)
65                 {
66                         Text = text;
67                 }
68                 
69                 public MenuItem (string text, string value)
70                 {
71                         Text = text;
72                         Value = value;
73                 }
74                 
75                 public MenuItem (string text, string value, string imageUrl)
76                 {
77                         Text = text;
78                         Value = value;
79                         ImageUrl = imageUrl;
80                 }
81                 
82                 public MenuItem (string text, string value, string imageUrl, string navigateUrl)
83                 {
84                         Text = text;
85                         Value = value;
86                         ImageUrl = imageUrl;
87                         NavigateUrl = navigateUrl;
88                 }
89                 
90                 public MenuItem (string text, string value, string imageUrl, string navigateUrl, string target)
91                 {
92                         Text = text;
93                         Value = value;
94                         ImageUrl = imageUrl;
95                         NavigateUrl = navigateUrl;
96                         Target = target;
97                 }
98                 
99                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
100                 [Browsable (false)]
101                 public int Depth {
102                         get {
103                                 if (depth != -1) return depth;
104                                 if (Parent == null) depth = 0;
105                                 else depth = Parent.Depth + 1;
106                                 return depth;
107                         }
108                 }
109                 
110                 void ResetPathData ()
111                 {
112                         path = null;
113                         depth = -1;
114                         gotBinding = false;
115                 }
116                 
117                 internal Menu Menu {
118                         get { return menu; }
119                         set {
120                                 menu = value;
121                                 if (items != null)
122                                         items.SetMenu (menu);
123                                 ResetPathData ();
124                         }
125                 }
126                 
127                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
128                 [DefaultValue (false)]
129                 [Browsable (false)]
130                 public bool DataBound {
131                         get { return ViewState ["DataBound"] == null ? false : (bool) ViewState ["DataBound"]; }
132                         private set { ViewState ["DataBound"] = value; }
133                 }
134                 
135                 [DefaultValue (null)]
136                 [Browsable (false)]
137                 public object DataItem {
138                         get {
139                                 if (!DataBound) throw new InvalidOperationException ("MenuItem is not data bound.");
140                                 return dataItem;
141                         }
142                 }
143                 
144                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
145                 [DefaultValue ("")]
146                 [Browsable (false)]
147                 public string DataPath {
148                         get {
149                                 return ViewState ["DataPath"] == null ? String.Empty : (String) ViewState ["DataPath"];
150                         }
151                         private set {
152                                 ViewState ["DataPath"] = value;
153                         }
154                 }
155                 
156                 [MergableProperty (false)]
157                 [Browsable (false)]
158                 [PersistenceMode (PersistenceMode.InnerDefaultProperty)]
159                 public MenuItemCollection ChildItems {
160                         get {
161                                 if (items == null) {
162                                         items = new MenuItemCollection (this);
163                                                 
164                                         if (((IStateManager)this).IsTrackingViewState)
165                                                 ((IStateManager)items).TrackViewState();
166                                 }
167                                 return items;
168                         }
169                 }
170                 
171                 [DefaultValue ("")]
172                 [UrlProperty]
173                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
174                 public string ImageUrl {
175                         get {
176                                 return ViewState ["ImageUrl"] == null ? String.Empty : (String) ViewState ["ImageUrl"];
177                         }
178                         set {
179                                 ViewState ["ImageUrl"] = value;
180                         }
181                 }
182
183                 [DefaultValue ("")]
184                 [UrlProperty]
185                 [Editor ("System.Web.UI.Design.UrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
186                 public string NavigateUrl {
187                         get {
188                                 return ViewState ["NavigateUrl"] == null ? String.Empty : (String) ViewState ["NavigateUrl"];
189                         }
190                         set {
191                                 ViewState ["NavigateUrl"] = value;
192                         }
193                 }
194
195                 [DefaultValue ("")]
196                 [UrlProperty]
197                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
198                 public string PopOutImageUrl {
199                         get {
200                                 return ViewState ["PopOutImageUrl"] == null ? String.Empty : (String) ViewState ["PopOutImageUrl"];
201                         }
202                         set {
203                                 ViewState ["PopOutImageUrl"] = value;
204                         }
205                 }
206
207                 [DefaultValue ("")]
208                 public string Target {
209                         get {
210                                 return ViewState ["Target"] == null ? String.Empty : (String) ViewState ["Target"];
211                         }
212                         set {
213                                 ViewState ["Target"] = value;
214                         }
215                 }
216
217                 [Localizable (true)]
218                 [DefaultValue ("")]
219                 public string Text {
220                         get {
221                                 return ViewState ["Text"] == null ? String.Empty : (String) ViewState ["Text"];
222                         }
223                         set {
224                                 ViewState ["Text"] = value;
225                         }
226                 }
227
228                 [Localizable (true)]
229                 [DefaultValue ("")]
230                 public string ToolTip {
231                         get {
232                                 return ViewState ["ToolTip"] == null ? String.Empty : (String) ViewState ["ToolTip"];
233                         }
234                         set {
235                                 ViewState ["ToolTip"] = value;
236                         }
237                 }
238
239                 [Localizable (true)]
240                 [DefaultValue ("")]
241                 public string Value {
242                         get {
243                                 return ViewState ["Value"] == null ? String.Empty : (String) ViewState ["Value"];
244                         }
245                         set {
246                                 ViewState ["Value"] = value;
247                         }
248                 }
249                 
250                 [DefaultValue ("")]
251                 [UrlProperty]
252                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
253                 public string SeparatorImageUrl {
254                         get {
255                                 return ViewState ["SeparatorImageUrl"] == null ? String.Empty : (String) ViewState ["SeparatorImageUrl"];
256                         }
257                         set {
258                                 ViewState ["SeparatorImageUrl"] = value;
259                         }
260                 }
261                 
262             [BrowsableAttribute (true)]
263             [DefaultValueAttribute (true)]
264                 public bool Selectable {
265                         get {
266                                 return ViewState ["Selectable"] == null ? true : (bool) ViewState ["Selectable"];
267                         }
268                         set {
269                                 ViewState ["Selectable"] = value;
270                         }
271                 }
272                 
273             [BrowsableAttribute (true)]
274             [DefaultValueAttribute (true)]
275                 public bool Enabled {
276                         get {
277                                 return ViewState ["Enabled"] == null ? true : (bool) ViewState ["Enabled"];
278                         }
279                         set {
280                                 ViewState ["Enabled"] = value;
281                         }
282                 }
283                 
284                 internal bool BranchEnabled {
285                         get { return Enabled && (parent == null || parent.BranchEnabled); }
286                 }
287
288                 [DefaultValue (false)]
289                 [Browsable (true)]
290                 public bool Selected {
291                         get {
292                                 if (menu != null)
293                                         return menu.SelectedItem == this;
294                                 else
295                                         return false;
296                         }
297                         set {
298                                 if (menu != null) {
299                                         if (!value && menu.SelectedItem == this)
300                                                 menu.SetSelectedItem (null);
301                                         else if (value)
302                                                 menu.SetSelectedItem (this);
303                                 }
304                         }
305                 }
306                 
307                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
308                 [Browsable (false)]
309                 public MenuItem Parent {
310                         get { return parent; }
311                 }
312                 
313                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
314                 [Browsable (false)]
315                 public string ValuePath {
316                         get {
317                                 if (menu == null) return Value;
318                                 
319                                 StringBuilder sb = new StringBuilder (Value);
320                                 MenuItem item = parent;
321                                 while (item != null) {
322                                         sb.Insert (0, menu.PathSeparator);
323                                         sb.Insert (0, item.Value);
324                                         item = item.Parent;
325                                 }
326                                 return sb.ToString ();
327                         }
328                 }
329                 
330                 internal int Index {
331                         get { return index; }
332                         set { index = value; ResetPathData (); }
333                 }
334                 
335                 internal void SetParent (MenuItem item) {
336                         parent = item;
337                         ResetPathData ();
338                 }
339                 
340                 internal string Path {
341                         get {
342                                 if (path != null) return path;
343                                 StringBuilder sb = new StringBuilder (index.ToString());
344                                 MenuItem item = parent;
345                                 while (item != null) {
346                                         sb.Insert (0, '_');
347                                         sb.Insert (0, item.Index.ToString ());
348                                         item = item.Parent;
349                                 }
350                                 path = sb.ToString ();
351                                 return path;
352                         }
353                 }
354                 
355                 internal bool HasChildData {
356                         get { return items != null; }
357                 }
358                 
359                 void IStateManager.LoadViewState (object savedState)
360                 {
361                         if (savedState == null)
362                                 return;
363
364                         object[] states = (object[]) savedState;
365                         ViewState.LoadViewState (states [0]);
366                         
367                         if (states [1] != null)
368                                 ((IStateManager)ChildItems).LoadViewState (states [1]);
369                 }
370                 
371                 object IStateManager.SaveViewState ()
372                 {
373                         object[] states = new object[2];
374                         states[0] = ViewState.SaveViewState();
375                         states[1] = (items == null ? null : ((IStateManager)items).SaveViewState());
376                         
377                         for (int i = 0; i < states.Length; i++) {
378                                 if (states [i] != null)
379                                         return states;
380                         }
381                         return null;
382                 }
383                 
384                 void IStateManager.TrackViewState ()
385                 {
386                         if (marked) return;
387                         marked = true;
388                         ViewState.TrackViewState();
389
390                         if (items != null)
391                                 ((IStateManager)items).TrackViewState ();
392                 }
393                 
394                 bool IStateManager.IsTrackingViewState
395                 {
396                         get { return marked; }
397                 }
398                 
399                 internal void SetDirty ()
400                 {
401                         ViewState.SetDirty (true);
402                         if (items != null)
403                                 items.SetDirty ();
404                 }
405                 
406                 object ICloneable.Clone ()
407                 {
408                         MenuItem nod = new MenuItem ();
409                         foreach (DictionaryEntry e in ViewState)
410                                 nod.ViewState [(string)e.Key] = e.Value;
411                                 
412                         foreach (ICloneable c in ChildItems)
413                                 nod.ChildItems.Add ((MenuItem)c.Clone ());
414                                 
415                         return nod;
416                 }
417                 
418                 internal void Bind (IHierarchyData hierarchyData)
419                 {
420                         this.hierarchyData = hierarchyData;
421                         DataBound = true;
422                         DataPath = hierarchyData.Path;
423                         dataItem = hierarchyData.Item;
424
425                         MenuItemBinding bin = GetBinding ();
426                         if (bin != null) {
427
428                                 // Bind Enabled property
429
430                                 if (bin.EnabledField != "")
431                                         try { Enabled = Convert.ToBoolean (GetBoundPropertyValue (bin.EnabledField)); }
432                                         catch { Enabled = bin.Enabled; }
433                                 else
434                                         Enabled = bin.Enabled;
435
436                                 // Bind ImageUrl property
437
438                                 if (bin.ImageUrlField.Length > 0) {
439                                         ImageUrl = Convert.ToString (GetBoundPropertyValue (bin.ImageUrlField));
440                                         if (ImageUrl.Length == 0)
441                                                 ImageUrl = bin.ImageUrl;
442                                 }
443                                 else if (bin.ImageUrl.Length > 0)
444                                         ImageUrl = bin.ImageUrl;
445
446                                 // Bind NavigateUrl property
447
448                                 if (bin.NavigateUrlField.Length > 0) {
449                                         NavigateUrl = Convert.ToString (GetBoundPropertyValue (bin.NavigateUrlField));
450                                         if (NavigateUrl.Length == 0)
451                                                 NavigateUrl = bin.NavigateUrl;
452                                 }
453                                 else if (bin.NavigateUrl.Length > 0)
454                                         NavigateUrl = bin.NavigateUrl;
455
456                                 // Bind PopOutImageUrl property
457
458                                 if (bin.PopOutImageUrlField.Length > 0) {
459                                         PopOutImageUrl = Convert.ToString (GetBoundPropertyValue (bin.PopOutImageUrlField));
460                                         if (PopOutImageUrl.Length == 0)
461                                                 PopOutImageUrl = bin.PopOutImageUrl;
462                                 }
463                                 else if (bin.PopOutImageUrl.Length > 0)
464                                         PopOutImageUrl = bin.PopOutImageUrl;
465
466                                 // Bind Selectable property
467
468                                 if (bin.SelectableField != "")
469                                         try { Selectable = Convert.ToBoolean (GetBoundPropertyValue (bin.SelectableField)); }
470                                         catch { Selectable = bin.Selectable; }
471                                 else
472                                         Selectable = bin.Selectable;
473
474                                 // Bind SeparatorImageUrl property
475
476                                 if (bin.SeparatorImageUrlField.Length > 0) {
477                                         SeparatorImageUrl = Convert.ToString (GetBoundPropertyValue (bin.SeparatorImageUrlField));
478                                         if (SeparatorImageUrl.Length == 0)
479                                                 SeparatorImageUrl = bin.SeparatorImageUrl;
480                                 }
481                                 else if (bin.SeparatorImageUrl.Length > 0)
482                                         SeparatorImageUrl = bin.SeparatorImageUrl;
483
484                                 // Bind Target property\r
485 \r
486                                 if (bin.TargetField.Length > 0) {
487                                         Target = Convert.ToString (GetBoundPropertyValue (bin.TargetField));
488                                         if (Target.Length == 0)
489                                                 Target = bin.Target;
490                                 }
491                                 else if (bin.Target.Length > 0)
492                                         Target = bin.Target;\r
493 \r
494                                 // Bind ToolTip property
495
496                                 if (bin.ToolTipField.Length > 0) {
497                                         ToolTip = Convert.ToString (GetBoundPropertyValue (bin.ToolTipField));
498                                         if (ToolTip.Length == 0)
499                                                 ToolTip = bin.ToolTip;
500                                 }
501                                 else if (bin.ToolTip.Length > 0)
502                                         ToolTip = bin.ToolTip;
503
504                                 // Bind Value property
505
506                                 if (bin.ValueField.Length > 0) {
507                                         Value = Convert.ToString (GetBoundPropertyValue (bin.ValueField));
508                                         if (Value.Length == 0)
509                                                 Value = bin.Value;
510                                         if (Value.Length == 0)
511                                                 Value = bin.Text;
512                                 }
513                                 else if (bin.Value.Length > 0)
514                                         Value = bin.Value;
515                                 else if (bin.Text.Length > 0)
516                                         Value = bin.Text;
517                                 else
518                                         Value = GetDefaultBoundText ();
519                                 
520                                 // Bind Text property
521
522                                 if (bin.TextField.Length > 0) {
523                                         Text = Convert.ToString (GetBoundPropertyValue (bin.TextField));
524                                         if (bin.FormatString.Length > 0)
525                                                 Text = string.Format (bin.FormatString, Text);
526                                         if (Text.Length == 0)
527                                                 Text = bin.Text;
528                                         if (Text.Length == 0)
529                                                 Text = bin.Value;
530                                 }
531                                 else if (bin.Text.Length > 0)
532                                         Text = bin.Text;
533                                 else if (bin.Value.Length > 0)
534                                         Text = bin.Value;
535                                 else
536                                         Text = GetDefaultBoundText ();
537
538                         }
539                         else {
540                                 Text = Value = GetDefaultBoundText ();
541                         }
542
543                         INavigateUIData navigateUIData = hierarchyData as INavigateUIData;
544                         if (navigateUIData != null) {
545                                 Text = navigateUIData.ToString ();
546                                 NavigateUrl = navigateUIData.NavigateUrl;
547                         }
548                 }
549                 
550                 internal void SetDataItem (object item)
551                 {
552                         dataItem = item;
553                 }
554                 
555                 internal void SetDataPath (string path)
556                 {
557                         DataPath = path;
558                 }
559                 
560                 internal void SetDataBound (bool bound)
561                 {
562                         DataBound = bound;
563                 }
564                 
565                 string GetDefaultBoundText ()
566                 {
567                         if (hierarchyData != null) return hierarchyData.ToString ();
568                         else if (dataItem != null) return dataItem.ToString ();
569                         else return string.Empty;
570                 }
571                 
572                 string GetDataItemType ()
573                 {
574                         if (hierarchyData != null) return hierarchyData.Type;
575                         else if (dataItem != null) return dataItem.GetType().ToString ();
576                         else return string.Empty;
577                 }
578                 
579                 MenuItemBinding GetBinding ()
580                 {
581                         if (menu == null) return null;
582                         if (gotBinding) return binding;
583                         binding = menu.FindBindingForItem (GetDataItemType (), Depth);
584                         gotBinding = true;
585                         return binding;
586                 }
587                 
588                 object GetBoundPropertyValue (string name)
589                 {
590                         if (boundProperties == null) {
591                                 if (hierarchyData != null)
592                                         boundProperties = TypeDescriptor.GetProperties (hierarchyData);
593                                 else
594                                         boundProperties = TypeDescriptor.GetProperties (dataItem);
595                         }
596                         
597                         PropertyDescriptor prop = boundProperties.Find (name, true);
598                         if (prop == null)
599                                 throw new InvalidOperationException ("Property '" + name + "' not found in data bound item");
600                                 
601                         if (hierarchyData != null)
602                                 return prop.GetValue (hierarchyData);
603                         else
604                                 return prop.GetValue (dataItem);
605                 }
606         }
607 }
608
609 #endif