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 CodeMemberMethod renderMethod;
67 internal int renderIndex;
68 internal bool isProperty;
69 internal ILocation location;
72 public ControlBuilder ()
76 internal ControlBuilder (TemplateParser parser,
77 ControlBuilder parentBuilder,
83 string sourceFileName)
87 this.parentBuilder = parentBuilder;
89 this.tagName = tagName;
91 this.attribs = attribs;
93 this.fileName = sourceFileName;
96 internal void EnsureOtherTags ()
98 if (otherTags == null)
99 otherTags = new ArrayList ();
102 internal ArrayList OtherTags {
103 get { return otherTags; }
106 public Type ControlType {
110 protected bool FChildrenAsProperties {
111 get { return childrenAsProperties; }
114 protected bool FIsNonParserAccessor {
115 get { return !isIParserAccessor; }
118 public bool HasAspCode {
119 get { return hasAspCode; }
127 internal ArrayList Children {
128 get { return children; }
131 internal void SetControlType (Type t)
136 protected bool InDesigner {
137 get { return false; }
140 public Type NamingContainerType {
142 if (parentBuilder == null)
143 return typeof (Control);
145 Type ptype = parentBuilder.ControlType;
147 return parentBuilder.NamingContainerType;
149 if (!typeof (INamingContainer).IsAssignableFrom (ptype))
150 return parentBuilder.NamingContainerType;
161 Type BindingContainerType {
163 if (parentBuilder == null)
164 return typeof (Control);
166 if (parentBuilder is TemplateBuilder && ((TemplateBuilder)parentBuilder).ContainerType != null)
167 return ((TemplateBuilder)parentBuilder).ContainerType;
169 Type ptype = parentBuilder.ControlType;
171 return parentBuilder.BindingContainerType;
173 if (!typeof (INamingContainer).IsAssignableFrom (ptype))
174 return parentBuilder.BindingContainerType;
180 internal TemplateBuilder ParentTemplateBuilder {
182 if (parentBuilder == null)
184 else if (parentBuilder is TemplateBuilder)
185 return (TemplateBuilder) parentBuilder;
187 return parentBuilder.ParentTemplateBuilder;
191 protected TemplateParser Parser {
192 get { return parser; }
195 public string TagName {
196 get { return tagName; }
199 internal RootBuilder Root {
201 if (GetType () == typeof (RootBuilder))
202 return (RootBuilder) this;
204 return (RootBuilder) parentBuilder.Root;
208 internal bool ChildrenAsProperties {
209 get { return childrenAsProperties; }
212 public virtual bool AllowWhitespaceLiterals ()
217 public virtual void AppendLiteralString (string s)
219 if (s == null || s == "")
222 if (childrenAsProperties || !isIParserAccessor) {
223 if (defaultPropertyBuilder != null) {
224 defaultPropertyBuilder.AppendLiteralString (s);
225 } else if (s.Trim () != "") {
226 throw new HttpException ("Literal content not allowed for " + tagName + " " +
227 GetType () + " \"" + s + "\"");
233 if (!AllowWhitespaceLiterals () && s.Trim () == "")
236 if (HtmlDecodeLiterals ())
237 s = HttpUtility.HtmlDecode (s);
239 if (children == null)
240 children = new ArrayList ();
245 public virtual void AppendSubBuilder (ControlBuilder subBuilder)
247 subBuilder.OnAppendToParentBuilder (this);
249 subBuilder.parentBuilder = this;
250 if (childrenAsProperties) {
251 AppendToProperty (subBuilder);
255 if (typeof (CodeRenderBuilder).IsAssignableFrom (subBuilder.GetType ())) {
256 AppendCode (subBuilder);
260 if (children == null)
261 children = new ArrayList ();
263 children.Add (subBuilder);
266 void AppendToProperty (ControlBuilder subBuilder)
268 if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
269 throw new HttpException ("Code render not supported here.");
271 if (defaultPropertyBuilder != null) {
272 defaultPropertyBuilder.AppendSubBuilder (subBuilder);
276 if (children == null)
277 children = new ArrayList ();
279 children.Add (subBuilder);
282 void AppendCode (ControlBuilder subBuilder)
284 if (type != null && !(typeof (Control).IsAssignableFrom (type)))
285 throw new HttpException ("Code render not supported here.");
287 if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
290 if (children == null)
291 children = new ArrayList ();
293 children.Add (subBuilder);
296 public virtual void CloseControl ()
300 public static ControlBuilder CreateBuilderFromType (TemplateParser parser,
301 ControlBuilder parentBuilder,
307 string sourceFileName)
309 ControlBuilder builder;
310 object [] atts = type.GetCustomAttributes (typeof (ControlBuilderAttribute), true);
311 if (atts != null && atts.Length > 0) {
312 ControlBuilderAttribute att = (ControlBuilderAttribute) atts [0];
313 builder = (ControlBuilder) Activator.CreateInstance (att.BuilderType);
315 builder = new ControlBuilder ();
318 builder.Init (parser, parentBuilder, type, tagName, id, attribs);
320 builder.fileName = sourceFileName;
324 public virtual Type GetChildControlType (string tagName, IDictionary attribs)
329 public virtual bool HasBody ()
334 public virtual bool HtmlDecodeLiterals ()
339 ControlBuilder CreatePropertyBuilder (string propName, TemplateParser parser, IDictionary atts)
341 PropertyInfo prop = type.GetProperty (propName, flagsNoCase);
343 string msg = String.Format ("Property {0} not found in type {1}", propName, type);
344 throw new HttpException (msg);
347 Type propType = prop.PropertyType;
348 ControlBuilder builder = null;
349 if (typeof (ICollection).IsAssignableFrom (propType)) {
350 builder = new CollectionBuilder ();
351 } else if (typeof (ITemplate).IsAssignableFrom (propType)) {
352 builder = new TemplateBuilder (prop);
354 builder = CreateBuilderFromType (parser, parentBuilder, propType, prop.Name,
355 null, atts, line, fileName);
356 builder.isProperty = true;
360 builder.Init (parser, this, null, prop.Name, null, atts);
361 builder.fileName = fileName;
363 builder.isProperty = true;
367 public virtual void Init (TemplateParser parser,
368 ControlBuilder parentBuilder,
374 this.parser = parser;
376 this.location = parser.Location;
378 this.parentBuilder = parentBuilder;
380 this.tagName = tagName;
382 this.attribs = attribs;
386 if (this is TemplateBuilder)
389 object [] atts = type.GetCustomAttributes (typeof (ParseChildrenAttribute), true);
391 if (!typeof (IParserAccessor).IsAssignableFrom (type) && atts.Length == 0) {
392 isIParserAccessor = false;
393 childrenAsProperties = true;
394 } else if (atts.Length > 0) {
395 ParseChildrenAttribute att = (ParseChildrenAttribute) atts [0];
396 childrenAsProperties = att.ChildrenAsProperties;
397 if (childrenAsProperties && att.DefaultProperty != "") {
398 defaultPropertyBuilder = CreatePropertyBuilder (att.DefaultProperty,
404 public virtual bool NeedsTagInnerText ()
409 public virtual void OnAppendToParentBuilder (ControlBuilder parentBuilder)
411 if (defaultPropertyBuilder == null)
414 ControlBuilder old = defaultPropertyBuilder;
415 defaultPropertyBuilder = null;
416 AppendSubBuilder (old);
419 internal void SetTagName (string name)
424 public virtual void SetTagInnerText (string text)
428 internal string GetNextID (string proposedID)
430 if (proposedID != null && proposedID.Trim () != "")
433 return "_bctrl_" + nextID++;
436 internal virtual ControlBuilder CreateSubBuilder (string tagid,
439 TemplateParser parser,
442 ControlBuilder childBuilder = null;
443 if (childrenAsProperties) {
444 if (defaultPropertyBuilder == null) {
445 childBuilder = CreatePropertyBuilder (tagid, parser, atts);
447 childBuilder = defaultPropertyBuilder.CreateSubBuilder (tagid, atts,
448 null, parser, location);
453 childType = GetChildControlType (tagid, atts);
454 if (childType == null)
457 childBuilder = CreateBuilderFromType (parser, this, childType, tagid, id, atts,
458 location.BeginLine, location.Filename);
463 internal virtual object CreateInstance ()
465 // HtmlGenericControl, HtmlTableCell...
466 object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
467 object [] args = null;
468 if (atts != null && atts.Length > 0) {
469 ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
471 args = new object [] {tagName};
474 return Activator.CreateInstance (type, args);
477 internal virtual void CreateChildren (object parent)
479 if (children == null || children.Count == 0)
482 IParserAccessor parser = parent as IParserAccessor;
486 foreach (object o in children) {
488 parser.AddParsedSubObject (new LiteralControl ((string) o));
490 parser.AddParsedSubObject (((ControlBuilder) o).CreateInstance ());
495 [MonoTODO ("unsure, lack documentation")]
496 public virtual object BuildObject ()
498 return CreateInstance ();
501 internal void ResetState()
503 haveParserVariable = false;
505 if (Children != null) {
506 foreach (object child in Children) {
507 ControlBuilder cb = child as ControlBuilder;