[asp.net] Fix for bug #685267. ClientScriptManager generates correct post-back event...
[mono.git] / mcs / class / System.Web / System.Web.UI / TemplateControl.cs
index 5ac14eaea357ce4a7bc2ab83f68ad92052ffc6e5..6480b008bd983488f7a684fb58121c89be6db3d4 100644 (file)
@@ -7,7 +7,7 @@
 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
 //
 // (C) 2002 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
@@ -33,33 +33,34 @@ using System.Collections;
 using System.ComponentModel;
 using System.Reflection;
 using System.Security.Permissions;
+using System.Threading;
 using System.Web.Compilation;
 using System.Web.Util;
 using System.Xml;
-
-namespace System.Web.UI {
-
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Collections.Generic;
+using System.Collections.Concurrent;
+
+namespace System.Web.UI
+{
        // CAS
        [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
        [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
-#if NET_2_0
-       public abstract class TemplateControl : Control, INamingContainer, IFilterResolutionService {
-#else
-       public abstract class TemplateControl : Control, INamingContainer {
-#endif
+       public abstract class TemplateControl : Control, INamingContainer, IFilterResolutionService
+       {
                static readonly Assembly _System_Web_Assembly = typeof (TemplateControl).Assembly;
                static object abortTransaction = new object ();
                static object commitTransaction = new object ();
                static object error = new object ();
                static string [] methodNames = { "Page_Init",
-#if NET_2_0
                                                 "Page_PreInit",
                                                 "Page_PreLoad",
                                                 "Page_LoadComplete",
                                                 "Page_PreRenderComplete",
                                                 "Page_SaveStateComplete",
                                                 "Page_InitComplete",
-#endif
                                                 "Page_Load",
                                                 "Page_DataBind",
                                                 "Page_PreRender",
@@ -73,13 +74,13 @@ namespace System.Web.UI {
                                            BindingFlags.NonPublic |
                                            BindingFlags.Instance;
 
-#if NET_2_0
                string _appRelativeVirtualPath;
-#endif
+               StringResourceData resource_data;
                
                #region Constructor
                protected TemplateControl ()
                {
+                       TemplateControl = this;
                        Construct ();
                }
 
@@ -87,9 +88,7 @@ namespace System.Web.UI {
 
                #region Properties
                [EditorBrowsable (EditorBrowsableState.Never)]
-#if NET_2_0
                [Obsolete]
-#endif
                protected virtual int AutoHandlers {
                        get { return 0; }
                        set { }
@@ -100,12 +99,10 @@ namespace System.Web.UI {
                        get { return true; }
                }
 
-#if NET_2_0
                public string AppRelativeVirtualPath {
                        get { return _appRelativeVirtualPath; }
                        set { _appRelativeVirtualPath = value; }
                }
-#endif
 
                #endregion
 
@@ -115,19 +112,49 @@ namespace System.Web.UI {
                {
                }
 
-               [MonoTODO ("Not implemented")]
-               protected LiteralControl CreateResourceBasedLiteralControl (int offset,
-                                                                                   int size,
-                                                                                   bool fAsciiOnly)
+               protected LiteralControl CreateResourceBasedLiteralControl (int offset, int size, bool fAsciiOnly)
                {
-                       return null;
+                       if (resource_data == null)
+                               return null;
+
+                       if (offset > resource_data.MaxOffset - size)
+                               throw new ArgumentOutOfRangeException ("size");
+
+                       IntPtr ptr = AddOffset (resource_data.Ptr, offset);
+                       return new ResourceBasedLiteralControl (ptr, size);
                }
 
+               class EvtInfo {
+                       public MethodInfo method;
+                       public string methodName;
+                       public EventInfo evt;
+                       public bool noParams;
+               }
+
+               static SplitOrderedList<Type, ArrayList> auto_event_info = new SplitOrderedList<Type, ArrayList> (EqualityComparer<Type>.Default);
+
                internal void WireupAutomaticEvents ()
                {
                        if (!SupportAutoEvents || !AutoEventWireup)
                                return;
 
+                       /* Avoid expensive reflection operations by computing the event info only once */
+                       Type type = GetType ();
+                       ArrayList events = auto_event_info.InsertOrGet ((uint)type.GetHashCode (), type, null, CollectAutomaticEventInfo);
+
+                       for (int i = 0; i < events.Count; ++i) {
+                               EvtInfo evinfo = (EvtInfo)events [i];
+                               if (evinfo.noParams) {
+                                       NoParamsInvoker npi = new NoParamsInvoker (this, evinfo.method);
+                                       evinfo.evt.AddEventHandler (this, npi.FakeDelegate);
+                               } else
+                                       evinfo.evt.AddEventHandler (this, Delegate.CreateDelegate (typeof (EventHandler), this, evinfo.method));
+                       }
+               }
+
+               ArrayList CollectAutomaticEventInfo () {
+                       ArrayList events = new ArrayList ();
+
                        foreach (string methodName in methodNames) {
                                MethodInfo method = null;
                                Type type;
@@ -156,7 +183,7 @@ namespace System.Web.UI {
                                    parms [1].ParameterType != typeof (EventArgs)))
                                    continue;
 
-                               int pos = methodName.IndexOf ("_");
+                               int pos = methodName.IndexOf ('_');
                                string eventName = methodName.Substring (pos + 1);
                                EventInfo evt = type.GetEvent (eventName);
                                if (evt == null) {
@@ -164,18 +191,16 @@ namespace System.Web.UI {
                                        continue;
                                }
 
-                               if (noParams) {
-                                       NoParamsInvoker npi = new NoParamsInvoker (this, method);
-                                       evt.AddEventHandler (this, npi.FakeDelegate);
-                               } else {
-                                       evt.AddEventHandler (this, Delegate.CreateDelegate (
-#if NET_2_0
-                                                       typeof (EventHandler), this, method));
-#else
-                                                       typeof (EventHandler), this, methodName));
-#endif
-                               }
+                               EvtInfo evinfo = new EvtInfo ();
+                               evinfo.method = method;
+                               evinfo.methodName = methodName;
+                               evinfo.evt = evt;
+                               evinfo.noParams = noParams;
+
+                               events.Add (evinfo);
                        }
+
+                       return events;
                }
 
                [EditorBrowsable (EditorBrowsableState.Never)]
@@ -189,26 +214,24 @@ namespace System.Web.UI {
                                throw new ArgumentNullException ("virtualPath");
 
                        string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
-                       string realpath = Context.Request.MapPath (vpath);
-                       return UserControlParser.GetCompiledType (vpath, realpath, Context);
+                       return BuildManager.GetCompiledType (vpath);
                }
 
                public Control LoadControl (string virtualPath)
                {
-#if NET_2_0
                        if (virtualPath == null)
                                throw new ArgumentNullException ("virtualPath");
-#else
-                       if (virtualPath == null)
-                               throw new HttpException ("virtualPath is null");
-#endif
                        Type type = GetTypeFromControlPath (virtualPath);
+                       
                        return LoadControl (type, null);
                }
 
                public Control LoadControl (Type type, object[] parameters) 
                {
-                       object [] attrs = type.GetCustomAttributes (typeof (PartialCachingAttribute), true);
+                       object [] attrs = null;
+
+                       if (type != null)
+                               type.GetCustomAttributes (typeof (PartialCachingAttribute), true);
                        if (attrs != null && attrs.Length == 1) {
                                PartialCachingAttribute attr = (PartialCachingAttribute) attrs [0];
                                PartialCachingControl ctrl = new PartialCachingControl (type, parameters);
@@ -227,13 +250,8 @@ namespace System.Web.UI {
 
                public ITemplate LoadTemplate (string virtualPath)
                {
-#if NET_2_0
                        if (virtualPath == null)
                                throw new ArgumentNullException ("virtualPath");
-#else
-                       if (virtualPath == null)
-                               throw new HttpException ("virtualPath is null");
-#endif
                        Type t = GetTypeFromControlPath (virtualPath);
                        return new SimpleTemplate (t);
                }
@@ -259,26 +277,58 @@ namespace System.Web.UI {
                                eh (this, e);
                }
 
-               [MonoTODO ("Not implemented, always returns null")]
                public Control ParseControl (string content)
                {
                        if (content == null)
                                throw new ArgumentNullException ("content");
 
-                       return null;
+                       // FIXME: This method needs to be rewritten in some sane way - the way it is now,
+                       // is a kludge. New version should not use
+                       // UserControlParser.GetCompiledType, but instead resort to some other way
+                       // of creating the content (template instantiation? BuildManager? TBD)
+                       TextReader reader = new StringReader (content);
+                       Type control = UserControlParser.GetCompiledType (reader, content.GetHashCode (), HttpContext.Current);
+                       if (control == null)
+                               return null;
+
+                       TemplateControl parsedControl = Activator.CreateInstance (control, null) as TemplateControl;
+                       if (parsedControl == null)
+                               return null;
+
+                       if (this is System.Web.UI.Page)
+                               parsedControl.Page = (System.Web.UI.Page) this;
+                       parsedControl.FrameworkInitialize ();
+                       
+                       Control ret = new Control ();
+                       int count = parsedControl.Controls.Count;
+                       Control[] parsedControlControls = new Control [count];
+                       parsedControl.Controls.CopyTo (parsedControlControls, 0);
+
+                       for (int i = 0; i < count; i++)
+                               ret.Controls.Add (parsedControlControls [i]);
+
+                       parsedControl = null;
+                       return ret;
                }
 
+               [MonoTODO ("Parser filters not implemented yet. Calls ParseControl (string) for now.")]
+               public Control ParseControl (string content, bool ignoreParserFilter)
+               {
+                       return ParseControl (content);
+               }
+       
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public 
-#if !NET_2_0
-               static
-#endif
-               object ReadStringResource ()
+               public object ReadStringResource ()
                {
-                       throw new NotSupportedException ();
+                       return ReadStringResource (GetType ());
+               }
+
+               class StringResourceData {
+                       public IntPtr Ptr;
+                       public int Length;
+                       public int MaxOffset;
                }
 
-#if NET_2_0
                protected object GetGlobalResourceObject (string className, string resourceKey)
                {
                        return HttpContext.GetGlobalResourceObject (className, resourceKey);
@@ -322,26 +372,76 @@ namespace System.Web.UI {
                        
                        return converter.ConvertFrom (localObject);
                }
-#endif
+
+               internal override TemplateControl TemplateControlInternal {
+                       get { return this; }
+               }
                
                [EditorBrowsable (EditorBrowsableState.Never)]
                public static object ReadStringResource (Type t)
                {
-                       throw new NotSupportedException ();
+                       StringResourceData data = new StringResourceData ();
+                       if (ICalls.GetUnmanagedResourcesPtr (t.Assembly, out data.Ptr, out data.Length))
+                               return data;
+
+                       throw new HttpException ("Unable to load the string resources.");
                }
 
-               [MonoTODO ("Not implemented, does nothing")]
                [EditorBrowsable (EditorBrowsableState.Never)]
                protected void SetStringResourcePointer (object stringResourcePointer,
                                                         int maxResourceOffset)
                {
+                       StringResourceData rd = stringResourcePointer as StringResourceData;
+                       if (rd == null)
+                               return;
+
+                       if (maxResourceOffset < 0 || maxResourceOffset > rd.Length)
+                               throw new ArgumentOutOfRangeException ("maxResourceOffset");
+
+                       resource_data = new StringResourceData ();
+                       resource_data.Ptr = rd.Ptr;
+                       resource_data.Length = rd.Length;
+                       resource_data.MaxOffset = maxResourceOffset > 0 ? Math.Min (maxResourceOffset, rd.Length) : rd.Length;
+               }
+
+               static IntPtr AddOffset (IntPtr ptr, int offset)
+               {
+                       if (offset == 0)
+                               return ptr;
+
+                       if (IntPtr.Size == 4) {
+                               int p = ptr.ToInt32 () + offset;
+                               ptr = new IntPtr (p);
+                       } else {
+                               long p = ptr.ToInt64 () + offset;
+                               ptr = new IntPtr (p);
+                       }
+                       return ptr;
                }
 
-               [MonoTODO ("Not implemented, does nothing")]
                [EditorBrowsable (EditorBrowsableState.Never)]
-               protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset,
-                                                       int size, bool fAsciiOnly)
-               {
+               protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset, int size, bool fAsciiOnly)
+               {
+                       if (resource_data == null)
+                               return; // throw?
+                       if (output == null)
+                               throw new ArgumentNullException ("output");
+                       if (offset > resource_data.MaxOffset - size)
+                               throw new ArgumentOutOfRangeException ("size");
+
+                       //TODO: fAsciiOnly?
+                       IntPtr ptr = AddOffset (resource_data.Ptr, offset);
+                       HttpWriter writer = output.GetHttpWriter ();
+                       
+                       if (writer == null || writer.Response.ContentEncoding.CodePage != 65001) {
+                               byte [] bytes = new byte [size];
+                               Marshal.Copy (ptr, bytes, 0, size);
+                               output.Write (Encoding.UTF8.GetString (bytes));
+                               bytes = null;
+                               return;
+                       }
+
+                       writer.WriteUTF8Ptr (ptr, size);
                }
 
                #endregion
@@ -385,7 +485,6 @@ namespace System.Web.UI {
                        }
                }
 
-#if NET_2_0
                protected internal object Eval (string expression)
                {
                        return DataBinder.Eval (Page.GetDataItem(), expression);
@@ -439,6 +538,5 @@ namespace System.Web.UI {
                {
                        throw new NotImplementedException ();
                }
-#endif
        }
 }