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;
155 protected TemplateParser Parser {
156 get { return parser; }
159 public string TagName {
160 get { return tagName; }
163 internal RootBuilder Root {
165 if (GetType () == typeof (RootBuilder))
166 return (RootBuilder) this;
168 return (RootBuilder) parentBuilder.Root;
172 internal bool ChildrenAsProperties {
173 get { return childrenAsProperties; }
176 public virtual bool AllowWhitespaceLiterals ()
181 public virtual void AppendLiteralString (string s)
183 if (s == null || s == "")
186 if (childrenAsProperties || !isIParserAccessor) {
187 if (defaultPropertyBuilder != null) {
188 defaultPropertyBuilder.AppendLiteralString (s);
189 } else if (s.Trim () != "") {
190 throw new HttpException ("Literal content not allowed for " + tagName + " " +
191 GetType () + " \"" + s + "\"");
197 if (!AllowWhitespaceLiterals () && s.Trim () == "")
200 if (HtmlDecodeLiterals ())
201 s = HttpUtility.HtmlDecode (s);
203 if (children == null)
204 children = new ArrayList ();
209 public virtual void AppendSubBuilder (ControlBuilder subBuilder)
211 subBuilder.OnAppendToParentBuilder (this);
213 subBuilder.parentBuilder = this;
214 if (childrenAsProperties) {
215 AppendToProperty (subBuilder);
219 if (typeof (CodeRenderBuilder).IsAssignableFrom (subBuilder.GetType ())) {
220 AppendCode (subBuilder);
224 if (children == null)
225 children = new ArrayList ();
227 children.Add (subBuilder);
230 void AppendToProperty (ControlBuilder subBuilder)
232 if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
233 throw new HttpException ("Code render not supported here.");
235 if (defaultPropertyBuilder != null) {
236 defaultPropertyBuilder.AppendSubBuilder (subBuilder);
240 if (children == null)
241 children = new ArrayList ();
243 children.Add (subBuilder);
246 void AppendCode (ControlBuilder subBuilder)
248 if (type != null && !(typeof (Control).IsAssignableFrom (type)))
249 throw new HttpException ("Code render not supported here.");
251 if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
254 if (children == null)
255 children = new ArrayList ();
257 children.Add (subBuilder);
260 public virtual void CloseControl ()
264 public static ControlBuilder CreateBuilderFromType (TemplateParser parser,
265 ControlBuilder parentBuilder,
271 string sourceFileName)
273 ControlBuilder builder;
274 object [] atts = type.GetCustomAttributes (typeof (ControlBuilderAttribute), true);
275 if (atts != null && atts.Length > 0) {
276 ControlBuilderAttribute att = (ControlBuilderAttribute) atts [0];
277 builder = (ControlBuilder) Activator.CreateInstance (att.BuilderType);
279 builder = new ControlBuilder ();
282 builder.Init (parser, parentBuilder, type, tagName, id, attribs);
284 builder.fileName = sourceFileName;
288 public virtual Type GetChildControlType (string tagName, IDictionary attribs)
293 public virtual bool HasBody ()
298 public virtual bool HtmlDecodeLiterals ()
303 ControlBuilder CreatePropertyBuilder (string propName, TemplateParser parser, IDictionary atts)
305 PropertyInfo prop = type.GetProperty (propName, flagsNoCase);
307 string msg = String.Format ("Property {0} not found in type {1}", propName, type);
308 throw new HttpException (msg);
311 Type propType = prop.PropertyType;
312 ControlBuilder builder = null;
313 if (typeof (ICollection).IsAssignableFrom (propType)) {
314 builder = new CollectionBuilder ();
315 } else if (typeof (ITemplate).IsAssignableFrom (propType)) {
316 builder = new TemplateBuilder (prop);
318 builder = CreateBuilderFromType (parser, parentBuilder, propType, prop.Name,
319 null, atts, line, fileName);
320 builder.isProperty = true;
324 builder.Init (parser, this, null, prop.Name, null, atts);
325 builder.fileName = fileName;
327 builder.isProperty = true;
331 public virtual void Init (TemplateParser parser,
332 ControlBuilder parentBuilder,
338 this.parser = parser;
340 this.location = parser.Location;
342 this.parentBuilder = parentBuilder;
344 this.tagName = tagName;
346 this.attribs = attribs;
350 if (this is TemplateBuilder)
353 object [] atts = type.GetCustomAttributes (typeof (ParseChildrenAttribute), true);
355 if (!typeof (IParserAccessor).IsAssignableFrom (type) && atts.Length == 0) {
356 isIParserAccessor = false;
357 childrenAsProperties = true;
358 } else if (atts.Length > 0) {
359 ParseChildrenAttribute att = (ParseChildrenAttribute) atts [0];
360 childrenAsProperties = att.ChildrenAsProperties;
361 if (childrenAsProperties && att.DefaultProperty != "") {
362 defaultPropertyBuilder = CreatePropertyBuilder (att.DefaultProperty,
368 public virtual bool NeedsTagInnerText ()
373 public virtual void OnAppendToParentBuilder (ControlBuilder parentBuilder)
375 if (defaultPropertyBuilder == null)
378 ControlBuilder old = defaultPropertyBuilder;
379 defaultPropertyBuilder = null;
380 AppendSubBuilder (old);
383 internal void SetTagName (string name)
388 public virtual void SetTagInnerText (string text)
392 internal string GetNextID (string proposedID)
394 if (proposedID != null && proposedID.Trim () != "")
397 return "_bctrl_" + nextID++;
400 internal virtual ControlBuilder CreateSubBuilder (string tagid,
403 TemplateParser parser,
406 ControlBuilder childBuilder = null;
407 if (childrenAsProperties) {
408 if (defaultPropertyBuilder == null) {
409 childBuilder = CreatePropertyBuilder (tagid, parser, atts);
411 childBuilder = defaultPropertyBuilder.CreateSubBuilder (tagid, atts,
412 null, parser, location);
417 childType = GetChildControlType (tagid, atts);
418 if (childType == null)
421 childBuilder = CreateBuilderFromType (parser, this, childType, tagid, id, atts,
422 location.BeginLine, location.Filename);
427 internal virtual object CreateInstance ()
429 // HtmlGenericControl, HtmlTableCell...
430 object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
431 object [] args = null;
432 if (atts != null && atts.Length > 0) {
433 ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
435 args = new object [] {tagName};
438 return Activator.CreateInstance (type, args);
441 internal virtual void CreateChildren (object parent)
443 if (children == null || children.Count == 0)
446 IParserAccessor parser = parent as IParserAccessor;
450 foreach (object o in children) {
452 parser.AddParsedSubObject (new LiteralControl ((string) o));
454 parser.AddParsedSubObject (((ControlBuilder) o).CreateInstance ());