Merge pull request #2023 from juergenhoetzel/master
[mono.git] / mcs / class / System.Web / System.Web / SiteMapNode.cs
1 //
2 // System.Web.SiteMapNode
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //
7 // (C) 2003 Ben Maurer
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 using System.Collections;
32 using System.Collections.Specialized;
33 using System.Text;
34 using System.Web.UI;
35 using System.Web.UI.WebControls;
36 using System.ComponentModel;
37 using System.Resources;
38 using System.Security.Principal;
39
40 namespace System.Web {
41         public class SiteMapNode : IHierarchyData, INavigateUIData, ICloneable {
42         
43                 SiteMapNode () {}
44                 
45                 public SiteMapNode (SiteMapProvider provider, string key)
46                         : this (provider, key, null, null, null, null, null, null, null) {}
47                 public SiteMapNode (SiteMapProvider provider, string key, string url)
48                         : this (provider, key, url, null, null, null, null, null, null) {}
49                 public SiteMapNode (SiteMapProvider provider, string key, string url, string title)
50                         : this (provider, key, url, title, null, null, null, null, null) {}
51                 public SiteMapNode (SiteMapProvider provider, string key, string url, string title, string description)
52                         : this (provider, key, url, title, description, null, null, null, null) {}
53                 
54                 public SiteMapNode (SiteMapProvider provider, string key, string url, string title, string description,
55                                     IList roles, NameValueCollection attributes, NameValueCollection explicitResourceKeys,
56                                     string implicitResourceKey)
57                 {
58                         if (provider == null)
59                                 throw new ArgumentNullException ("provider");
60                         if (key == null)
61                                 throw new ArgumentNullException ("key");
62                         
63                         this.provider = provider;
64                         this.key = key;
65                         this.url = url;
66                         this.title = title;
67                         this.description = description;
68                         this.roles = roles;
69                         this.attributes = attributes;
70                         this.resourceKeys = explicitResourceKeys;
71                         this.resourceKey = implicitResourceKey;
72                 }
73
74                 public SiteMapDataSourceView GetDataSourceView (SiteMapDataSource owner, string viewName)
75                 {
76                         return new SiteMapDataSourceView (owner, viewName, this);
77                 }
78                 
79                 public SiteMapHierarchicalDataSourceView GetHierarchicalDataSourceView ()
80                 {
81                         return new SiteMapHierarchicalDataSourceView (this);
82                 }
83                 
84                 public virtual bool IsAccessibleToUser (System.Web.HttpContext ctx)
85                 {
86                         return provider.IsAccessibleToUser (ctx, this);
87                 }
88                 
89                 public override string ToString()
90                 {
91                         return Title;
92                 }
93
94                 public virtual bool HasChildNodes {
95                         get {
96                                 SiteMapNodeCollection childNodes = ChildNodes;
97                                 return childNodes != null && childNodes.Count > 0;
98                         }
99                 }
100
101                 public SiteMapNodeCollection GetAllNodes ()
102                 {
103                         SiteMapNodeCollection ret;
104                 
105                         ret = new SiteMapNodeCollection ();
106                         GetAllNodesRecursive (ret);
107                         return SiteMapNodeCollection.ReadOnly (ret);
108                 }
109                 
110                 void GetAllNodesRecursive(SiteMapNodeCollection c)
111                 {
112                         SiteMapNodeCollection childNodes = this.ChildNodes;
113
114                         if (childNodes != null && childNodes.Count > 0) {
115                                 c.AddRange (childNodes);
116                                 foreach (SiteMapNode n in childNodes)
117                                         n.GetAllNodesRecursive (c);
118                         }
119                 }
120
121                 
122                 public virtual bool IsDescendantOf (SiteMapNode node)
123                 {
124                         for (SiteMapNode n = ParentNode; n != null; n = n.ParentNode)
125                                 if (n == node) return true; 
126
127                         return false; 
128                 }
129                 
130                 public virtual SiteMapNode NextSibling {
131                         get {
132                                 IList siblings = this.SiblingNodes;
133                                 if (siblings == null)
134                                         return null; 
135                                 
136                                 int pos = siblings.IndexOf (this);
137                                 if (pos >= 0 && pos < siblings.Count - 1)
138                                         return (SiteMapNode) siblings [pos + 1]; 
139                                 
140                                 return null; 
141                         }
142                 }
143                 
144                 public virtual SiteMapNode PreviousSibling {
145                         get {
146                                 IList siblings = this.SiblingNodes;
147                                 if (siblings == null)
148                                         return null; 
149                                 
150                                 int pos = siblings.IndexOf (this);
151                                 if (pos > 0 && pos < siblings.Count)
152                                         return (SiteMapNode) siblings [pos - 1]; 
153                                 
154                                 return null; 
155                         }
156                 }
157                 
158                 public virtual SiteMapNode ParentNode {
159                         get {
160                                 if (parent != null) return parent;
161                                 
162                                 SiteMapProvider provider = this.provider;
163                                 
164                                 do {
165                                         parent = provider.GetParentNode (this);
166                                         if (parent != null)
167                                                 return parent; 
168                                         
169                                         provider = provider.ParentProvider;
170                                 } while (provider != null);
171                                 return null;
172                         }
173                         set {
174                                 CheckWritable ();
175                                 parent = value;
176                         }
177                 }
178
179                 public virtual SiteMapNodeCollection ChildNodes {
180                         get {
181                                 if (provider.SecurityTrimmingEnabled) {
182                                         IPrincipal p = HttpContext.Current.User;
183                                         if ((user == null && user != p) || user != null && user != p) {
184                                                 user = p;
185                                                 childNodes = provider.GetChildNodes (this);
186                                         }
187                                 } else if (childNodes == null) {
188                                         childNodes = provider.GetChildNodes (this);
189                                 }
190                                 return childNodes;
191                         } 
192                         set {
193                                 CheckWritable ();
194                                 user = null;
195                                 childNodes = value;
196                         }
197                 }
198
199                 public virtual SiteMapNode RootNode { get { return provider.RootProvider.RootNode; }  }
200                 
201                 SiteMapNodeCollection SiblingNodes {
202                         get {
203                                 if (ParentNode != null)
204                                         return ParentNode.ChildNodes;
205                                 
206                                 return null;
207                         }
208                 }
209                 
210                 protected string GetExplicitResourceString (string attributeName, string defaultValue, bool throwIfNotFound)
211                 {
212                         if (attributeName == null)
213                                 throw new ArgumentNullException ("attributeName");
214                         
215                         if (resourceKeys != null){
216                                 string[] values = resourceKeys.GetValues (attributeName);
217                                 if (values != null && values.Length == 2) {
218                                         try {
219                                                 object o = HttpContext.GetGlobalResourceObject (values [0], values [1]);
220                                                 if (o is string)
221                                                         return (string) o;
222                                         }
223                                         catch (MissingManifestResourceException) {
224                                         }
225
226                                         if (throwIfNotFound && defaultValue == null)
227                                                 throw new InvalidOperationException (String.Format ("The resource object with classname '{0}' and key '{1}' was not found.", values [0], values [1]));
228                                 }
229                         }
230
231                         return defaultValue;
232                 }
233
234                 protected string GetImplicitResourceString (string attributeName)
235                 {
236                         if (attributeName == null)
237                                 throw new ArgumentNullException ("attributeName");
238
239                         string resourceKey = ResourceKey;
240                         if (String.IsNullOrEmpty (resourceKey))
241                                 return null;
242
243                         try {
244                                 object o = HttpContext.GetGlobalResourceObject (provider.ResourceKey, resourceKey + "." + attributeName);
245                                 if (o is string)
246                                         return (string) o;
247                         } catch (MissingManifestResourceException) {
248                         }
249                         
250                         return null;
251                 }
252                 
253                 public virtual string this [string key]
254                 {
255                         get {
256                                 if (provider.EnableLocalization) {
257                                         string val = GetImplicitResourceString (key);
258                                         if (val == null)
259                                                 val = GetExplicitResourceString (key, null, true);
260                                         if (val != null)
261                                                 return val;
262                                 }
263                                 if (attributes != null) return attributes [key];
264                                 return null;
265                         }
266                         set {
267                                 CheckWritable ();
268                                 if (attributes == null) attributes = new NameValueCollection ();
269                                 attributes [key] = value;
270                         }
271                 }
272                 
273                 object ICloneable.Clone ()
274                 {
275                         return Clone (false);
276                 }
277                 
278                 public virtual SiteMapNode Clone ()
279                 {
280                         return Clone (false);
281                 }
282                 
283                 public virtual SiteMapNode Clone (bool cloneParentNodes)
284                 {
285                         SiteMapNode node = new SiteMapNode ();
286                         node.provider = provider;
287                         node.key = key;
288                         node.url = url;
289                         node.title = title;
290                         node.description = description;
291                         if (roles != null)
292                                 node.roles = new ArrayList (roles);
293                         if (attributes != null)
294                                 node.attributes = new NameValueCollection (attributes);
295                         if (cloneParentNodes && ParentNode != null)
296                                 node.parent = (SiteMapNode) ParentNode.Clone (true);
297                         return node;
298                 }
299                                 
300                 public override bool Equals (object ob)
301                 {
302                         SiteMapNode node = ob as SiteMapNode;
303                         if (node == null) return false;
304                         
305                         if (node.key != key ||
306                                         node.url != url ||
307                                         node.title != title ||
308                                         node.description != description) {
309                                 return false;
310                         }
311
312                         if (roles == null || node.roles == null) {
313                                 if (roles != node.roles)
314                                         return false;
315                         }
316                         else {
317                                 if (roles.Count != node.roles.Count)
318                                         return false;
319
320                                 foreach (object role in roles)
321                                         if (!node.roles.Contains (role)) return false;
322                         }
323                         if (attributes == null || node.attributes == null) {
324                                 if (attributes != node.attributes)
325                                         return false;
326                         }
327                         else {
328                                 if (attributes.Count != node.attributes.Count)
329                                         return false;
330
331                                 foreach (string k in attributes)
332                                         if (attributes[k] != node.attributes[k])
333                                                 return false;
334                         }
335                         return true;
336                 }
337                 
338                 public override int GetHashCode ()
339                 {
340                         return (key + url + title + description).GetHashCode ();
341                 }
342                 
343                 void CheckWritable ()
344                 {
345                         if (readOnly)
346                                 throw new InvalidOperationException ("Can't modify read-only node");
347                 }
348                                 
349                 #region Field Accessors
350                 
351                 protected NameValueCollection Attributes {
352                         get { return attributes; } 
353                         set { CheckWritable (); attributes = value; }
354                 }
355                 
356                 [Localizable (true)]
357                 public virtual string Description {
358                         get {
359                                 string ret = null;
360                                 
361                                 if (provider.EnableLocalization) {
362                                         ret = GetImplicitResourceString ("description");
363                                         if (ret == null)
364                                                 ret = GetExplicitResourceString ("description", description, true);
365                                 } else
366                                         ret = description;
367                                 
368                                 return ret != null ? ret : String.Empty;
369                         }
370                         set { CheckWritable (); description = value; }
371                 }
372                 
373                 [LocalizableAttribute (true)]
374                 public virtual string Title {
375                         get {
376                                 string ret = null;
377
378                                 if (provider.EnableLocalization) {
379                                         ret = GetImplicitResourceString ("title");
380                                         if (ret == null)
381                                                 ret = GetExplicitResourceString ("title", title, true);
382                                 } else
383                                         ret = title;
384                                 
385                                 return ret != null ? ret : String.Empty;
386                         }
387                         set { CheckWritable (); title = value; }
388                 }
389                 
390                 public virtual string Url {
391                         get { return url != null ? url : ""; }
392                         set { CheckWritable (); url = value; }
393                 }
394                 
395                 public IList Roles {
396                         get { return roles; }
397                         set { CheckWritable (); roles = value; }
398                 }
399                 
400                 public bool ReadOnly {
401                         get { return readOnly; }
402                         set { readOnly = value; }
403                 }
404                 
405                 public string ResourceKey {
406                         get { return resourceKey; }
407                         set {
408                                 if (ReadOnly)
409                                         throw new InvalidOperationException ("The node is read-only.");
410                                 resourceKey = value;
411                         }
412                 }
413                 
414                 public string Key { get { return key; } }
415                 public SiteMapProvider Provider { get { return provider; } }
416                 
417                 #endregion
418                 
419                 #region INavigateUIData
420                 IHierarchicalEnumerable System.Web.UI.IHierarchyData.GetChildren () { return ChildNodes; }
421                 IHierarchyData System.Web.UI.IHierarchyData.GetParent ()
422                 {
423                         return ParentNode;
424                 }
425
426                 bool System.Web.UI.IHierarchyData.HasChildren { get { return HasChildNodes; } }
427                 object System.Web.UI.IHierarchyData.Item { get { return this; } }
428                 string System.Web.UI.IHierarchyData.Path { get { return Url; } }
429                 string System.Web.UI.IHierarchyData.Type { get { return "SiteMapNode"; } }
430                 #endregion
431                 
432                 #region INavigateUIData
433                 string INavigateUIData.Name { get { return Title; }  }
434                 string INavigateUIData.NavigateUrl { get { return Url; } }
435                 string INavigateUIData.Value { get { return Title; } }
436                 #endregion
437
438                 #region Fields
439                 SiteMapProvider provider;
440                 string key;
441                 string url;
442                 string title;
443                 string description;
444                 IList roles;
445                 NameValueCollection attributes;
446                 NameValueCollection resourceKeys;
447                 bool readOnly;
448                 string resourceKey;
449                 SiteMapNode parent;
450                 SiteMapNodeCollection childNodes;
451                 IPrincipal user;
452                 #endregion
453                 
454         }
455 }
456
457