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