2 // System.Web.UI.ControlBuilder.cs
5 // Duncan Mak (duncan@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // (C) 2002, 2003 Ximian, Inc. (http://www.ximian.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
35 using System.Reflection;
37 using System.Web.Compilation;
39 namespace System.Web.UI {
41 public class ControlBuilder
43 internal static BindingFlags flagsNoCase = BindingFlags.Public |
44 BindingFlags.Instance |
46 BindingFlags.IgnoreCase;
48 TemplateParser parser;
49 internal ControlBuilder parentBuilder;
53 internal IDictionary attribs;
55 internal string fileName;
56 bool childrenAsProperties;
57 bool isIParserAccessor = true;
59 internal ControlBuilder defaultPropertyBuilder;
63 internal bool haveParserVariable;
64 internal CodeMemberMethod method;
65 internal CodeMemberMethod renderMethod;
66 internal int renderIndex;
67 internal bool isProperty;
68 internal ILocation location;
70 public ControlBuilder ()
74 internal ControlBuilder (TemplateParser parser,
75 ControlBuilder parentBuilder,
81 string sourceFileName)
85 this.parentBuilder = parentBuilder;
87 this.tagName = tagName;
89 this.attribs = attribs;
91 this.fileName = sourceFileName;
94 public Type ControlType {
98 protected bool FChildrenAsProperties {
99 get { return childrenAsProperties; }
102 protected bool FIsNonParserAccessor {
103 get { return !isIParserAccessor; }
106 public bool HasAspCode {
107 get { return hasAspCode; }
115 internal ArrayList Children {
116 get { return children; }
119 internal void SetControlType (Type t)
124 protected bool InDesigner {
125 get { return false; }
128 public Type NamingContainerType {
130 if (parentBuilder == null)
131 return typeof (Control);
133 Type ptype = parentBuilder.ControlType;
135 return parentBuilder.NamingContainerType;
137 if (!typeof (INamingContainer).IsAssignableFrom (ptype))
138 return parentBuilder.NamingContainerType;
144 protected TemplateParser Parser {
145 get { return parser; }
148 public string TagName {
149 get { return tagName; }
152 internal RootBuilder Root {
154 if (GetType () == typeof (RootBuilder))
155 return (RootBuilder) this;
157 return (RootBuilder) parentBuilder.Root;
161 internal bool ChildrenAsProperties {
162 get { return childrenAsProperties; }
165 public virtual bool AllowWhitespaceLiterals ()
170 public virtual void AppendLiteralString (string s)
172 if (s == null || s == "")
175 if (childrenAsProperties || !isIParserAccessor) {
176 if (defaultPropertyBuilder != null) {
177 defaultPropertyBuilder.AppendLiteralString (s);
178 } else if (s.Trim () != "") {
179 throw new HttpException ("Literal content not allowed for " + tagName + " " +
180 GetType () + " \"" + s + "\"");
186 if (!AllowWhitespaceLiterals () && s.Trim () == "")
189 if (HtmlDecodeLiterals ())
190 s = HttpUtility.HtmlDecode (s);
192 if (children == null)
193 children = new ArrayList ();
198 public virtual void AppendSubBuilder (ControlBuilder subBuilder)
200 subBuilder.OnAppendToParentBuilder (this);
202 subBuilder.parentBuilder = this;
203 if (childrenAsProperties) {
204 AppendToProperty (subBuilder);
208 if (typeof (CodeRenderBuilder).IsAssignableFrom (subBuilder.GetType ())) {
209 AppendCode (subBuilder);
213 if (children == null)
214 children = new ArrayList ();
216 children.Add (subBuilder);
219 void AppendToProperty (ControlBuilder subBuilder)
221 if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
222 throw new HttpException ("Code render not supported here.");
224 if (defaultPropertyBuilder != null) {
225 defaultPropertyBuilder.AppendSubBuilder (subBuilder);
229 if (children == null)
230 children = new ArrayList ();
232 children.Add (subBuilder);
235 void AppendCode (ControlBuilder subBuilder)
237 if (type != null && !(typeof (Control).IsAssignableFrom (type)))
238 throw new HttpException ("Code render not supported here.");
240 if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
243 if (children == null)
244 children = new ArrayList ();
246 children.Add (subBuilder);
249 public virtual void CloseControl ()
253 public static ControlBuilder CreateBuilderFromType (TemplateParser parser,
254 ControlBuilder parentBuilder,
260 string sourceFileName)
262 ControlBuilder builder;
263 object [] atts = type.GetCustomAttributes (typeof (ControlBuilderAttribute), true);
264 if (atts != null && atts.Length > 0) {
265 ControlBuilderAttribute att = (ControlBuilderAttribute) atts [0];
266 builder = (ControlBuilder) Activator.CreateInstance (att.BuilderType);
268 builder = new ControlBuilder ();
271 builder.Init (parser, parentBuilder, type, tagName, id, attribs);
273 builder.fileName = sourceFileName;
277 public virtual Type GetChildControlType (string tagName, IDictionary attribs)
282 public virtual bool HasBody ()
287 public virtual bool HtmlDecodeLiterals ()
292 ControlBuilder CreatePropertyBuilder (string propName, TemplateParser parser, IDictionary atts)
294 PropertyInfo prop = type.GetProperty (propName, flagsNoCase);
296 string msg = String.Format ("Property {0} not found in type {1}", propName, type);
297 throw new HttpException (msg);
300 Type propType = prop.PropertyType;
301 ControlBuilder builder = null;
302 if (typeof (ICollection).IsAssignableFrom (propType)) {
303 builder = new CollectionBuilder ();
304 } else if (typeof (ITemplate).IsAssignableFrom (propType)) {
305 builder = new TemplateBuilder ();
307 builder = CreateBuilderFromType (parser, parentBuilder, propType, prop.Name,
308 null, atts, line, fileName);
309 builder.isProperty = true;
313 builder.Init (parser, this, null, prop.Name, null, atts);
314 builder.fileName = fileName;
316 builder.isProperty = true;
320 public virtual void Init (TemplateParser parser,
321 ControlBuilder parentBuilder,
327 this.parser = parser;
329 this.location = parser.Location;
331 this.parentBuilder = parentBuilder;
333 this.tagName = tagName;
335 this.attribs = attribs;
339 if (this is TemplateBuilder)
342 if (!typeof (IParserAccessor).IsAssignableFrom (type)) {
343 isIParserAccessor = false;
344 childrenAsProperties = true;
346 object [] atts = type.GetCustomAttributes (typeof (ParseChildrenAttribute), true);
347 if (atts != null && atts.Length > 0) {
348 ParseChildrenAttribute att = (ParseChildrenAttribute) atts [0];
349 childrenAsProperties = att.ChildrenAsProperties;
350 if (childrenAsProperties && att.DefaultProperty != "") {
351 defaultPropertyBuilder = CreatePropertyBuilder (att.DefaultProperty,
358 public virtual bool NeedsTagInnerText ()
363 public virtual void OnAppendToParentBuilder (ControlBuilder parentBuilder)
365 if (defaultPropertyBuilder == null)
368 ControlBuilder old = defaultPropertyBuilder;
369 defaultPropertyBuilder = null;
370 AppendSubBuilder (old);
373 internal void SetTagName (string name)
378 public virtual void SetTagInnerText (string text)
382 internal string GetNextID (string proposedID)
384 if (proposedID != null && proposedID.Trim () != "")
387 return "_bctrl_" + nextID++;
390 internal virtual ControlBuilder CreateSubBuilder (string tagid,
393 TemplateParser parser,
396 ControlBuilder childBuilder = null;
397 if (childrenAsProperties) {
398 if (defaultPropertyBuilder == null) {
399 childBuilder = CreatePropertyBuilder (tagid, parser, atts);
401 childBuilder = defaultPropertyBuilder.CreateSubBuilder (tagid, atts,
402 null, parser, location);
407 childType = GetChildControlType (tagid, atts);
408 if (childType == null)
411 childBuilder = CreateBuilderFromType (parser, this, childType, tagid, id, atts,
412 location.BeginLine, location.Filename);
417 internal virtual object CreateInstance ()
419 // HtmlGenericControl, HtmlTableCell...
420 object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
421 object [] args = null;
422 if (atts != null && atts.Length > 0) {
423 ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
425 args = new object [] {tagName};
428 return Activator.CreateInstance (type, args);
431 internal virtual void CreateChildren (object parent)
433 if (children == null || children.Count == 0)
436 IParserAccessor parser = parent as IParserAccessor;
440 foreach (object o in children) {
442 parser.AddParsedSubObject (new LiteralControl ((string) o));
444 parser.AddParsedSubObject (((ControlBuilder) o).CreateInstance ());