Merge pull request #2916 from ludovic-henry/fix-40306
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / SiteMapDataSource.cs
1 //
2 // System.Web.UI.WebControls.SiteMapDataSource.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
32 using System;
33 using System.Collections;
34 using System.Drawing;
35 using System.Web.UI;
36 using System.Web.Util;
37 using System.ComponentModel;
38 using System.Collections.Generic;
39
40 namespace System.Web.UI.WebControls
41 {
42         [PersistChildrenAttribute (false)]
43         [DesignerAttribute ("System.Web.UI.Design.WebControls.SiteMapDataSourceDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
44         [ParseChildrenAttribute (true)]
45         [ToolboxBitmap ("")]
46         public class SiteMapDataSource : HierarchicalDataSourceControl, IDataSource, IListSource
47         {
48                 static string[] emptyNames = new string[] { "DefaultView" };
49                 
50                 SiteMapProvider provider;
51                 
52                 public virtual ICollection GetViewNames ()
53                 {
54                         return emptyNames;
55                 }
56
57                 IList IListSource.GetList () {
58                         return GetList ();
59                 }
60
61                 bool IListSource.ContainsListCollection {
62                         get { return ContainsListCollection; }
63                 }
64
65                 public virtual IList GetList ()
66                 {
67                         return ListSourceHelper.GetList (this);
68                 }
69                 
70                 [BrowsableAttribute (false)]
71                 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
72                 public virtual bool ContainsListCollection {
73                         get { return ListSourceHelper.ContainsListCollection (this); }
74                 }
75
76                 DataSourceView IDataSource.GetView (string viewName) {
77                         return GetView (viewName);
78                 }
79
80                 ICollection IDataSource.GetViewNames () {
81                         return GetViewNames ();
82                 }
83                 
84                 event EventHandler IDataSource.DataSourceChanged {
85                         add { ((IHierarchicalDataSource)this).DataSourceChanged += value; }
86                         remove { ((IHierarchicalDataSource)this).DataSourceChanged -= value; }
87                 }
88                 
89                 [BrowsableAttribute (false)]
90                 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
91                 public SiteMapProvider Provider {
92                         get {
93                                 if (provider == null) {
94                                         if (this.SiteMapProvider.Length == 0) {
95                                                 provider = SiteMap.Provider;
96                                                 if (provider == null)
97                                                         throw new HttpException ("There is no default provider configured for the site.");
98                                         } else {
99                                                 provider = SiteMap.Providers [this.SiteMapProvider];
100                                                 if (provider == null)
101                                                         throw new HttpException ("SiteMap provider '" + this.SiteMapProvider + "' not found.");
102                                         }
103                                 }
104                                 return provider;
105                         }
106                         set {
107                                 provider = value;
108                                 OnDataSourceChanged (EventArgs.Empty);
109                         }
110                 }
111                 
112                 [DefaultValueAttribute ("")]
113                 public virtual string SiteMapProvider {
114                         get { return ViewState.GetString ("SiteMapProvider", ""); }
115                         set {
116                                 ViewState ["SiteMapProvider"] = value;
117                                 OnDataSourceChanged (EventArgs.Empty);
118                         }
119                 }
120                 
121                 [DefaultValueAttribute ("")]
122                 [EditorAttribute ("System.Web.UI.Design.UrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
123                 [UrlPropertyAttribute]
124                 public virtual string StartingNodeUrl {
125                         get { return ViewState.GetString ("StartingNodeUrl", ""); }
126                         set {
127                                 ViewState ["StartingNodeUrl"] = value;
128                                 OnDataSourceChanged (EventArgs.Empty);
129                         }
130                 }
131
132                 [DefaultValue (0)]
133                 public virtual int StartingNodeOffset {
134                         get { return ViewState.GetInt ("StartingNodeOffset", 0); }
135                         set {
136                                 ViewState ["StartingNodeOffset"] = value;
137                                 OnDataSourceChanged (EventArgs.Empty);
138                         }
139                 }
140                 
141                 [DefaultValueAttribute (false)]
142                 public virtual bool StartFromCurrentNode {
143                         get { return ViewState.GetBool ("StartFromCurrentNode", false); }
144                         set {
145                                 ViewState ["StartFromCurrentNode"] = value;
146                                 OnDataSourceChanged (EventArgs.Empty);
147                         }
148                 }
149                 
150                 [DefaultValueAttribute (true)]
151                 public virtual bool ShowStartingNode {
152                         get { return ViewState.GetBool ("ShowStartingNode", true); }
153                         set {
154                                 ViewState ["ShowStartingNode"] = value;
155                                 OnDataSourceChanged (EventArgs.Empty);
156                         }
157                 }
158
159                 public virtual DataSourceView GetView (string viewName)
160                 {
161                         SiteMapNode node = GetStartNode (viewName);
162                         if (node == null)
163                                 return new SiteMapDataSourceView (this, viewName, SiteMapNodeCollection.EmptyList);
164                         else if (ShowStartingNode)
165                                 return new SiteMapDataSourceView (this, viewName, node);
166                         else
167                                 return new SiteMapDataSourceView (this, viewName, node.ChildNodes);
168                 }
169
170                 protected override HierarchicalDataSourceView GetHierarchicalView (string viewPath)
171                 {
172                         SiteMapNode node = GetStartNode (viewPath);
173                         if (node == null)
174                                 return new SiteMapHierarchicalDataSourceView (SiteMapNodeCollection.EmptyList);
175                         else if (ShowStartingNode || node == null)
176                                 return new SiteMapHierarchicalDataSourceView (node);
177                         else
178                                 return new SiteMapHierarchicalDataSourceView (node.ChildNodes);
179                 }
180                 
181                 [MonoTODO ("handle StartNodeOffsets > 0")]
182                 SiteMapNode GetStartNode (string viewPath)
183                 {
184                         SiteMapNode starting_node;
185
186                         if (viewPath != null && viewPath.Length != 0) {
187                                 string url = MapUrl (StartingNodeUrl);
188                                 return Provider.FindSiteMapNode (url);
189                         } else if (StartFromCurrentNode) {
190                                 if (StartingNodeUrl.Length != 0)
191                                         throw new InvalidOperationException ("StartingNodeUrl can't be set if StartFromCurrentNode is set to true.");
192                                 starting_node = SiteMap.CurrentNode;
193                         } else if (StartingNodeUrl.Length != 0) {
194                                 string url = MapUrl (StartingNodeUrl);
195                                 SiteMapNode node = Provider.FindSiteMapNode (url);
196                                 if (node == null) throw new ArgumentException ("Can't find a site map node for the url: " + StartingNodeUrl);
197
198                                 starting_node = node;
199                         } else
200                                 starting_node = Provider.RootNode;
201
202                         if (starting_node == null)
203                                 return null;
204                         
205                         int i;
206                         if (StartingNodeOffset < 0) {
207                                 for (i = StartingNodeOffset; i < 0; i ++) {
208                                         if (starting_node.ParentNode == null)
209                                                 break;
210                                         starting_node = starting_node.ParentNode;
211                                 }
212                         } else if (StartingNodeOffset > 0) {
213                                 List<SiteMapNode> pathCurrentToStartingNode = new List<SiteMapNode> ();
214                                 SiteMapNode tmpNode = Provider.CurrentNode;
215                                 while (tmpNode != null && tmpNode != starting_node) {
216                                         pathCurrentToStartingNode.Insert (0, tmpNode);
217                                         tmpNode = tmpNode.ParentNode;
218                                 }
219                                 if (tmpNode == starting_node &&
220                                         StartingNodeOffset <= pathCurrentToStartingNode.Count) {
221                                         // The requested node is in the same subtree as the starting_node
222                                         // try to advance on this path.
223                                         starting_node = pathCurrentToStartingNode [StartingNodeOffset - 1];
224                                 }
225                         }
226
227                         return starting_node;
228                 }
229                 
230                 string MapUrl (string url)
231                 {
232                         if (String.IsNullOrEmpty (url))
233                                 return String.Empty;
234                         if (UrlUtils.IsRelativeUrl (url))
235                                 return UrlUtils.Combine (HttpRuntime.AppDomainAppVirtualPath, url);
236                         else
237                                 return UrlUtils.ResolveVirtualPathFromAppAbsolute (url);
238                 }
239         }
240 }
241
242
243