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;
71 public ControlBuilder ()
75 internal ControlBuilder (TemplateParser parser,
76 ControlBuilder parentBuilder,
82 string sourceFileName)
86 this.parentBuilder = parentBuilder;
88 this.tagName = tagName;
90 this.attribs = attribs;
92 this.fileName = sourceFileName;
95 internal void EnsureOtherTags ()
97 if (otherTags == null)
98 otherTags = new ArrayList ();
101 internal ArrayList OtherTags {
102 get { return otherTags; }
105 public Type ControlType {
109 protected bool FChildrenAsProperties {
110 get { return childrenAsProperties; }
113 protected bool FIsNonParserAccessor {
114 get { return !isIParserAccessor; }
117 public bool HasAspCode {
118 get { return hasAspCode; }
126 internal ArrayList Children {
127 get { return children; }
130 internal void SetControlType (Type t)
135 protected bool InDesigner {
136 get { return false; }
139 public Type NamingContainerType {
141 if (parentBuilder == null)
142 return typeof (Control);
144 Type ptype = parentBuilder.ControlType;
146 return parentBuilder.NamingContainerType;
148 if (!typeof (INamingContainer).IsAssignableFrom (ptype))
149 return parentBuilder.NamingContainerType;
160 Type BindingContainerType {
162 if (parentBuilder == null)
163 return typeof (Control);
165 if (parentBuilder is TemplateBuilder && ((TemplateBuilder)parentBuilder).ContainerType != null)
166 return ((TemplateBuilder)parentBuilder).ContainerType;
168 Type ptype = parentBuilder.ControlType;
170 return parentBuilder.BindingContainerType;
172 if (!typeof (INamingContainer).IsAssignableFrom (ptype))
173 return parentBuilder.BindingContainerType;
179 internal TemplateBuilder ParentTemplateBuilder {
181 if (parentBuilder == null)
183 else if (parentBuilder is TemplateBuilder)
184 return (TemplateBuilder) parentBuilder;
186 return parentBuilder.ParentTemplateBuilder;
190 protected TemplateParser Parser {
191 get { return parser; }
194 public string TagName {
195 get { return tagName; }
198 internal RootBuilder Root {
200 if (GetType () == typeof (RootBuilder))
201 return (RootBuilder) this;
203 return (RootBuilder) parentBuilder.Root;
207 internal bool ChildrenAsProperties {
208 get { return childrenAsProperties; }
211 public virtual bool AllowWhitespaceLiterals ()
216 public virtual void AppendLiteralString (string s)
218 if (s == null || s == "")
221 if (childrenAsProperties || !isIParserAccessor) {
222 if (defaultPropertyBuilder != null) {
223 defaultPropertyBuilder.AppendLiteralString (s);
224 } else if (s.Trim () != "") {
225 throw new HttpException ("Literal content not allowed for " + tagName + " " +
226 GetType () + " \"" + s + "\"");
232 if (!AllowWhitespaceLiterals () && s.Trim () == "")
235 if (HtmlDecodeLiterals ())
236 s = HttpUtility.HtmlDecode (s);
238 if (children == null)
239 children = new ArrayList ();
244 public virtual void AppendSubBuilder (ControlBuilder subBuilder)
246 subBuilder.OnAppendToParentBuilder (this);
248 subBuilder.parentBuilder = this;
249 if (childrenAsProperties) {
250 AppendToProperty (subBuilder);
254 if (typeof (CodeRenderBuilder).IsAssignableFrom (subBuilder.GetType ())) {
255 AppendCode (subBuilder);
259 if (children == null)
260 children = new ArrayList ();
262 children.Add (subBuilder);
265 void AppendToProperty (ControlBuilder subBuilder)
267 if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
268 throw new HttpException ("Code render not supported here.");
270 if (defaultPropertyBuilder != null) {
271 defaultPropertyBuilder.AppendSubBuilder (subBuilder);
275 if (children == null)
276 children = new ArrayList ();
278 children.Add (subBuilder);
281 void AppendCode (ControlBuilder subBuilder)
283 if (type != null && !(typeof (Control).IsAssignableFrom (type)))
284 throw new HttpException ("Code render not supported here.");
286 if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
289 if (children == null)
290 children = new ArrayList ();
292 children.Add (subBuilder);
295 public virtual void CloseControl ()
299 public static ControlBuilder CreateBuilderFromType (TemplateParser parser,
300 ControlBuilder parentBuilder,
306 string sourceFileName)
308 ControlBuilder builder;
309 object [] atts = type.GetCustomAttributes (typeof (ControlBuilderAttribute), true);
310 if (atts != null && atts.Length > 0) {
311 ControlBuilderAttribute att = (ControlBuilderAttribute) atts [0];
312 builder = (ControlBuilder) Activator.CreateInstance (att.BuilderType);
314 builder = new ControlBuilder ();
317 builder.Init (parser, parentBuilder, type, tagName, id, attribs);
319 builder.fileName = sourceFileName;
323 public virtual Type GetChildControlType (string tagName, IDictionary attribs)
328 public virtual bool HasBody ()
333 public virtual bool HtmlDecodeLiterals ()
338 ControlBuilder CreatePropertyBuilder (string propName, TemplateParser parser, IDictionary atts)
340 PropertyInfo prop = type.GetProperty (propName, flagsNoCase);
342 string msg = String.Format ("Property {0} not found in type {1}", propName, type);
343 throw new HttpException (msg);
346 Type propType = prop.PropertyType;
347 ControlBuilder builder = null;
348 if (typeof (ICollection).IsAssignableFrom (propType)) {
349 builder = new CollectionBuilder ();
350 } else if (typeof (ITemplate).IsAssignableFrom (propType)) {
351 builder = new TemplateBuilder (prop);
353 builder = CreateBuilderFromType (parser, parentBuilder, propType, prop.Name,
354 null, atts, line, fileName);
355 builder.isProperty = true;
359 builder.Init (parser, this, null, prop.Name, null, atts);
360 builder.fileName = fileName;
362 builder.isProperty = true;
366 public virtual void Init (TemplateParser parser,
367 ControlBuilder parentBuilder,
373 this.parser = parser;
375 this.location = parser.Location;
377 this.parentBuilder = parentBuilder;
379 this.tagName = tagName;
381 this.attribs = attribs;
385 if (this is TemplateBuilder)
388 object [] atts = type.GetCustomAttributes (typeof (ParseChildrenAttribute), true);
390 if (!typeof (IParserAccessor).IsAssignableFrom (type) && atts.Length == 0) {
391 isIParserAccessor = false;
392 childrenAsProperties = true;
393 } else if (atts.Length > 0) {
394 ParseChildrenAttribute att = (ParseChildrenAttribute) atts [0];
395 childrenAsProperties = att.ChildrenAsProperties;
396 if (childrenAsProperties && att.DefaultProperty != "") {
397 defaultPropertyBuilder = CreatePropertyBuilder (att.DefaultProperty,
403 public virtual bool NeedsTagInnerText ()
408 public virtual void OnAppendToParentBuilder (ControlBuilder parentBuilder)
410 if (defaultPropertyBuilder == null)
413 ControlBuilder old = defaultPropertyBuilder;
414 defaultPropertyBuilder = null;
415 AppendSubBuilder (old);
418 internal void SetTagName (string name)
423 public virtual void SetTagInnerText (string text)
427 internal string GetNextID (string proposedID)
429 if (proposedID != null && proposedID.Trim () != "")
432 return "_bctrl_" + nextID++;
435 internal virtual ControlBuilder CreateSubBuilder (string tagid,
438 TemplateParser parser,
441 ControlBuilder childBuilder = null;
442 if (childrenAsProperties) {
443 if (defaultPropertyBuilder == null) {
444 childBuilder = CreatePropertyBuilder (tagid, parser, atts);
446 childBuilder = defaultPropertyBuilder.CreateSubBuilder (tagid, atts,
447 null, parser, location);
452 childType = GetChildControlType (tagid, atts);
453 if (childType == null)
456 childBuilder = CreateBuilderFromType (parser, this, childType, tagid, id, atts,
457 location.BeginLine, location.Filename);
462 internal virtual object CreateInstance ()
464 // HtmlGenericControl, HtmlTableCell...
465 object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
466 object [] args = null;
467 if (atts != null && atts.Length > 0) {
468 ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
470 args = new object [] {tagName};
473 return Activator.CreateInstance (type, args);
476 internal virtual void CreateChildren (object parent)
478 if (children == null || children.Count == 0)
481 IParserAccessor parser = parent as IParserAccessor;
485 foreach (object o in children) {
487 parser.AddParsedSubObject (new LiteralControl ((string) o));
489 parser.AddParsedSubObject (((ControlBuilder) o).CreateInstance ());