1 //------------------------------------------------------------------------------
2 // <copyright file="SiteMapNode.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
8 * SiteMapNode class definition
10 * Copyright (c) 2002 Microsoft Corporation
13 namespace System.Web {
16 using System.Configuration.Provider;
17 using System.Collections;
18 using System.Collections.Specialized;
19 using System.ComponentModel;
20 using System.Resources;
21 using System.Security.Permissions;
22 using System.Web.Configuration;
23 using System.Web.Compilation;
25 using System.Web.UI.WebControls;
26 using System.Web.Util;
31 public class SiteMapNode : ICloneable, IHierarchyData, INavigateUIData {
33 private static readonly string _siteMapNodeType = typeof(SiteMapNode).Name;
35 private SiteMapProvider _provider;
37 private bool _readonly;
38 private bool _parentNodeSet;
39 private bool _childNodesSet;
41 private VirtualPath _virtualPath;
42 private string _title;
43 private string _description;
46 private string _resourceKey;
49 private NameValueCollection _attributes;
50 private NameValueCollection _resourceKeys;
52 private SiteMapNode _parentNode;
53 private SiteMapNodeCollection _childNodes;
55 public SiteMapNode(SiteMapProvider provider, string key) :
56 this(provider, key, null, null, null, null, null, null, null) {
59 public SiteMapNode(SiteMapProvider provider, string key, string url) :
60 this(provider, key, url, null, null, null, null, null, null) {
63 public SiteMapNode(SiteMapProvider provider, string key, string url, string title) :
64 this(provider, key, url, title, null, null, null, null, null) {
67 public SiteMapNode(SiteMapProvider provider, string key, string url, string title, string description) :
68 this(provider, key, url, title, description, null, null, null, null) {
71 public SiteMapNode(SiteMapProvider provider, string key, string url, string title, string description,
72 IList roles, NameValueCollection attributes, NameValueCollection explicitResourceKeys, string implicitResourceKey) {
76 _description = description;
78 _attributes = attributes;
80 _resourceKeys = explicitResourceKeys;
81 _resourceKey = implicitResourceKey;
87 _virtualPath = CreateVirtualPathFromUrl(_url);
90 throw new ArgumentNullException("key");
93 if (_provider == null) {
94 throw new ArgumentNullException("provider");
98 protected NameValueCollection Attributes {
104 throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "Attributes"));
111 // Access custom attributes.
112 public virtual string this[string key] {
115 if (_attributes != null) {
116 text = _attributes[key];
119 if (_provider.EnableLocalization) {
120 // Try the implicit resource first
121 string localizedText = GetImplicitResourceString(key);
122 if (localizedText != null) {
123 return localizedText;
126 // If not found, try the explicit resource.
127 localizedText = GetExplicitResourceString(key, text, true);
128 if (localizedText != null) {
129 return localizedText;
138 throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "Item"));
141 if (_attributes == null) {
142 _attributes = new NameValueCollection();
145 _attributes[key] = value;
149 public virtual SiteMapNodeCollection ChildNodes {
154 return _provider.GetChildNodes(this);
158 throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "ChildNodes"));
162 _childNodesSet = true;
169 public virtual string Description {
171 if (_provider.EnableLocalization) {
172 string localizedText = GetImplicitResourceString("description");
173 if (localizedText != null) {
174 return localizedText;
177 localizedText = GetExplicitResourceString("description", _description, true);
178 if (localizedText != null) {
179 return localizedText;
183 return _description == null? String.Empty : _description;
187 throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "Description"));
190 _description = value;
200 public virtual bool HasChildNodes {
202 IList children = ChildNodes;
203 return children != null && children.Count > 0;
207 public virtual SiteMapNode NextSibling {
209 IList siblings = SiblingNodes;
210 if (siblings == null) {
214 int index = siblings.IndexOf(this);
215 if (index >= 0 && index < siblings.Count - 1) {
216 return (SiteMapNode)siblings[index + 1];
223 // Get parent node. If not found in current provider, search recursively in parent providers.
224 public virtual SiteMapNode ParentNode {
229 return _provider.GetParentNode(this);
233 throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "ParentNode"));
237 _parentNodeSet = true;
241 public virtual SiteMapNode PreviousSibling {
243 IList siblings = SiblingNodes;
244 if (siblings == null) {
248 int index = siblings.IndexOf(this);
249 if (index > 0 && index <= siblings.Count - 1) {
250 return (SiteMapNode)siblings[index - 1];
257 public SiteMapProvider Provider {
263 public bool ReadOnly {
272 public String ResourceKey {
278 throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "ResourceKey"));
281 _resourceKey = value;
291 throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "Roles"));
298 public virtual SiteMapNode RootNode {
300 SiteMapNode root = _provider.RootProvider.RootNode;
302 String name = ((ProviderBase)_provider.RootProvider).Name;
303 throw new InvalidOperationException(SR.GetString(SR.SiteMapProvider_Invalid_RootNode, name));
310 private SiteMapNodeCollection SiblingNodes {
312 SiteMapNode parent = ParentNode;
313 return parent == null? null : parent.ChildNodes;
320 public virtual string Title {
322 if (_provider.EnableLocalization) {
323 string localizedText = GetImplicitResourceString("title");
324 if (localizedText != null) {
325 return localizedText;
328 localizedText = GetExplicitResourceString("title", _title, true);
329 if (localizedText != null) {
330 return localizedText;
334 return _title == null? String.Empty : _title;
338 throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "Title"));
345 public virtual string Url {
347 return _url == null? String.Empty : _url;
351 throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "Url"));
358 _virtualPath = CreateVirtualPathFromUrl(_url);
362 internal VirtualPath VirtualPath {
368 private VirtualPath CreateVirtualPathFromUrl(string url) {
369 if (String.IsNullOrEmpty(url)) {
373 if (!UrlPath.IsValidVirtualPathWithoutProtocol(url)) {
377 if (UrlPath.IsAbsolutePhysicalPath(url)) {
381 // Do not generate the virtualPath class at designtime.
382 if (HttpRuntime.AppDomainAppVirtualPath == null) {
386 if (UrlPath.IsRelativeUrl(url) && !UrlPath.IsAppRelativePath(url)) {
387 url = UrlPath.Combine(HttpRuntime.AppDomainAppVirtualPathString, url);
390 // Remove the query string from url so the path can be validated by Authorization module.
391 int queryStringIndex = url.IndexOf('?');
392 if (queryStringIndex != -1) {
393 url = url.Substring(0, queryStringIndex);
396 return VirtualPath.Create(url,
397 VirtualPathOptions.AllowAbsolutePath | VirtualPathOptions.AllowAppRelativePath);
400 public virtual SiteMapNode Clone() {
401 ArrayList newRoles = null;
402 NameValueCollection newAttributes = null;
403 NameValueCollection newResourceKeys = null;
405 if (_roles != null) {
406 newRoles = new ArrayList(_roles);
408 if (_attributes != null) {
409 newAttributes = new NameValueCollection(_attributes);
411 if (_resourceKeys != null) {
412 newResourceKeys = new NameValueCollection(_resourceKeys);
415 SiteMapNode newNode = new SiteMapNode(_provider, Key, Url, Title, Description, newRoles, newAttributes, newResourceKeys, _resourceKey);
419 public virtual SiteMapNode Clone(bool cloneParentNodes) {
420 SiteMapNode current = Clone();
422 if (cloneParentNodes) {
423 SiteMapNode node = current;
424 SiteMapNode parent = ParentNode;
425 while (parent != null) {
426 SiteMapNode cloneParent = parent.Clone();
427 node.ParentNode = cloneParent;
428 cloneParent.ChildNodes = new SiteMapNodeCollection(node);
430 parent = parent.ParentNode;
438 public override bool Equals(object obj) {
439 SiteMapNode node = obj as SiteMapNode;
440 return node != null && (_key == node.Key) &&
441 (String.Equals(_url, node._url, StringComparison.OrdinalIgnoreCase));
444 public SiteMapNodeCollection GetAllNodes() {
445 SiteMapNodeCollection collection = new SiteMapNodeCollection();
446 GetAllNodesRecursive(collection);
447 return SiteMapNodeCollection.ReadOnly(collection);
450 private void GetAllNodesRecursive(SiteMapNodeCollection collection) {
451 SiteMapNodeCollection childNodes = this.ChildNodes;
453 if (childNodes != null && childNodes.Count > 0) {
454 collection.AddRange(childNodes);
455 foreach(SiteMapNode node in childNodes)
456 node.GetAllNodesRecursive(collection);
460 public SiteMapDataSourceView GetDataSourceView(SiteMapDataSource owner, string viewName) {
461 return new SiteMapDataSourceView(owner, viewName, this);
465 public SiteMapHierarchicalDataSourceView GetHierarchicalDataSourceView() {
466 return new SiteMapHierarchicalDataSourceView(this);
469 // Helpe method to retrieve localized string based on attribute name
470 protected string GetExplicitResourceString(string attributeName, string defaultValue, bool throwIfNotFound) {
471 if (attributeName == null) {
472 throw new ArgumentNullException("attributeName");
476 if (_resourceKeys != null) {
477 string[] keys = _resourceKeys.GetValues(attributeName);
478 if (keys != null && keys.Length > 1) {
480 text = ResourceExpressionBuilder.GetGlobalResourceObject(keys[0], keys[1]) as string;
482 catch (MissingManifestResourceException) {
483 if (defaultValue != null) {
488 if (text == null && throwIfNotFound) {
489 // throw if default value is not specified.
490 throw new InvalidOperationException(
491 SR.GetString(SR.Res_not_found_with_class_and_key, keys[0], keys[1])); ;
499 // Only use the key to get the hashcode since url can be changed and makes the objects mutable.
500 public override int GetHashCode() {
501 return _key.GetHashCode();
504 // Helper method to retrieve localized string based on attribute name
505 protected string GetImplicitResourceString(string attributeName) {
506 if (attributeName == null) {
507 throw new ArgumentNullException("attributeName");
511 if (!String.IsNullOrEmpty(_resourceKey)) {
513 text = ResourceExpressionBuilder.GetGlobalResourceObject(Provider.ResourceKey, ResourceKey + "." + attributeName) as String;
521 public virtual bool IsAccessibleToUser(HttpContext context) {
522 return _provider.IsAccessibleToUser(context, this);
525 public virtual bool IsDescendantOf(SiteMapNode node) {
526 SiteMapNode parent = ParentNode;
527 while (parent != null) {
528 if (parent.Equals(node)) {
532 parent = parent.ParentNode;
538 public override string ToString() {
542 #region ICloneable implementation
545 object ICloneable.Clone() {
550 #region IHierarchyData implementation
553 bool IHierarchyData.HasChildren {
555 return HasChildNodes;
561 object IHierarchyData.Item {
569 string IHierarchyData.Path {
577 string IHierarchyData.Type {
579 return _siteMapNodeType;
585 IHierarchicalEnumerable IHierarchyData.GetChildren() {
591 IHierarchyData IHierarchyData.GetParent() {
592 SiteMapNode parentNode = ParentNode;
593 if (parentNode == null)
600 #region INavigateUIData implementations
601 string INavigateUIData.Description {
609 string INavigateUIData.Name {
617 string INavigateUIData.NavigateUrl {
625 string INavigateUIData.Value {