// Authors:
// Duncan Mak (duncan@ximian.com)
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+// Marek Habersack <mhabersack@novell.com>
//
// (C) 2002, 2003 Ximian, Inc. (http://www.ximian.com)
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
using System.Collections;
using System.Configuration;
using System.CodeDom;
+using System.Globalization;
using System.Reflection;
using System.Security.Permissions;
using System.Web.Compilation;
using System.Web.Configuration;
using System.IO;
using System.Web.UI.WebControls;
+using System.Web.Util;
+
+using _Location = System.Web.Compilation.Location;
namespace System.Web.UI {
[AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
public class ControlBuilder
{
- internal static BindingFlags flagsNoCase = BindingFlags.Public |
+ internal static readonly BindingFlags FlagsNoCase = BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.IgnoreCase;
ControlBuilder myNamingContainer;
TemplateParser parser;
- internal ControlBuilder parentBuilder;
+ Type parserType;
+ ControlBuilder parentBuilder;
Type type;
string tagName;
+ string originalTagName;
string id;
- internal IDictionary attribs;
- internal int line;
- internal string fileName;
+ IDictionary attribs;
+ int line;
+ string fileName;
bool childrenAsProperties;
bool isIParserAccessor = true;
bool hasAspCode;
- internal ControlBuilder defaultPropertyBuilder;
+ ControlBuilder defaultPropertyBuilder;
ArrayList children;
+ ArrayList templateChildren;
static int nextID;
- internal bool haveParserVariable;
- internal CodeMemberMethod method;
- internal CodeStatementCollection methodStatements;
- internal CodeMemberMethod renderMethod;
- internal int renderIndex;
- internal bool isProperty;
- internal ILocation location;
+ bool haveParserVariable;
+ CodeMemberMethod method;
+ CodeStatementCollection methodStatements;
+ CodeMemberMethod renderMethod;
+ int renderIndex;
+ bool isProperty;
+ bool isPropertyWritable;
+ ILocation location;
ArrayList otherTags;
-#if NET_2_0
- static string privateBinPath;
-#endif
+
+ int localVariableCount = 0;
+ bool? isTemplate;
public ControlBuilder ()
{
{
this.parser = parser;
+ this.parserType = parser != null ? parser.GetType () : null;
this.parentBuilder = parentBuilder;
this.type = type;
this.tagName = tagName;
if (otherTags == null)
otherTags = new ArrayList ();
}
+
+ internal ControlBuilder ParentBuilder {
+ get { return parentBuilder; }
+ }
+
+ internal IDictionary Attributes {
+ get { return attribs; }
+ }
+
+ internal int Line {
+ get { return line; }
+ set { line = value; }
+ }
+
+ internal string FileName {
+ get { return fileName; }
+ set { fileName = value; }
+ }
+
+ internal ControlBuilder DefaultPropertyBuilder {
+ get { return defaultPropertyBuilder; }
+ }
+
+ internal bool HaveParserVariable {
+ get { return haveParserVariable; }
+ set { haveParserVariable = value; }
+ }
+
+ internal CodeMemberMethod Method {
+ get { return method; }
+ set { method = value; }
+ }
+
+ internal CodeMemberMethod DataBindingMethod {
+ get;
+ set;
+ }
+
+ internal CodeStatementCollection MethodStatements {
+ get { return methodStatements; }
+ set { methodStatements = value; }
+ }
+
+ internal CodeMemberMethod RenderMethod {
+ get { return renderMethod; }
+ set { renderMethod = value; }
+ }
+
+ internal int RenderIndex {
+ get { return renderIndex; }
+ }
+
+ internal bool IsProperty {
+ get { return isProperty; }
+ }
+
+ internal bool IsPropertyWritable {
+ get { return isPropertyWritable; }
+ }
+ internal ILocation Location {
+ get { return location; }
+ set { location = new _Location (value); }
+ }
+
internal ArrayList OtherTags {
get { return otherTags; }
}
get { return children; }
}
+ internal ArrayList TemplateChildren {
+ get { return templateChildren; }
+ }
+
internal void SetControlType (Type t)
{
type = t;
}
}
+ internal bool IsNamingContainer {
+ get {
+ if (type == null)
+ return false;
+
+ return typeof (INamingContainer).IsAssignableFrom (type);
+ }
+ }
+
+ internal bool IsTemplate {
+ get {
+ if (isTemplate == null)
+ isTemplate = (typeof (TemplateBuilder).IsAssignableFrom (GetType ()));
+
+ return isTemplate.Value;
+ }
+ }
+
+ internal bool PropertyBuilderShouldReturnValue {
+ get { return isProperty && isPropertyWritable && RenderMethod == null && !IsTemplate && !(this is CollectionBuilder) && !(this is RootBuilder); }
+ }
+
ControlBuilder MyNamingContainer {
get {
if (myNamingContainer == null) {
if (parentBuilder == null && controlType == null)
myNamingContainer = null;
+ else if (parentBuilder is TemplateBuilder)
+ myNamingContainer = parentBuilder;
else if (controlType != null && typeof (INamingContainer).IsAssignableFrom (controlType))
myNamingContainer = parentBuilder;
else
}
}
-#if NET_2_0
- public virtual
-#else
- internal
-#endif
- Type BindingContainerType {
+ public virtual Type BindingContainerType {
get {
- ControlBuilder cb = MyNamingContainer;
- if (cb == null)
+ ControlBuilder cb = (this is TemplateBuilder && !(this is RootBuilder)) ? this : MyNamingContainer;
+
+ if (cb == null) {
+ if (this is RootBuilder && parserType == typeof (PageParser))
+ return typeof (Page);
+
return typeof (Control);
+ }
-#if NET_2_0
- if (cb is ContentBuilderInternal)
+ if (cb != this && cb is ContentBuilderInternal && !typeof (INonBindingContainer).IsAssignableFrom (cb.BindingContainerType))
return cb.BindingContainerType;
-#endif
+ Type ct;
+ if (cb is TemplateBuilder) {
+ ct = ((TemplateBuilder) cb).ContainerType;
+ if (typeof (INonBindingContainer).IsAssignableFrom (ct))
+ return MyNamingContainer.BindingContainerType;
+
+ if (ct != null)
+ return ct;
+
+ ct = cb.ControlType;
+ if (ct == null)
+ return typeof (Control);
+
+ if (typeof (INonBindingContainer).IsAssignableFrom (ct) || !typeof (INamingContainer).IsAssignableFrom (ct))
+ return MyNamingContainer.BindingContainerType;
+
+ return ct;
+ }
+
+ ct = cb.ControlType;
+ if (ct == null)
+ return typeof (Control);
+
+ if (typeof (INonBindingContainer).IsAssignableFrom (ct) || !typeof (INamingContainer).IsAssignableFrom (ct))
+ return MyNamingContainer.BindingContainerType;
+
return cb.ControlType;
}
}
get { return tagName; }
}
+ internal string OriginalTagName {
+ get {
+ if (originalTagName == null || originalTagName.Length == 0)
+ return TagName;
+ return originalTagName;
+ }
+ }
+
internal RootBuilder Root {
get {
- if (GetType () == typeof (RootBuilder))
+ if (typeof (RootBuilder).IsAssignableFrom (GetType ()))
return (RootBuilder) this;
return (RootBuilder) parentBuilder.Root;
internal bool ChildrenAsProperties {
get { return childrenAsProperties; }
}
+
+ internal string GetAttribute (string name)
+ {
+ if (attribs == null)
+ return null;
+
+ return attribs [name] as string;
+ }
+
+ internal void IncreaseRenderIndex ()
+ {
+ renderIndex++;
+ }
+
+ void AddChild (object child)
+ {
+ if (children == null)
+ children = new ArrayList ();
+
+ children.Add (child);
+ ControlBuilder cb = child as ControlBuilder;
+ if (cb != null && cb is TemplateBuilder) {
+ if (templateChildren == null)
+ templateChildren = new ArrayList ();
+ templateChildren.Add (child);
+ }
+
+ if (parser == null)
+ return;
+
+ string tag = cb != null ? cb.TagName : null;
+ if (String.IsNullOrEmpty (tag))
+ return;
+
+ RootBuilder rb = Root;
+ AspComponentFoundry foundry = rb != null ? rb.Foundry : null;
+ if (foundry == null)
+ return;
+ AspComponent component = foundry.GetComponent (tag);
+ if (component == null || !component.FromConfig)
+ return;
+
+ parser.AddImport (component.Namespace);
+ parser.AddDependency (component.Source);
+ }
public virtual bool AllowWhitespaceLiterals ()
{
if (HtmlDecodeLiterals ())
s = HttpUtility.HtmlDecode (s);
- if (children == null)
- children = new ArrayList ();
-
- children.Add (s);
+ AddChild (s);
}
public virtual void AppendSubBuilder (ControlBuilder subBuilder)
return;
}
- if (children == null)
- children = new ArrayList ();
-
- children.Add (subBuilder);
+ AddChild (subBuilder);
}
void AppendToProperty (ControlBuilder subBuilder)
return;
}
- if (children == null)
- children = new ArrayList ();
-
- children.Add (subBuilder);
+ AddChild (subBuilder);
}
void AppendCode (ControlBuilder subBuilder)
if (typeof (CodeRenderBuilder) == subBuilder.GetType ())
hasAspCode = true;
- if (children == null)
- children = new ArrayList ();
-
- children.Add (subBuilder);
+ AddChild (subBuilder);
}
public virtual void CloseControl ()
{
}
-#if NET_2_0
static Type MapTagType (Type tagType)
{
if (tagType == null)
return tagType;
}
-#endif
public static ControlBuilder CreateBuilderFromType (TemplateParser parser,
ControlBuilder parentBuilder,
int line,
string sourceFileName)
{
-
- Type tagType;
-#if NET_2_0
- tagType = MapTagType (type);
-#else
- tagType = type;
-#endif
- ControlBuilder builder;
+ Type tagType = MapTagType (type);
+ ControlBuilder builder;
object [] atts = tagType.GetCustomAttributes (typeof (ControlBuilderAttribute), true);
if (atts != null && atts.Length > 0) {
ControlBuilderAttribute att = (ControlBuilderAttribute) atts [0];
{
return false;
}
-
+
ControlBuilder CreatePropertyBuilder (string propName, TemplateParser parser, IDictionary atts)
{
- PropertyInfo prop = type.GetProperty (propName, flagsNoCase);
+ int idx;
+ string propertyName;
+
+ if ((idx = propName.IndexOf (':')) >= 0)
+ propertyName = propName.Substring (idx + 1);
+ else
+ propertyName = propName;
+
+ PropertyInfo prop = type.GetProperty (propertyName, FlagsNoCase);
if (prop == null) {
- string msg = String.Format ("Property {0} not found in type {1}", propName, type);
+ string msg = String.Format ("Property {0} not found in type {1}", propertyName, type);
throw new HttpException (msg);
}
builder = CreateBuilderFromType (parser, parentBuilder, propType, prop.Name,
null, atts, line, fileName);
builder.isProperty = true;
+ builder.isPropertyWritable = prop.CanWrite;
+ if (idx >= 0)
+ builder.originalTagName = propName;
return builder;
}
builder.fileName = fileName;
builder.line = line;
builder.isProperty = true;
+ builder.isPropertyWritable = prop.CanWrite;
+ if (idx >= 0)
+ builder.originalTagName = propName;
return builder;
}
{
this.parser = parser;
if (parser != null)
- this.location = parser.Location;
+ this.Location = parser.Location;
this.parentBuilder = parentBuilder;
this.type = type;
return "_bctrl_" + nextID++;
}
+ internal string GetNextLocalVariableName (string baseName)
+ {
+ localVariableCount++;
+ return baseName + localVariableCount.ToString ();
+ }
+
internal virtual ControlBuilder CreateSubBuilder (string tagid,
- Hashtable atts,
+ IDictionary atts,
Type childType,
TemplateParser parser,
ILocation location)
if (defaultPropertyBuilder == null)
childBuilder = CreatePropertyBuilder (tagid, parser, atts);
else {
- if (defaultPropertyBuilder.TagName == tagid) {
+ if (String.Compare (defaultPropertyBuilder.TagName, tagid, true, Helpers.InvariantCulture) == 0) {
// The child tag is the same what our default property name. Act as if there was
// no default property builder, or otherwise we'll end up with invalid nested
// builder call.
defaultPropertyBuilder = null;
childBuilder = CreatePropertyBuilder (tagid, parser, atts);
- } else
- childBuilder = defaultPropertyBuilder.CreateSubBuilder (tagid, atts,
- null, parser,
- location);
+ } else {
+ Type ct = ControlType;
+ MemberInfo[] mems = ct != null ? ct.GetMember (tagid, MemberTypes.Property, FlagsNoCase) : null;
+ PropertyInfo prop = mems != null && mems.Length > 0 ? mems [0] as PropertyInfo : null;
+
+ if (prop != null && typeof (ITemplate).IsAssignableFrom (prop.PropertyType)) {
+ childBuilder = CreatePropertyBuilder (tagid, parser, atts);
+ defaultPropertyBuilder = null;
+ } else
+ childBuilder = defaultPropertyBuilder.CreateSubBuilder (tagid, atts, null, parser, location);
+ }
}
+
return childBuilder;
}
- if (tagName == tagid)
+ if (String.Compare (tagName, tagid, true, Helpers.InvariantCulture) == 0)
return null;
childType = GetChildControlType (tagid, atts);
}
}
}
-#if NET_2_0
+
[MonoTODO ("unsure, lack documentation")]
public virtual object BuildObject ()
{
return CreateInstance ();
}
+
+ public virtual void ProcessGeneratedCode(CodeCompileUnit codeCompileUnit,
+ CodeTypeDeclaration baseType,
+ CodeTypeDeclaration derivedType,
+ CodeMemberMethod buildMethod,
+ CodeMemberMethod dataBindingMethod)
+ {
+ // nothing to do
+ }
internal void ResetState()
{
}
}
}
-#endif
}
}