Copied remotely
[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 //
7 // (C) 2004 Novell, Inc (http://www.novell.com)
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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 using System.Web.Handlers;
39 using System.Collections.Specialized;
40 using System.IO;
41
42 namespace System.Web.UI.WebControls
43 {
44         public class Menu : HierarchicalDataBoundControl, IPostBackEventHandler, INamingContainer
45         {
46                 MenuItemCollection items;
47                 MenuItemBindingCollection dataBindings;
48                 MenuItem selectedItem;
49                 Hashtable bindings;
50                 
51                 [PersistenceMode (PersistenceMode.InnerProperty)]
52                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
53                 [Editor ("System.Web.UI.Design.MenuItemBindingsEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
54                 public virtual MenuItemBindingCollection DataBindings {
55                         get {
56                                 if (dataBindings == null) {
57                                         dataBindings = new MenuItemBindingCollection ();
58                                         if (IsTrackingViewState)
59                                                 ((IStateManager)dataBindings).TrackViewState();
60                                 }
61                                 return dataBindings;
62                         }
63                 }
64
65                 [DefaultValue (500)]
66                 public virtual int DisappearAfter {
67                         get {
68                                 object o = ViewState ["DisappearAfter"];
69                                 if (o != null) return (int)o;
70                                 return 500;
71                         }
72                         set {
73                                 ViewState["DisappearAfter"] = value;
74                         }
75                 }
76
77                 [DefaultValue ("")]
78                 [UrlProperty]
79                 [WebCategory ("Appearance")]
80                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
81                 public virtual string DynamicBottomSeparatorImageUrl {
82                         get {
83                                 object o = ViewState ["dbsiu"];
84                                 if (o != null) return (string)o;
85                                 return "";
86                         }
87                         set {
88                                 ViewState["dbsiu"] = value;
89                         }
90                 }
91
92                 [DefaultValue (Orientation.Vertical)]
93                 public virtual Orientation Orientation {
94                         get {
95                                 object o = ViewState ["Orientation"];
96                                 if (o != null) return (Orientation) o;
97                                 return Orientation.Vertical;
98                         }
99                         set {
100                                 ViewState["Orientation"] = value;
101                         }
102                 }
103
104                 [DefaultValue (1)]
105                 public virtual int StaticDisplayLevels {
106                         get {
107                                 object o = ViewState ["StaticDisplayLevels"];
108                                 if (o != null) return (int)o;
109                                 return 1;
110                         }
111                         set {
112                                 if (value < 1) throw new ArgumentOutOfRangeException ();
113                                 ViewState["StaticDisplayLevels"] = value;
114                         }
115                 }
116
117                 [DefaultValue ("16px")]
118                 public Unit StaticSubMenuIndent {
119                         get {
120                                 object o = ViewState ["StaticSubMenuIndent"];
121                                 if (o != null) return (Unit)o;
122                                 return new Unit (16);
123                         }
124                         set {
125                                 ViewState["StaticSubMenuIndent"] = value;
126                         }
127                 }
128
129                 [DefaultValue (3)]
130                 public virtual int MaximumDynamicDisplayLevels {
131                         get {
132                                 object o = ViewState ["MaximumDynamicDisplayLevels"];
133                                 if (o != null) return (int)o;
134                                 return 3;
135                         }
136                         set {
137                                 if (value < 0) throw new ArgumentOutOfRangeException ();
138                                 ViewState["MaximumDynamicDisplayLevels"] = value;
139                         }
140                 }
141
142 /*              [DefaultValue (true)]
143                 public virtual bool DynamicEnableDefaultPopOutImage {
144                         get {
145                                 object o = ViewState ["dedpoi"];
146                                 if (o != null) return (bool)o;
147                                 return true;
148                         }
149                         set {
150                                 ViewState["dedpoi"] = value;
151                         }
152                 }
153 */
154                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
155                 [PersistenceMode (PersistenceMode.InnerProperty)]
156                 [Editor ("System.Web.UI.Design.MenuItemCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
157                 public virtual MenuItemCollection Items {
158                         get {
159                                 if (items == null) {
160                                         items = new MenuItemCollection (this);
161                                         if (IsTrackingViewState)
162                                                 ((IStateManager)items).TrackViewState();
163                                 }
164                                 return items;
165                         }
166                 }
167
168                 [DefaultValue ('/')]
169                 public virtual char PathSeparator {
170                         get {
171                                 object o = ViewState ["PathSeparator"];
172                                 if(o != null) return (char)o;
173                                 return '/';
174                         }
175                         set {
176                                 ViewState ["PathSeparator"] = value;
177                         }
178                 }
179
180                 [Browsable (false)]
181                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
182                 public MenuItem SelectedItem {
183                         get { return selectedItem; }
184                 }
185
186                 internal void SetSelectedItem (MenuItem item)
187                 {
188                         if (selectedItem == item) return;
189                         if (selectedItem != null)
190                                 selectedItem.SelectedFlag = false;
191                         selectedItem = item;
192                         selectedItem.SelectedFlag = true;
193         //              OnSelectedItemChanged (new MenuItemEventArgs (selectedItem));
194                 }
195                 
196                 public MenuItem FindItem (string valuePath)
197                 {
198                         if (valuePath == null) throw new ArgumentNullException ("valuePath");
199                         string[] path = valuePath.Split (PathSeparator);
200                         int n = 0;
201                         MenuItemCollection col = Items;
202                         bool foundBranch = true;
203                         while (col.Count > 0 && foundBranch) {
204                                 foundBranch = false;
205                                 foreach (MenuItem item in col) {
206                                         if (item.Value == path [n]) {
207                                                 if (++n == path.Length) return item;
208                                                 col = item.ChildItems;
209                                                 foundBranch = true;
210                                                 break;
211                                         }
212                                 }
213                         }
214                         return null;
215                 }
216                 
217                 string GetBindingKey (string dataMember, int depth)
218                 {
219                         return dataMember + " " + depth;
220                 }
221                 
222                 internal MenuItemBinding FindBindingForItem (string type, int depth)
223                 {
224                         if (bindings == null) return null;
225
226                         MenuItemBinding bin = (MenuItemBinding) bindings [GetBindingKey (type, depth)];
227                         if (bin != null) return bin;
228                         
229                         bin = (MenuItemBinding) bindings [GetBindingKey (type, -1)];
230                         if (bin != null) return bin;
231                         
232                         bin = (MenuItemBinding) bindings [GetBindingKey ("", depth)];
233                         if (bin != null) return bin;
234                         
235                         bin = (MenuItemBinding) bindings [GetBindingKey ("", -1)];
236                         return bin;
237                 }
238                 
239                 protected internal override void PerformDataBinding ()
240                 {
241                         base.PerformDataBinding ();
242                         HierarchicalDataSourceView data = GetData ("");
243                         IHierarchicalEnumerable e = data.Select ();
244                         foreach (object obj in e) {
245                                 IHierarchyData hdata = e.GetHierarchyData (obj);
246                                 MenuItem item = new MenuItem ();
247                                 item.Bind (hdata);
248                                 Items.Add (item);
249                         }
250                 }
251                 
252                 void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
253                 {
254                 }
255                 
256                 protected override void TrackViewState()
257                 {
258                         EnsureDataBound ();
259                         
260                         base.TrackViewState();
261                         if (dataBindings != null) {
262                                 ((IStateManager)dataBindings).TrackViewState ();
263                         }
264                         if (items != null) {
265                                 ((IStateManager)items).TrackViewState();;
266                         }
267                 }
268
269                 protected override object SaveViewState()
270                 {
271                         object[] states = new object [3];
272                         states[0] = base.SaveViewState();
273                         states[1] = (dataBindings == null ? null : ((IStateManager)dataBindings).SaveViewState());
274                         states[2] = (items == null ? null : ((IStateManager)items).SaveViewState());
275
276                         for (int i = states.Length - 1; i >= 0; i--) {
277                                 if (states [i] != null)
278                                         return states;
279                         }
280
281                         return null;
282                 }
283
284                 protected override void LoadViewState (object savedState)
285                 {
286                         if (savedState == null)
287                                 return;
288
289                         object [] states = (object []) savedState;
290                         base.LoadViewState (states[0]);
291                         
292                         if (states[1] != null)
293                                 ((IStateManager)dataBindings).LoadViewState(states[8]);
294                         if (states[2] != null)
295                                 ((IStateManager)Items).LoadViewState(states[9]);
296                 }
297                 
298                 protected override void OnPreRender (EventArgs e)
299                 {
300                         base.OnPreRender (e);
301                         
302                         if (!Page.ClientScript.IsClientScriptIncludeRegistered (typeof(Menu), "Menu.js")) {
303                                 string url = Page.GetWebResourceUrl (typeof(Menu), "Menu.js");
304                                 Page.ClientScript.RegisterClientScriptInclude (typeof(Menu), "Menu.js", url);
305                                 
306                                 string cmenu = ClientID + "_data";
307                                 string script = string.Format ("var {0} = new Object ();\n", cmenu);
308                                 script += string.Format ("{0}.disappearAfter = {1};\n", cmenu, ClientScriptManager.GetScriptLiteral (DisappearAfter));
309                                 script += string.Format ("{0}.vertical = {1};\n", cmenu, ClientScriptManager.GetScriptLiteral (Orientation == Orientation.Vertical));
310                                 
311                                 Page.ClientScript.RegisterStartupScript (typeof(Menu), "", script, true);
312                         }
313
314                         if (dataBindings != null && dataBindings.Count > 0) {
315                                 bindings = new Hashtable ();
316                                 foreach (TreeNodeBinding bin in dataBindings) {
317                                         string key = GetBindingKey (bin.DataMember, bin.Depth);
318                                         bindings [key] = bin;
319                                 }
320                         }
321                         else
322                                 bindings = null;
323                 }
324                 
325                 protected override void RenderContents (HtmlTextWriter writer)
326                 {
327                         ArrayList dynamicMenus = new ArrayList ();
328                         
329                         if (Orientation == Orientation.Horizontal) {
330                                 writer.AddAttribute ("cellpadding", "0");
331                                 writer.AddAttribute ("cellspacing", "0");
332                                 writer.AddStyleAttribute ("border-width", "0");
333                                 writer.RenderBeginTag (HtmlTextWriterTag.Table);
334                                 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
335                         }
336                         
337                         foreach (MenuItem item in Items) {
338                                 RenderMenuItem (writer, item, dynamicMenus);
339                         }
340                         
341                         if (Orientation == Orientation.Horizontal) {
342                                 writer.RenderEndTag (); // TR
343                                 writer.RenderEndTag (); // TABLE
344                         }
345                         
346                         for (int n=0; n<dynamicMenus.Count; n++) {
347                                 MenuItem item = (MenuItem) dynamicMenus [n];
348                                 writer.AddStyleAttribute ("display", "none");
349                                 writer.AddStyleAttribute ("visibility", "hidden");
350                                 writer.AddStyleAttribute ("position", "absolute");
351                                 writer.AddStyleAttribute ("left", "0px");
352                                 writer.AddStyleAttribute ("top", "0px");
353                                 writer.AddAttribute ("id", GetItemClientId (item, "s"));
354                                 writer.RenderBeginTag (HtmlTextWriterTag.Div);
355                                 
356                                 foreach (MenuItem mi in item.ChildItems) {
357                                         RenderMenuItem (writer, mi, dynamicMenus);
358                                 }
359                                 
360                                 writer.RenderEndTag (); // DIV
361                         }
362                 }
363                 
364                 void RenderMenuItem (HtmlTextWriter writer, MenuItem item, ArrayList dynamicMenus)
365                 {
366                         bool displayChildren = (item.Depth + 1 < StaticDisplayLevels + MaximumDynamicDisplayLevels);
367                         bool dynamicChildren = displayChildren && (item.Depth + 1 >= StaticDisplayLevels) && item.ChildItems.Count > 0;
368                         bool isDynamicItem = item.Depth + 1 > StaticDisplayLevels;
369
370                         if (Orientation == Orientation.Vertical) {
371                                 writer.AddAttribute ("cellpadding", "0");
372                                 writer.AddAttribute ("cellspacing", "0");
373                                 writer.AddStyleAttribute ("border-width", "0");
374                                 writer.RenderBeginTag (HtmlTextWriterTag.Table);
375                                 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
376                         }
377                         
378                         if (item.Depth > 0 && !isDynamicItem) {
379                                 for (int n=0; n<item.Depth; n++) {
380                                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
381                                         writer.AddStyleAttribute ("width", StaticSubMenuIndent.ToString ());
382                                         writer.RenderBeginTag (HtmlTextWriterTag.Div);
383                                         writer.RenderEndTag (); // DIV
384                                         writer.RenderEndTag (); // TD
385                                 }
386                         }
387                         
388                         writer.RenderBeginTag (HtmlTextWriterTag.Td);
389                         
390                         if (item.NavigateUrl != "") {
391                                 writer.AddAttribute ("href", item.NavigateUrl);
392                                 if (item.Target != null)
393                                         writer.AddAttribute ("target", item.Target);
394                                 writer.AddStyleAttribute ("text-decoration", "none");
395                         }
396                         else {
397                                 writer.AddAttribute ("href", GetClientEvent (item, "sel"));
398                                 writer.AddStyleAttribute ("text-decoration", "none");
399                         }
400                         
401                         string parentId = item.Parent != null ? "'" + item.Parent.Path + "'" : "null";
402                         if (dynamicChildren) {
403                                 writer.AddAttribute ("onmouseover", "javascript:Menu_OverItem ('" + ClientID + "', '" + item.Path + "', " + parentId + ")");
404                                 writer.AddAttribute ("onmouseout", "javascript:Menu_OutItem ('" + ClientID + "', '" + item.Path + "')");
405                         } else if (isDynamicItem) {
406                                 writer.AddAttribute ("onmouseover", "javascript:Menu_OverLeafItem ('" + ClientID + "', " + parentId + ")");
407                                 writer.AddAttribute ("onmouseout", "javascript:Menu_OutItem ('" + ClientID + "', " + parentId + ")");
408                         }
409                         
410                         writer.AddAttribute ("id", GetItemClientId (item, "i"));
411                         writer.RenderBeginTag (HtmlTextWriterTag.A);
412                         writer.Write (item.Text);
413                         writer.RenderEndTag (); // A
414                         
415                         writer.RenderEndTag (); // TD
416                         
417                         if (Orientation == Orientation.Vertical) {
418                                 writer.RenderEndTag (); // TR
419                                 writer.RenderEndTag (); // TABLE
420                         }
421                         
422                         if (displayChildren) {
423                                 if (dynamicChildren) {
424                                         dynamicMenus.Add (item);
425                                 } else {
426                                         foreach (MenuItem mi in item.ChildItems) {
427                                                 RenderMenuItem (writer, mi, dynamicMenus);
428                                         }
429                                 }
430                         }
431                 }
432                 
433                 string GetItemClientId (MenuItem item, string sufix)
434                 {
435                         return ClientID + "_" + item.Path + sufix;
436                 }
437                                                         
438                 string GetClientEvent (MenuItem item, string ev)
439                 {
440                         return Page.GetPostBackClientHyperlink (this, ev + "|" + item.Path);
441                 }
442         }
443 }
444
445 #endif