Merge pull request #396 from directhex/master
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / SiteMapPath.cs
1 //
2 // System.Web.UI.WebControls.SiteMapPath.cs
3 //
4 // Authors:
5 //      Lluis Sanchez Gual (lluis@novell.com)
6 //
7 // (C) 2005 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) 2005 Novell, Inc (http://www.novell.com)
29 //
30
31 #if NET_2_0
32
33 using System;
34 using System.Collections;
35 using System.ComponentModel;
36 using System.Web.UI.HtmlControls;
37
38 namespace System.Web.UI.WebControls
39 {
40         [Designer ("System.Web.UI.Design.WebControls.SiteMapPathDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
41         public class SiteMapPath: CompositeControl
42         {
43                 SiteMapProvider provider;
44                 
45                 Style currentNodeStyle;
46                 Style nodeStyle;
47                 Style pathSeparatorStyle;
48                 Style rootNodeStyle;
49                 
50                 ITemplate currentNodeTemplate;
51                 ITemplate nodeTemplate;
52                 ITemplate pathSeparatorTemplate;
53                 ITemplate rootNodeTemplate;
54
55                 static readonly object ItemCreatedEvent = new object();
56                 static readonly object ItemDataBoundEvent = new object();
57                 
58                 public event SiteMapNodeItemEventHandler ItemCreated {
59                         add { Events.AddHandler (ItemCreatedEvent, value); }
60                         remove { Events.RemoveHandler (ItemCreatedEvent, value); }
61                 }
62                 
63                 public event SiteMapNodeItemEventHandler ItemDataBound {
64                         add { Events.AddHandler (ItemDataBoundEvent, value); }
65                         remove { Events.RemoveHandler (ItemDataBoundEvent, value); }
66                 }
67                 
68                 protected virtual void OnItemCreated (SiteMapNodeItemEventArgs e)
69                 {
70                         if (Events != null) {
71                                 SiteMapNodeItemEventHandler eh = (SiteMapNodeItemEventHandler) Events [ItemCreatedEvent];
72                                 if (eh != null) eh (this, e);
73                         }
74                 }
75                 
76                 protected virtual void OnItemDataBound (SiteMapNodeItemEventArgs e)
77                 {
78                         if (Events != null) {
79                                 SiteMapNodeItemEventHandler eh = (SiteMapNodeItemEventHandler) Events [ItemDataBoundEvent];
80                                 if (eh != null) eh (this, e);
81                         }
82                 }
83                 
84                 [DefaultValueAttribute (null)]
85                 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Content)]
86                 [NotifyParentPropertyAttribute (true)]
87                 [PersistenceModeAttribute (PersistenceMode.InnerProperty)]
88                 public Style CurrentNodeStyle {
89                         get {
90                                 if (currentNodeStyle == null) {
91                                         currentNodeStyle = new Style ();
92                                         if (IsTrackingViewState)
93                                                 ((IStateManager)currentNodeStyle).TrackViewState ();
94                                 }
95                                 return currentNodeStyle;
96                         }
97                 }
98         
99                 [DefaultValue (null)]
100                 [TemplateContainer (typeof(SiteMapNodeItem), BindingDirection.OneWay)]
101                 [PersistenceMode (PersistenceMode.InnerProperty)]
102                 [Browsable (false)]
103                 public virtual ITemplate CurrentNodeTemplate {
104                         get { return currentNodeTemplate; }
105                         set { currentNodeTemplate = value; UpdateControls (); }
106                 }
107                 
108                 [DefaultValueAttribute (null)]
109                 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Content)]
110                 [NotifyParentPropertyAttribute (true)]
111                 [PersistenceModeAttribute (PersistenceMode.InnerProperty)]
112                 public Style NodeStyle {
113                         get {
114                                 if (nodeStyle == null) {
115                                         nodeStyle = new Style ();
116                                         if (IsTrackingViewState)
117                                                 ((IStateManager)nodeStyle).TrackViewState ();
118                                 }
119                                 return nodeStyle;
120                         }
121                 }
122         
123                 [DefaultValue (null)]
124                 [TemplateContainer (typeof(SiteMapNodeItem), BindingDirection.OneWay)]
125                 [PersistenceMode (PersistenceMode.InnerProperty)]
126                 [Browsable (false)]
127                 public virtual ITemplate NodeTemplate {
128                         get { return nodeTemplate; }
129                         set { nodeTemplate = value; UpdateControls (); }
130                 }
131                 
132                 [DefaultValueAttribute (-1)]
133                 [ThemeableAttribute (false)]
134                 public virtual int ParentLevelsDisplayed {
135                         get { return ViewState.GetInt ("ParentLevelsDisplayed", -1); }
136                         set {
137                                 if (value < -1) throw new ArgumentOutOfRangeException ("value");
138                                 ViewState ["ParentLevelsDisplayed"] = value;
139                                 UpdateControls ();
140                         }
141                 }
142                 
143                 [DefaultValueAttribute (PathDirection.RootToCurrent)]
144                 public virtual PathDirection PathDirection {
145                         get { return (PathDirection)ViewState.GetInt ("PathDirection", (int)PathDirection.RootToCurrent); }
146                         set {
147                                 if (value != PathDirection.RootToCurrent && value != PathDirection.CurrentToRoot)
148                                         throw new ArgumentOutOfRangeException ("value");
149                                 ViewState ["PathDirection"] = value;
150                                 UpdateControls ();
151                         }
152                 }
153                 
154                 [DefaultValueAttribute (" > ")]
155                 [LocalizableAttribute (true)]
156                 public virtual string PathSeparator {
157                         get { return ViewState.GetString ("PathSeparator", " > "); }
158                         set {
159                                 ViewState ["PathSeparator"] = value;
160                                 UpdateControls ();
161                         }
162                 }
163                 
164                 [DefaultValueAttribute (null)]
165                 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Content)]
166                 [NotifyParentPropertyAttribute (true)]
167                 [PersistenceModeAttribute (PersistenceMode.InnerProperty)]
168                 public Style PathSeparatorStyle {
169                         get {
170                                 if (pathSeparatorStyle == null) {
171                                         pathSeparatorStyle = new Style ();
172                                         if (IsTrackingViewState)
173                                                 ((IStateManager)pathSeparatorStyle).TrackViewState ();
174                                 }
175                                 return pathSeparatorStyle;
176                         }
177                 }
178         
179                 [DefaultValue (null)]
180                 [TemplateContainer (typeof(SiteMapNodeItem), BindingDirection.OneWay)]
181                 [PersistenceMode (PersistenceMode.InnerProperty)]
182                 [Browsable (false)]
183                 public virtual ITemplate PathSeparatorTemplate {
184                         get { return pathSeparatorTemplate; }
185                         set { pathSeparatorTemplate = value; UpdateControls (); }
186                 }
187                 
188                 [BrowsableAttribute (false)]
189                 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
190                 public SiteMapProvider Provider {
191                         get {
192                                 if (provider == null) {
193                                         if (this.SiteMapProvider.Length == 0) {
194                                                 provider = SiteMap.Provider;
195                                                 if (provider == null)
196                                                         throw new HttpException ("There is no default provider configured for the site.");
197                                         } else {
198                                                 provider = SiteMap.Providers [this.SiteMapProvider];
199                                                 if (provider == null)
200                                                         throw new HttpException ("SiteMap provider '" + this.SiteMapProvider + "' not found.");
201                                         }
202                                 }
203                                 return provider;
204                         }
205                         set {
206                                 provider = value;
207                                 UpdateControls ();
208                         }
209                 }
210                 
211                 [DefaultValueAttribute (false)]
212                 public virtual bool RenderCurrentNodeAsLink {
213                         get { return ViewState.GetBool ("RenderCurrentNodeAsLink", false); }
214                         set {
215                                 ViewState ["RenderCurrentNodeAsLink"] = value;
216                                 UpdateControls ();
217                         }
218                 }
219                 
220                 [DefaultValueAttribute (null)]
221                 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Content)]
222                 [NotifyParentPropertyAttribute (true)]
223                 [PersistenceModeAttribute (PersistenceMode.InnerProperty)]
224                 public Style RootNodeStyle {
225                         get {
226                                 if (rootNodeStyle == null) {
227                                         rootNodeStyle = new Style ();
228                                         if (IsTrackingViewState)
229                                                 ((IStateManager)rootNodeStyle).TrackViewState ();
230                                 }
231                                 return rootNodeStyle;
232                         }
233                 }
234         
235                 [DefaultValue (null)]
236                 [TemplateContainer (typeof(SiteMapNodeItem), BindingDirection.OneWay)]
237                 [PersistenceMode (PersistenceMode.InnerProperty)]
238                 [Browsable (false)]
239                 public virtual ITemplate RootNodeTemplate {
240                         get { return rootNodeTemplate; }
241                         set { rootNodeTemplate = value; UpdateControls (); }
242                 }
243                 
244                 [DefaultValueAttribute (true)]
245                 [ThemeableAttribute (false)]
246                 public virtual bool ShowToolTips {
247                         get { return ViewState.GetBool ("ShowToolTips", true); }
248                         set {
249                                 ViewState ["ShowToolTips"] = value;
250                                 UpdateControls ();
251                         }
252                 }
253                 
254                 [DefaultValueAttribute ("")]
255                 [ThemeableAttribute (false)]
256                 public virtual string SiteMapProvider {
257                         get { return ViewState.GetString ("SiteMapProvider", ""); }
258                         set {
259                                 ViewState ["SiteMapProvider"] = value;
260                                 UpdateControls ();
261                         }
262                 }
263
264                 [Localizable (true)]
265                 public virtual string SkipLinkText 
266                 {
267                         get { return ViewState.GetString ("SkipLinkText", "Skip Navigation Links"); }
268                         set { ViewState["SkipLinkText"] = value; }
269                 }
270                 
271                 
272                 void UpdateControls ()
273                 {
274                         ChildControlsCreated = false;
275                 }
276
277                 public override void DataBind ()
278                 {
279                         base.DataBind ();
280
281                         /* the child controls get bound in
282                          * base.DataBind */
283                         foreach (Control c in Controls) {
284                                 if (c is SiteMapNodeItem) {
285                                         SiteMapNodeItem it = (SiteMapNodeItem)c;
286                                         OnItemDataBound (new SiteMapNodeItemEventArgs (it));
287                                 }
288                         }
289                 }
290                 
291                 protected internal override void CreateChildControls ()
292                 {
293                         Controls.Clear ();
294                         CreateControlHierarchy ();
295                         DataBind ();
296                 }
297
298                 protected virtual void CreateControlHierarchy ()
299                 {
300                         ArrayList nodes = new ArrayList ();
301                         SiteMapNode node = Provider.CurrentNode;
302                         if (node == null) return;
303                         
304                         int levels = ParentLevelsDisplayed != -1 ? ParentLevelsDisplayed + 1 : int.MaxValue;
305                         
306                         while (node != null && levels > 0) {
307                                 if (nodes.Count > 0) {
308                                         SiteMapNodeItem sep = new SiteMapNodeItem (nodes.Count, SiteMapNodeItemType.PathSeparator);
309                                         InitializeItem (sep);
310                                         SiteMapNodeItemEventArgs sargs = new SiteMapNodeItemEventArgs (sep);
311                                         OnItemCreated (sargs);
312                                         nodes.Add (sep);
313                                 }
314
315                                 SiteMapNodeItemType nt;
316                                 if (nodes.Count == 0)
317                                         nt = SiteMapNodeItemType.Current;
318                                 else if (node.ParentNode == null)
319                                         nt = SiteMapNodeItemType.Root;
320                                 else
321                                         nt = SiteMapNodeItemType.Parent;
322                                         
323                                 SiteMapNodeItem it = new SiteMapNodeItem (nodes.Count, nt);
324                                 it.SiteMapNode = node;
325                                 InitializeItem (it);
326                                 
327                                 SiteMapNodeItemEventArgs args = new SiteMapNodeItemEventArgs (it);
328                                 OnItemCreated (args);
329                                 
330                                 nodes.Add (it);
331                                 node = node.ParentNode;
332                                 levels--;
333                         }
334                         
335                         if (PathDirection == PathDirection.RootToCurrent) {
336                                 for (int n=nodes.Count - 1; n>=0; n--)
337                                         Controls.Add ((Control)nodes[n]);
338                         } else {
339                                 for (int n=0; n<nodes.Count; n++)
340                                         Controls.Add ((Control)nodes[n]);
341                         }
342                 }
343                 
344                 protected virtual void InitializeItem (SiteMapNodeItem item)
345                 {
346                         switch (item.ItemType) {
347                                 case SiteMapNodeItemType.Root:
348                                         if (RootNodeTemplate != null) {
349                                                 item.ApplyStyle (NodeStyle);
350                                                 item.ApplyStyle (RootNodeStyle);
351                                                 RootNodeTemplate.InstantiateIn (item);
352                                         }
353                                         else if (NodeTemplate != null) {
354                                                 item.ApplyStyle (NodeStyle);
355                                                 item.ApplyStyle (RootNodeStyle);
356                                                 NodeTemplate.InstantiateIn (item);
357                                         }
358                                         else {
359                                                 WebControl c = CreateHyperLink (item);
360                                                 c.ApplyStyle (NodeStyle);
361                                                 c.ApplyStyle (RootNodeStyle);
362                                                 item.Controls.Add (c);
363                                         }
364                                         break;
365
366                                 case SiteMapNodeItemType.Current:
367                                         if (CurrentNodeTemplate != null) {
368                                                 item.ApplyStyle (NodeStyle);
369                                                 item.ApplyStyle (CurrentNodeStyle);
370                                                 CurrentNodeTemplate.InstantiateIn (item);
371                                         }
372                                         else if (NodeTemplate != null) {
373                                                 item.ApplyStyle (NodeStyle);
374                                                 item.ApplyStyle (CurrentNodeStyle);
375                                                 NodeTemplate.InstantiateIn (item);
376                                         } else if (RenderCurrentNodeAsLink) {
377                                                 HyperLink c = CreateHyperLink (item);
378                                                 c.ApplyStyle (NodeStyle);
379                                                 c.ApplyStyle (CurrentNodeStyle);
380                                                 item.Controls.Add (c);
381                                         } else {
382                                                 Literal c = CreateLiteral (item);
383                                                 item.ApplyStyle (NodeStyle);
384                                                 item.ApplyStyle (CurrentNodeStyle);
385                                                 item.Controls.Add (c);
386                                         }
387                                         break;
388                                         
389                                 case SiteMapNodeItemType.Parent:
390                                         if (NodeTemplate != null) {
391                                                 item.ApplyStyle (NodeStyle);
392                                                 NodeTemplate.InstantiateIn (item);
393                                         }
394                                         else {
395                                                 WebControl c = CreateHyperLink (item);
396                                                 c.ApplyStyle (NodeStyle);
397                                                 item.Controls.Add (c);
398                                         }
399                                         break;
400                                         
401                                 case SiteMapNodeItemType.PathSeparator:
402                                         if (PathSeparatorTemplate != null) {
403                                                 item.ApplyStyle (PathSeparatorStyle);
404                                                 PathSeparatorTemplate.InstantiateIn (item);
405                                         } else {
406                                                 Literal h = new Literal ();
407                                                 h.Text = HttpUtility.HtmlEncode (PathSeparator);
408                                                 item.ApplyStyle (PathSeparatorStyle);
409                                                 item.Controls.Add (h);
410                                         }
411                                         break;
412                         }
413                 }
414                 
415                 HyperLink CreateHyperLink (SiteMapNodeItem item)
416                 {
417                         HyperLink h = new HyperLink ();
418                         h.Text = item.SiteMapNode.Title;
419                         h.NavigateUrl = item.SiteMapNode.Url;
420                         if (ShowToolTips)
421                                 h.ToolTip = item.SiteMapNode.Description;
422                         return h;
423                 }
424
425                 Literal CreateLiteral (SiteMapNodeItem item)
426                 {
427                         Literal h = new Literal ();
428                         h.Text = item.SiteMapNode.Title;
429                         return h;
430                 }
431                 
432                 protected override void LoadViewState (object savedState)
433                 {
434                         if (savedState == null) {
435                                 base.LoadViewState (null);
436                                 return;
437                         }
438                         
439                         object[] states = (object[]) savedState;
440                         base.LoadViewState (states [0]);
441                         
442                         if (states[1] != null) ((IStateManager)CurrentNodeStyle).LoadViewState (states[1]);
443                         if (states[2] != null) ((IStateManager)NodeStyle).LoadViewState (states[2]);
444                         if (states[3] != null) ((IStateManager)PathSeparatorStyle).LoadViewState (states[3]);
445                         if (states[4] != null) ((IStateManager)RootNodeStyle).LoadViewState (states[4]);
446                 }
447
448                 [MonoTODO ("why override?")]
449                 protected override void OnDataBinding (EventArgs e)
450                 {
451                         base.OnDataBinding (e);
452                 }
453                 
454                 [MonoTODO ("why override?")]
455                 protected internal override void Render (HtmlTextWriter w)
456                 {
457                         base.Render (w);
458                 }
459
460                 protected internal override void RenderContents (HtmlTextWriter w)
461                 {
462                         string skip_id = ClientID + "_SkipLink";
463                         string altText = SkipLinkText;
464                         bool needAnchor = !String.IsNullOrEmpty (altText);
465                         
466                         if (needAnchor) {
467                                 // Anchor start
468                                 w.AddAttribute (HtmlTextWriterAttribute.Href, "#" + skip_id);
469                                 w.RenderBeginTag (HtmlTextWriterTag.A);
470
471                                 // Image
472                                 w.AddAttribute (HtmlTextWriterAttribute.Alt, altText);
473                                 w.AddAttribute (HtmlTextWriterAttribute.Height, "0");
474                                 w.AddAttribute (HtmlTextWriterAttribute.Width, "0");
475                                 w.AddAttribute (HtmlTextWriterAttribute.Src, Page.ClientScript.GetWebResourceUrl (typeof (SiteMapPath), "transparent.gif"));
476                                 w.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0px");
477                                 w.RenderBeginTag (HtmlTextWriterTag.Img);
478                                 w.RenderEndTag ();
479
480                                 w.RenderEndTag ();
481                         }
482
483                         base.RenderContents (w);
484
485                         if (needAnchor) {
486                                  w.AddAttribute(HtmlTextWriterAttribute.Id, skip_id);
487                                  w.RenderBeginTag(HtmlTextWriterTag.A);
488                                  w.RenderEndTag();
489                         }
490                 }
491                 
492                 protected override object SaveViewState ()
493                 {
494                         object[] state = new object [5];
495                         state [0] = base.SaveViewState ();
496                         
497                         if (currentNodeStyle != null) state [1] = ((IStateManager)currentNodeStyle).SaveViewState ();
498                         if (nodeStyle != null) state [2] = ((IStateManager)nodeStyle).SaveViewState ();
499                         if (pathSeparatorStyle != null) state [3] = ((IStateManager)pathSeparatorStyle).SaveViewState ();
500                         if (rootNodeStyle != null) state [4] = ((IStateManager)rootNodeStyle).SaveViewState ();
501                         
502                         for (int n=0; n<state.Length; n++)
503                                 if (state [n] != null) return state;
504                         return null;
505                 }
506                 
507                 protected override void TrackViewState ()
508                 {
509                         base.TrackViewState();
510                         if (currentNodeStyle != null) ((IStateManager)currentNodeStyle).TrackViewState();
511                         if (nodeStyle != null) ((IStateManager)nodeStyle).TrackViewState();
512                         if (pathSeparatorStyle != null) ((IStateManager)pathSeparatorStyle).TrackViewState();
513                         if (rootNodeStyle != null) ((IStateManager)rootNodeStyle).TrackViewState();
514                 }
515         }
516 }
517
518 #endif