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 flushOutputStatements;
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);
355 builder = CreateBuilderFromType (parser, parentBuilder, propType, prop.Name,
356 null, atts, line, fileName);
357 builder.isProperty = true;
361 builder.Init (parser, this, null, prop.Name, null, atts);
362 builder.fileName = fileName;
364 builder.isProperty = true;
368 public virtual void Init (TemplateParser parser,
369 ControlBuilder parentBuilder,
375 this.parser = parser;
377 this.location = parser.Location;
379 this.parentBuilder = parentBuilder;
381 this.tagName = tagName;
383 this.attribs = attribs;
387 if (this is TemplateBuilder)
390 object [] atts = type.GetCustomAttributes (typeof (ParseChildrenAttribute), true);
392 if (!typeof (IParserAccessor).IsAssignableFrom (type) && atts.Length == 0) {
393 isIParserAccessor = false;
394 childrenAsProperties = true;
395 } else if (atts.Length > 0) {
396 ParseChildrenAttribute att = (ParseChildrenAttribute) atts [0];
397 childrenAsProperties = att.ChildrenAsProperties;
398 if (childrenAsProperties && att.DefaultProperty != "") {
399 defaultPropertyBuilder = CreatePropertyBuilder (att.DefaultProperty,
405 public virtual bool NeedsTagInnerText ()
410 public virtual void OnAppendToParentBuilder (ControlBuilder parentBuilder)
412 if (defaultPropertyBuilder == null)
415 ControlBuilder old = defaultPropertyBuilder;
416 defaultPropertyBuilder = null;
417 AppendSubBuilder (old);
420 internal void SetTagName (string name)
425 public virtual void SetTagInnerText (string text)
429 internal string GetNextID (string proposedID)
431 if (proposedID != null && proposedID.Trim () != "")
434 return "_bctrl_" + nextID++;
437 internal virtual ControlBuilder CreateSubBuilder (string tagid,
440 TemplateParser parser,
443 ControlBuilder childBuilder = null;
444 if (childrenAsProperties) {
445 if (defaultPropertyBuilder == null) {
446 childBuilder = CreatePropertyBuilder (tagid, parser, atts);
448 childBuilder = defaultPropertyBuilder.CreateSubBuilder (tagid, atts,
449 null, parser, location);
454 childType = GetChildControlType (tagid, atts);
455 if (childType == null)
458 childBuilder = CreateBuilderFromType (parser, this, childType, tagid, id, atts,
459 location.BeginLine, location.Filename);
464 internal virtual object CreateInstance ()
466 // HtmlGenericControl, HtmlTableCell...
467 object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
468 object [] args = null;
469 if (atts != null && atts.Length > 0) {
470 ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
472 args = new object [] {tagName};
475 return Activator.CreateInstance (type, args);
478 internal virtual void CreateChildren (object parent)
480 if (children == null || children.Count == 0)
483 IParserAccessor parser = parent as IParserAccessor;
487 foreach (object o in children) {
489 parser.AddParsedSubObject (new LiteralControl ((string) o));
491 parser.AddParsedSubObject (((ControlBuilder) o).CreateInstance ());
496 [MonoTODO ("unsure, lack documentation")]
497 public virtual object BuildObject ()
499 return CreateInstance ();
502 internal void ResetState()
504 haveParserVariable = false;
506 if (Children != null) {
507 foreach (object child in Children) {
508 ControlBuilder cb = child as ControlBuilder;