Merge pull request #396 from directhex/master
[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                                 object o = ViewState ["Text"];
222                                 if (o == null)
223                                         o = ViewState ["Value"];
224                                 if (o != null)
225                                         return (string) o;
226                                 return String.Empty;
227                         }
228                         set {
229                                 ViewState ["Text"] = value;
230                         }
231                 }
232
233                 [Localizable (true)]
234                 [DefaultValue ("")]
235                 public string ToolTip {
236                         get {
237                                 return ViewState ["ToolTip"] == null ? String.Empty : (String) ViewState ["ToolTip"];
238                         }
239                         set {
240                                 ViewState ["ToolTip"] = value;
241                         }
242                 }
243
244                 [Localizable (true)]
245                 [DefaultValue ("")]
246                 public string Value {
247                         get {
248                                 object o = ViewState ["Value"];
249                                 if (o == null)
250                                         o = ViewState ["Text"];
251                                 if (o != null)
252                                         return (string) o;
253                                 return String.Empty;
254                         }
255                         set {
256                                 ViewState ["Value"] = value;
257                         }
258                 }
259                 
260                 [DefaultValue ("")]
261                 [UrlProperty]
262                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
263                 public string SeparatorImageUrl {
264                         get {
265                                 return ViewState ["SeparatorImageUrl"] == null ? String.Empty : (String) ViewState ["SeparatorImageUrl"];
266                         }
267                         set {
268                                 ViewState ["SeparatorImageUrl"] = value;
269                         }
270                 }
271                 
272             [BrowsableAttribute (true)]
273             [DefaultValueAttribute (true)]
274                 public bool Selectable {
275                         get {
276                                 return ViewState ["Selectable"] == null ? true : (bool) ViewState ["Selectable"];
277                         }
278                         set {
279                                 ViewState ["Selectable"] = value;
280                         }
281                 }
282                 
283             [BrowsableAttribute (true)]
284             [DefaultValueAttribute (true)]
285                 public bool Enabled {
286                         get {
287                                 return ViewState ["Enabled"] == null ? true : (bool) ViewState ["Enabled"];
288                         }
289                         set {
290                                 ViewState ["Enabled"] = value;
291                         }
292                 }
293                 
294                 internal bool BranchEnabled {
295                         get { return Enabled && (parent == null || parent.BranchEnabled); }
296                 }
297
298                 [DefaultValue (false)]
299                 [Browsable (true)]
300                 public bool Selected {
301                         get {
302                                 if (menu != null)
303                                         return menu.SelectedItem == this;
304                                 else
305                                         return false;
306                         }
307                         set {
308                                 if (menu != null) {
309                                         if (!value && menu.SelectedItem == this)
310                                                 menu.SetSelectedItem (null);
311                                         else if (value)
312                                                 menu.SetSelectedItem (this);
313                                 }
314                         }
315                 }
316                 
317                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
318                 [Browsable (false)]
319                 public MenuItem Parent {
320                         get { return parent; }
321                 }
322                 
323                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
324                 [Browsable (false)]
325                 public string ValuePath {
326                         get {
327                                 if (menu == null) return Value;
328                                 
329                                 StringBuilder sb = new StringBuilder (Value);
330                                 MenuItem item = parent;
331                                 while (item != null) {
332                                         sb.Insert (0, menu.PathSeparator);
333                                         sb.Insert (0, item.Value);
334                                         item = item.Parent;
335                                 }
336                                 return sb.ToString ();
337                         }
338                 }
339                 
340                 internal int Index {
341                         get { return index; }
342                         set { index = value; ResetPathData (); }
343                 }
344                 
345                 internal void SetParent (MenuItem item) {
346                         parent = item;
347                         ResetPathData ();
348                 }
349                 
350                 internal string Path {
351                         get {
352                                 if (path != null) return path;
353                                 StringBuilder sb = new StringBuilder (index.ToString());
354                                 MenuItem item = parent;
355                                 while (item != null) {
356                                         sb.Insert (0, '_');
357                                         sb.Insert (0, item.Index.ToString ());
358                                         item = item.Parent;
359                                 }
360                                 path = sb.ToString ();
361                                 return path;
362                         }
363                 }
364                 
365                 internal bool HasChildData {
366                         get { return items != null; }
367                 }
368                 
369                 void IStateManager.LoadViewState (object savedState)
370                 {
371                         if (savedState == null)
372                                 return;
373
374                         object[] states = (object[]) savedState;
375                         ViewState.LoadViewState (states [0]);
376                         
377                         if (states [1] != null)
378                                 ((IStateManager)ChildItems).LoadViewState (states [1]);
379                 }
380                 
381                 object IStateManager.SaveViewState ()
382                 {
383                         object[] states = new object[2];
384                         states[0] = ViewState.SaveViewState();
385                         states[1] = (items == null ? null : ((IStateManager)items).SaveViewState());
386                         
387                         for (int i = 0; i < states.Length; i++) {
388                                 if (states [i] != null)
389                                         return states;
390                         }
391                         return null;
392                 }
393                 
394                 void IStateManager.TrackViewState ()
395                 {
396                         if (marked) return;
397                         marked = true;
398                         ViewState.TrackViewState();
399
400                         if (items != null)
401                                 ((IStateManager)items).TrackViewState ();
402                 }
403                 
404                 bool IStateManager.IsTrackingViewState
405                 {
406                         get { return marked; }
407                 }
408                 
409                 internal void SetDirty ()
410                 {
411                         ViewState.SetDirty (true);
412                         if (items != null)
413                                 items.SetDirty ();
414                 }
415                 
416                 object ICloneable.Clone ()
417                 {
418                         MenuItem nod = new MenuItem ();
419                         foreach (DictionaryEntry e in ViewState)
420                                 nod.ViewState [(string)e.Key] = e.Value;
421                                 
422                         foreach (ICloneable c in ChildItems)
423                                 nod.ChildItems.Add ((MenuItem)c.Clone ());
424                                 
425                         return nod;
426                 }
427                 
428                 internal void Bind (IHierarchyData hierarchyData)
429                 {
430                         this.hierarchyData = hierarchyData;
431                         DataBound = true;
432                         DataPath = hierarchyData.Path;
433                         dataItem = hierarchyData.Item;
434
435                         MenuItemBinding bin = GetBinding ();
436                         if (bin != null) {
437
438                                 // Bind Enabled property
439
440                                 if (bin.EnabledField != "")
441                                         try { Enabled = Convert.ToBoolean (GetBoundPropertyValue (bin.EnabledField)); }
442                                         catch { Enabled = bin.Enabled; }
443                                 else
444                                         Enabled = bin.Enabled;
445
446                                 // Bind ImageUrl property
447
448                                 if (bin.ImageUrlField.Length > 0) {
449                                         ImageUrl = Convert.ToString (GetBoundPropertyValue (bin.ImageUrlField));
450                                         if (ImageUrl.Length == 0)
451                                                 ImageUrl = bin.ImageUrl;
452                                 }
453                                 else if (bin.ImageUrl.Length > 0)
454                                         ImageUrl = bin.ImageUrl;
455
456                                 // Bind NavigateUrl property
457
458                                 if (bin.NavigateUrlField.Length > 0) {
459                                         NavigateUrl = Convert.ToString (GetBoundPropertyValue (bin.NavigateUrlField));
460                                         if (NavigateUrl.Length == 0)
461                                                 NavigateUrl = bin.NavigateUrl;
462                                 }
463                                 else if (bin.NavigateUrl.Length > 0)
464                                         NavigateUrl = bin.NavigateUrl;
465
466                                 // Bind PopOutImageUrl property
467
468                                 if (bin.PopOutImageUrlField.Length > 0) {
469                                         PopOutImageUrl = Convert.ToString (GetBoundPropertyValue (bin.PopOutImageUrlField));
470                                         if (PopOutImageUrl.Length == 0)
471                                                 PopOutImageUrl = bin.PopOutImageUrl;
472                                 }
473                                 else if (bin.PopOutImageUrl.Length > 0)
474                                         PopOutImageUrl = bin.PopOutImageUrl;
475
476                                 // Bind Selectable property
477
478                                 if (bin.SelectableField != "")
479                                         try { Selectable = Convert.ToBoolean (GetBoundPropertyValue (bin.SelectableField)); }
480                                         catch { Selectable = bin.Selectable; }
481                                 else
482                                         Selectable = bin.Selectable;
483
484                                 // Bind SeparatorImageUrl property
485
486                                 if (bin.SeparatorImageUrlField.Length > 0) {
487                                         SeparatorImageUrl = Convert.ToString (GetBoundPropertyValue (bin.SeparatorImageUrlField));
488                                         if (SeparatorImageUrl.Length == 0)
489                                                 SeparatorImageUrl = bin.SeparatorImageUrl;
490                                 }
491                                 else if (bin.SeparatorImageUrl.Length > 0)
492                                         SeparatorImageUrl = bin.SeparatorImageUrl;
493
494                                 // Bind Target property
495
496                                 if (bin.TargetField.Length > 0) {
497                                         Target = Convert.ToString (GetBoundPropertyValue (bin.TargetField));
498                                         if (Target.Length == 0)
499                                                 Target = bin.Target;
500                                 }
501                                 else if (bin.Target.Length > 0)
502                                         Target = bin.Target;
503
504                                 // Bind ToolTip property
505
506                                 if (bin.ToolTipField.Length > 0) {
507                                         ToolTip = Convert.ToString (GetBoundPropertyValue (bin.ToolTipField));
508                                         if (ToolTip.Length == 0)
509                                                 ToolTip = bin.ToolTip;
510                                 }
511                                 else if (bin.ToolTip.Length > 0)
512                                         ToolTip = bin.ToolTip;
513
514                                 // Bind Value property
515                                 string value = null;
516                                 if (bin.ValueField.Length > 0) {
517                                         value = Convert.ToString (GetBoundPropertyValue (bin.ValueField));
518                                 }
519                                 if (String.IsNullOrEmpty (value)) {
520                                         if (bin.Value.Length > 0)
521                                                 value = bin.Value;
522                                         else if (bin.Text.Length > 0)
523                                                 value = bin.Text;
524                                         else
525                                                 value = String.Empty;
526                                 }
527                                 Value = value;
528
529                                 // Bind Text property
530                                 string text = null;
531                                 if (bin.TextField.Length > 0) {
532                                         text = Convert.ToString (GetBoundPropertyValue (bin.TextField));
533                                         if (bin.FormatString.Length > 0)
534                                                 text = string.Format (bin.FormatString, text);
535                                 }
536                                 if (String.IsNullOrEmpty (text)) {
537                                         if (bin.Text.Length > 0)
538                                                 text = bin.Text;
539                                         else if (bin.Value.Length > 0)
540                                                 text = bin.Value;
541                                         else
542                                                 text = String.Empty;
543                                 }
544                                 Text = text;
545
546                         }
547                         else {
548                                 Text = Value = GetDefaultBoundText ();
549                         }
550
551                         INavigateUIData navigateUIData = hierarchyData as INavigateUIData;
552                         if (navigateUIData != null) {
553                                 ToolTip = navigateUIData.Description;
554                                 Text = navigateUIData.ToString ();
555                                 NavigateUrl = navigateUIData.NavigateUrl;
556                         }
557                 }
558                 
559                 internal void SetDataItem (object item)
560                 {
561                         dataItem = item;
562                 }
563                 
564                 internal void SetDataPath (string path)
565                 {
566                         DataPath = path;
567                 }
568                 
569                 internal void SetDataBound (bool bound)
570                 {
571                         DataBound = bound;
572                 }
573                 
574                 string GetDefaultBoundText ()
575                 {
576                         if (hierarchyData != null) return hierarchyData.ToString ();
577                         else if (dataItem != null) return dataItem.ToString ();
578                         else return string.Empty;
579                 }
580                 
581                 string GetDataItemType ()
582                 {
583                         if (hierarchyData != null) return hierarchyData.Type;
584                         else if (dataItem != null) return dataItem.GetType().ToString ();
585                         else return string.Empty;
586                 }
587                 
588                 MenuItemBinding GetBinding ()
589                 {
590                         if (menu == null) return null;
591                         if (gotBinding) return binding;
592                         binding = menu.FindBindingForItem (GetDataItemType (), Depth);
593                         gotBinding = true;
594                         return binding;
595                 }
596                 
597                 object GetBoundPropertyValue (string name)
598                 {
599                         if (boundProperties == null) {
600                                 if (hierarchyData != null)
601                                         boundProperties = TypeDescriptor.GetProperties (hierarchyData);
602                                 else
603                                         boundProperties = TypeDescriptor.GetProperties (dataItem);
604                         }
605                         
606                         PropertyDescriptor prop = boundProperties.Find (name, true);
607                         if (prop == null)
608                                 throw new InvalidOperationException ("Property '" + name + "' not found in data bound item");
609                                 
610                         if (hierarchyData != null)
611                                 return prop.GetValue (hierarchyData);
612                         else
613                                 return prop.GetValue (dataItem);
614                 }
615         }
616 }
617
618 #endif