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