1 //
2 // System.Web.UI.MasterPage.cs
3 //
4 // Authors:
5 //   Lluis Sanchez Gual (lluis@novell.com)
6 //
7 // (C) 2005-2010 Novell, Inc.
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;
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.ComponentModel;
35 using System.Web.Compilation;
36 using System.Web.Hosting;
37 using System.Web.Util;
38 using System.Web.UI.WebControls;
39 using System.IO;
40 
41 namespace System.Web.UI
42 {
43 	[ParseChildren (false)]
44 #if notyet
45 	[Designer (...)]
46 #endif
47 	[ControlBuilder (typeof (MasterPageControlBuilder))]
48 	public class MasterPage: UserControl
49 	{
50 		Hashtable definedContentTemplates = new Hashtable ();
51 		Hashtable templates = new Hashtable ();
52 		List <string> placeholders;
53 		string parentMasterPageFile = null;
54 		MasterPage parentMasterPage;
55 
56 		[EditorBrowsable (EditorBrowsableState.Advanced)]
AddContentTemplate(string templateName, ITemplate template)57 		protected internal void AddContentTemplate (string templateName, ITemplate template)
58 		{
59 			// LAMESPEC: should be ArgumentException
60 			if (definedContentTemplates.ContainsKey (templateName))
61 				throw new HttpException ("Multiple contents applied to " + templateName);
62 
63 			definedContentTemplates [templateName] = template;
64 		}
65 
66 		[Browsable (false)]
67 		[EditorBrowsable (EditorBrowsableState.Advanced)]
68 		protected internal IList ContentPlaceHolders {
69 			get {
70 				if (placeholders == null)
71 					placeholders = new List <string> ();
72 				return placeholders;
73 			}
74 		}
75 
76 		[Browsable (false)]
77 		[EditorBrowsable (EditorBrowsableState.Advanced)]
78 		protected internal IDictionary ContentTemplates {
79 			get { return templates; }
80 		}
81 
82 		[DefaultValueAttribute ("")]
83 		public string MasterPageFile {
84 			get { return parentMasterPageFile; }
85 			set {
86 				parentMasterPageFile = value;
87 				parentMasterPage = null;
88 			}
89 		}
90 
91 		[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
92 		[BrowsableAttribute (false)]
93 		public MasterPage Master {
94 			get {
95 				if (parentMasterPage == null && parentMasterPageFile != null)
96 					parentMasterPage = MasterPage.CreateMasterPage (this, Context, parentMasterPageFile, definedContentTemplates);
97 
98 				return parentMasterPage;
99 			}
100 		}
InstantiateInContentPlaceHolder(Control contentPlaceHolder, ITemplate template)101 		public void InstantiateInContentPlaceHolder (Control contentPlaceHolder, ITemplate template)
102 		{
103 			// .NET compatibility...
104 			if (contentPlaceHolder == null || template == null)
105 				throw new NullReferenceException ();
106 
107 			if (contentPlaceHolder != null && template != null)
108 				template.InstantiateIn (contentPlaceHolder);
109 		}
CreateMasterPage(TemplateControl owner, HttpContext context, string masterPageFile, IDictionary contentTemplateCollection)110 		internal static MasterPage CreateMasterPage (TemplateControl owner, HttpContext context,
111 							     string masterPageFile, IDictionary contentTemplateCollection)
112 		{
113 			var req = context.Request;
114 			if (req != null)
115 				masterPageFile = HostingEnvironment.VirtualPathProvider.CombineVirtualPaths (req.CurrentExecutionFilePath, masterPageFile);
116 			MasterPage masterPage = BuildManager.CreateInstanceFromVirtualPath (masterPageFile, typeof (MasterPage)) as MasterPage;
117 			if (masterPage == null)
118 				throw new HttpException ("Failed to create MasterPage instance for '" + masterPageFile + "'.");
119 
120 			if (contentTemplateCollection != null) {
121 				foreach (string templateName in contentTemplateCollection.Keys) {
122 					if (masterPage.ContentTemplates [templateName] == null)
123 						masterPage.ContentTemplates [templateName] = contentTemplateCollection[templateName];
124 				}
125 			}
126 
127 			masterPage.Page = owner.Page;
128 			masterPage.InitializeAsUserControlInternal ();
129 
130 			List <string> placeholders = masterPage.placeholders;
131 			if (contentTemplateCollection != null && placeholders != null && placeholders.Count > 0) {
132 				foreach (string templateName in contentTemplateCollection.Keys) {
133 					if (!placeholders.Contains (templateName.ToLowerInvariant ())) {
134 						throw new HttpException (
135 							String.Format ("Cannot find ContentPlaceHolder '{0}' in the master page '{1}'",
136 								       templateName, masterPageFile));
137 					}
138 				}
139 			}
140 
141 			return masterPage;
142 		}
143 
ApplyMasterPageRecursive(string currentFilePath, VirtualPathProvider vpp, MasterPage master, Dictionary <string, bool> appliedMasterPageFiles)144 		internal static void ApplyMasterPageRecursive (string currentFilePath, VirtualPathProvider vpp, MasterPage master, Dictionary <string, bool> appliedMasterPageFiles)
145 		{
146 			/* XXX need to use virtual paths here? */
147 			string mpFile = master.MasterPageFile;
148 			if (!String.IsNullOrEmpty (mpFile)) {
149 				mpFile = vpp.CombineVirtualPaths (currentFilePath, mpFile);
150 				if (appliedMasterPageFiles.ContainsKey (mpFile))
151 					throw new HttpException ("circular dependency in master page files detected");
152 
153 				MasterPage innerMaster = master.Master;
154 				if (innerMaster != null) {
155 					master.Controls.Clear ();
156 					master.Controls.Add (innerMaster);
157 					appliedMasterPageFiles.Add (mpFile, true);
158 					MasterPage.ApplyMasterPageRecursive (currentFilePath, vpp, innerMaster, appliedMasterPageFiles);
159 				}
160 			}
161 		}
162 	}
163 }
164