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)
9 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
31 using System.Collections;
33 using System.Reflection;
34 using System.Security.Permissions;
35 using System.Web.Compilation;
37 namespace System.Web.UI {
40 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
41 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
42 public class ControlBuilder
44 internal static BindingFlags flagsNoCase = BindingFlags.Public |
45 BindingFlags.Instance |
47 BindingFlags.IgnoreCase;
49 TemplateParser parser;
50 internal ControlBuilder parentBuilder;
54 internal IDictionary attribs;
56 internal string fileName;
57 bool childrenAsProperties;
58 bool isIParserAccessor = true;
60 internal ControlBuilder defaultPropertyBuilder;
64 internal bool haveParserVariable;
65 internal CodeMemberMethod method;
66 internal CodeStatementCollection methodStatements;
67 internal CodeMemberMethod renderMethod;
68 internal int renderIndex;
69 internal bool isProperty;
70 internal ILocation location;
73 public ControlBuilder ()
77 internal ControlBuilder (TemplateParser parser,
78 ControlBuilder parentBuilder,
84 string sourceFileName)
88 this.parentBuilder = parentBuilder;
90 this.tagName = tagName;
92 this.attribs = attribs;
94 this.fileName = sourceFileName;
97 internal void EnsureOtherTags ()
99 if (otherTags == null)
100 otherTags = new ArrayList ();
103 internal ArrayList OtherTags {
104 get { return otherTags; }
107 public Type ControlType {
111 protected bool FChildrenAsProperties {
112 get { return childrenAsProperties; }
115 protected bool FIsNonParserAccessor {
116 get { return !isIParserAccessor; }
119 public bool HasAspCode {
120 get { return hasAspCode; }
128 internal ArrayList Children {
129 get { return children; }
132 internal void SetControlType (Type t)
137 protected bool InDesigner {
138 get { return false; }
141 public Type NamingContainerType {
143 if (parentBuilder == null)
144 return typeof (Control);
146 Type ptype = parentBuilder.ControlType;
148 return parentBuilder.NamingContainerType;
150 if (!typeof (INamingContainer).IsAssignableFrom (ptype))
151 return parentBuilder.NamingContainerType;
162 Type BindingContainerType {
164 if (parentBuilder == null)
165 return typeof (Control);
167 if (parentBuilder is TemplateBuilder && ((TemplateBuilder)parentBuilder).ContainerType != null)
168 return ((TemplateBuilder)parentBuilder).ContainerType;
170 Type ptype = parentBuilder.ControlType;
172 return parentBuilder.BindingContainerType;
174 if (!typeof (INamingContainer).IsAssignableFrom (ptype))
175 return parentBuilder.BindingContainerType;
181 internal TemplateBuilder ParentTemplateBuilder {
183 if (parentBuilder == null)
185 else if (parentBuilder is TemplateBuilder)
186 return (TemplateBuilder) parentBuilder;
188 return parentBuilder.ParentTemplateBuilder;
192 protected TemplateParser Parser {
193 get { return parser; }
196 public string TagName {
197 get { return tagName; }
200 internal RootBuilder Root {
202 if (GetType () == typeof (RootBuilder))
203 return (RootBuilder) this;
205 return (RootBuilder) parentBuilder.Root;
209 internal bool ChildrenAsProperties {
210 get { return childrenAsProperties; }
213 public virtual bool AllowWhitespaceLiterals ()
218 public virtual void AppendLiteralString (string s)
220 if (s == null || s == "")
223 if (childrenAsProperties || !isIParserAccessor) {
224 if (defaultPropertyBuilder != null) {
225 defaultPropertyBuilder.AppendLiteralString (s);
226 } else if (s.Trim () != "") {
227 throw new HttpException ("Literal content not allowed for " + tagName + " " +
228 GetType () + " \"" + s + "\"");
234 if (!AllowWhitespaceLiterals () && s.Trim () == "")
237 if (HtmlDecodeLiterals ())
238 s = HttpUtility.HtmlDecode (s);
240 if (children == null)
241 children = new ArrayList ();
246 public virtual void AppendSubBuilder (ControlBuilder subBuilder)
248 subBuilder.OnAppendToParentBuilder (this);
250 subBuilder.parentBuilder = this;
251 if (childrenAsProperties) {
252 AppendToProperty (subBuilder);
256 if (typeof (CodeRenderBuilder).IsAssignableFrom (subBuilder.GetType ())) {
257 AppendCode (subBuilder);
261 if (children == null)
262 children = new ArrayList ();
264 children.Add (subBuilder);
267 void AppendToProperty (ControlBuilder subBuilder)
269 if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
270 throw new HttpException ("Code render not supported here.");
272 if (defaultPropertyBuilder != null) {
273 defaultPropertyBuilder.AppendSubBuilder (subBuilder);
277 if (children == null)
278 children = new ArrayList ();
280 children.Add (subBuilder);
283 void AppendCode (ControlBuilder subBuilder)
285 if (type != null && !(typeof (Control).IsAssignableFrom (type)))
286 throw new HttpException ("Code render not supported here.");
288 if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
291 if (children == null)
292 children = new ArrayList ();
294 children.Add (subBuilder);
297 public virtual void CloseControl ()
301 public static ControlBuilder CreateBuilderFromType (TemplateParser parser,
302 ControlBuilder parentBuilder,
308 string sourceFileName)
310 ControlBuilder builder;
311 object [] atts = type.GetCustomAttributes (typeof (ControlBuilderAttribute), true);
312 if (atts != null && atts.Length > 0) {
313 ControlBuilderAttribute att = (ControlBuilderAttribute) atts [0];
314 builder = (ControlBuilder) Activator.CreateInstance (att.BuilderType);
316 builder = new ControlBuilder ();
319 builder.Init (parser, parentBuilder, type, tagName, id, attribs);
321 builder.fileName = sourceFileName;
325 public virtual Type GetChildControlType (string tagName, IDictionary attribs)
330 public virtual bool HasBody ()
335 public virtual bool HtmlDecodeLiterals ()
340 ControlBuilder CreatePropertyBuilder (string propName, TemplateParser parser, IDictionary atts)
342 PropertyInfo prop = type.GetProperty (propName, flagsNoCase);
344 string msg = String.Format ("Property {0} not found in type {1}", propName, type);
345 throw new HttpException (msg);
348 Type propType = prop.PropertyType;
349 ControlBuilder builder = null;
350 if (typeof (ICollection).IsAssignableFrom (propType)) {
351 builder = new CollectionBuilder ();
352 } else if (typeof (ITemplate).IsAssignableFrom (propType)) {
353 builder = new TemplateBuilder (prop);
354 } else if (typeof (string) == propType) {
355 builder = new StringPropertyBuilder (prop.Name);
357 builder = CreateBuilderFromType (parser, parentBuilder, propType, prop.Name,
358 null, atts, line, fileName);
359 builder.isProperty = true;
363 builder.Init (parser, this, null, prop.Name, null, atts);
364 builder.fileName = fileName;
366 builder.isProperty = true;
370 public virtual void Init (TemplateParser parser,
371 ControlBuilder parentBuilder,
377 this.parser = parser;
379 this.location = parser.Location;
381 this.parentBuilder = parentBuilder;
383 this.tagName = tagName;
385 this.attribs = attribs;
389 if (this is TemplateBuilder)
392 object [] atts = type.GetCustomAttributes (typeof (ParseChildrenAttribute), true);
394 if (!typeof (IParserAccessor).IsAssignableFrom (type) && atts.Length == 0) {
395 isIParserAccessor = false;
396 childrenAsProperties = true;
397 } else if (atts.Length > 0) {
398 ParseChildrenAttribute att = (ParseChildrenAttribute) atts [0];
399 childrenAsProperties = att.ChildrenAsProperties;
400 if (childrenAsProperties && att.DefaultProperty != "") {
401 defaultPropertyBuilder = CreatePropertyBuilder (att.DefaultProperty,
407 public virtual bool NeedsTagInnerText ()
412 public virtual void OnAppendToParentBuilder (ControlBuilder parentBuilder)
414 if (defaultPropertyBuilder == null)
417 ControlBuilder old = defaultPropertyBuilder;
418 defaultPropertyBuilder = null;
419 AppendSubBuilder (old);
422 internal void SetTagName (string name)
427 public virtual void SetTagInnerText (string text)
431 internal string GetNextID (string proposedID)
433 if (proposedID != null && proposedID.Trim () != "")
436 return "_bctrl_" + nextID++;
439 internal virtual ControlBuilder CreateSubBuilder (string tagid,
442 TemplateParser parser,
445 ControlBuilder childBuilder = null;
446 if (childrenAsProperties) {
447 if (defaultPropertyBuilder == null) {
448 childBuilder = CreatePropertyBuilder (tagid, parser, atts);
450 childBuilder = defaultPropertyBuilder.CreateSubBuilder (tagid, atts,
451 null, parser, location);
456 childType = GetChildControlType (tagid, atts);
457 if (childType == null)
460 childBuilder = CreateBuilderFromType (parser, this, childType, tagid, id, atts,
461 location.BeginLine, location.Filename);
466 internal virtual object CreateInstance ()
468 // HtmlGenericControl, HtmlTableCell...
469 object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
470 object [] args = null;
471 if (atts != null && atts.Length > 0) {
472 ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
474 args = new object [] {tagName};
477 return Activator.CreateInstance (type, args);
480 internal virtual void CreateChildren (object parent)
482 if (children == null || children.Count == 0)
485 IParserAccessor parser = parent as IParserAccessor;
489 foreach (object o in children) {
491 parser.AddParsedSubObject (new LiteralControl ((string) o));
493 parser.AddParsedSubObject (((ControlBuilder) o).CreateInstance ());
498 [MonoTODO ("unsure, lack documentation")]
499 public virtual object BuildObject ()
501 return CreateInstance ();
504 internal void ResetState()
507 haveParserVariable = false;
509 if (Children != null) {
510 foreach (object child in Children) {
511 ControlBuilder cb = child as ControlBuilder;