2008-10-24 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.UI / TemplateControl.cs
1 //
2 // System.Web.UI.TemplateControl.cs
3 //
4 // Authors:
5 //   Duncan Mak  (duncan@ximian.com)
6 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
8 //
9 // (C) 2002 Ximian, Inc. (http://www.ximian.com)
10 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
11 //
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:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
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.
30 //
31
32 using System.Collections;
33 using System.ComponentModel;
34 using System.Reflection;
35 using System.Security.Permissions;
36 using System.Web.Compilation;
37 using System.Web.Util;
38 using System.Xml;
39 using System.IO;
40
41 namespace System.Web.UI {
42
43         // CAS
44         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
45         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
46 #if NET_2_0
47         public abstract class TemplateControl : Control, INamingContainer, IFilterResolutionService {
48 #else
49         public abstract class TemplateControl : Control, INamingContainer {
50 #endif
51                 static readonly Assembly _System_Web_Assembly = typeof (TemplateControl).Assembly;
52                 static object abortTransaction = new object ();
53                 static object commitTransaction = new object ();
54                 static object error = new object ();
55                 static string [] methodNames = { "Page_Init",
56 #if NET_2_0
57                                                  "Page_PreInit",
58                                                  "Page_PreLoad",
59                                                  "Page_LoadComplete",
60                                                  "Page_PreRenderComplete",
61                                                  "Page_SaveStateComplete",
62                                                  "Page_InitComplete",
63 #endif
64                                                  "Page_Load",
65                                                  "Page_DataBind",
66                                                  "Page_PreRender",
67                                                  "Page_Disposed",
68                                                  "Page_Error",
69                                                  "Page_Unload",
70                                                  "Page_AbortTransaction",
71                                                  "Page_CommitTransaction"};
72
73                 const BindingFlags bflags = BindingFlags.Public |
74                                             BindingFlags.NonPublic |
75                                             BindingFlags.Instance;
76
77 #if NET_2_0
78                 string _appRelativeVirtualPath;
79 #endif
80                 
81                 #region Constructor
82                 protected TemplateControl ()
83                 {
84 #if NET_2_0
85                         TemplateControl = this;
86 #endif
87                         Construct ();
88                 }
89
90                 #endregion
91
92                 #region Properties
93                 [EditorBrowsable (EditorBrowsableState.Never)]
94 #if NET_2_0
95                 [Obsolete]
96 #endif
97                 protected virtual int AutoHandlers {
98                         get { return 0; }
99                         set { }
100                 }
101
102                 [EditorBrowsable (EditorBrowsableState.Never)]
103                 protected virtual bool SupportAutoEvents {
104                         get { return true; }
105                 }
106
107 #if NET_2_0
108                 public string AppRelativeVirtualPath {
109                         get { return _appRelativeVirtualPath; }
110                         set { _appRelativeVirtualPath = value; }
111                 }
112 #endif
113
114                 #endregion
115
116                 #region Methods
117
118                 protected virtual void Construct ()
119                 {
120                 }
121
122                 [MonoTODO ("Not implemented")]
123                 protected LiteralControl CreateResourceBasedLiteralControl (int offset,
124                                                                                     int size,
125                                                                                     bool fAsciiOnly)
126                 {
127                         return null;
128                 }
129
130                 class EvtInfo {
131                         public MethodInfo method;
132                         public string methodName;
133                         public EventInfo evt;
134                         public bool noParams;
135                 }
136
137                 static Hashtable auto_event_info;
138                 static object auto_event_info_monitor = new Object ();
139
140                 internal void WireupAutomaticEvents ()
141                 {
142                         if (!SupportAutoEvents || !AutoEventWireup)
143                                 return;
144
145                         ArrayList events = null;
146
147                         /* Avoid expensive reflection operations by computing the event info only once */
148                         lock (auto_event_info_monitor) {
149                                 if (auto_event_info == null)
150                                         auto_event_info = new Hashtable ();
151                                 events = (ArrayList)auto_event_info [GetType ()];
152                                 if (events == null) {
153                                         events = CollectAutomaticEventInfo ();
154                                         auto_event_info [GetType ()] = events;
155                                 }
156                         }
157
158                         for (int i = 0; i < events.Count; ++i) {
159                                 EvtInfo evinfo = (EvtInfo)events [i];
160                                 if (evinfo.noParams) {
161                                         NoParamsInvoker npi = new NoParamsInvoker (this, evinfo.method);
162                                         evinfo.evt.AddEventHandler (this, npi.FakeDelegate);
163                                 } else {
164                                         evinfo.evt.AddEventHandler (this, Delegate.CreateDelegate (
165 #if NET_2_0
166                                                         typeof (EventHandler), this, evinfo.method));
167 #else
168                                                         typeof (EventHandler), this, evinfo.methodName));
169 #endif
170                                 }
171                         }
172                 }
173
174                 ArrayList CollectAutomaticEventInfo () {
175                         ArrayList events = new ArrayList ();
176
177                         foreach (string methodName in methodNames) {
178                                 MethodInfo method = null;
179                                 Type type;
180                                 for (type = GetType (); type.Assembly != _System_Web_Assembly; type = type.BaseType) {
181                                         method = type.GetMethod (methodName, bflags);
182                                         if (method != null)
183                                                 break;
184                                 }
185                                 if (method == null)
186                                         continue;
187
188                                 if (method.DeclaringType != type) {
189                                         if (!method.IsPublic && !method.IsFamilyOrAssembly &&
190                                             !method.IsFamilyAndAssembly && !method.IsFamily)
191                                                 continue;
192                                 }
193
194                                 if (method.ReturnType != typeof (void))
195                                         continue;
196
197                                 ParameterInfo [] parms = method.GetParameters ();
198                                 int length = parms.Length;
199                                 bool noParams = (length == 0);
200                                 if (!noParams && (length != 2 ||
201                                     parms [0].ParameterType != typeof (object) ||
202                                     parms [1].ParameterType != typeof (EventArgs)))
203                                     continue;
204
205                                 int pos = methodName.IndexOf ("_");
206                                 string eventName = methodName.Substring (pos + 1);
207                                 EventInfo evt = type.GetEvent (eventName);
208                                 if (evt == null) {
209                                         /* This should never happen */
210                                         continue;
211                                 }
212
213                                 EvtInfo evinfo = new EvtInfo ();
214                                 evinfo.method = method;
215                                 evinfo.methodName = methodName;
216                                 evinfo.evt = evt;
217                                 evinfo.noParams = noParams;
218
219                                 events.Add (evinfo);
220                         }
221
222                         return events;
223                 }
224
225                 [EditorBrowsable (EditorBrowsableState.Never)]
226                 protected virtual void FrameworkInitialize ()
227                 {
228                 }
229
230                 Type GetTypeFromControlPath (string virtualPath)
231                 {
232                         if (virtualPath == null)
233                                 throw new ArgumentNullException ("virtualPath");
234
235                         string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
236 #if NET_2_0
237                         return BuildManager.GetCompiledType (vpath);
238 #else
239                         string realpath = Context.Request.MapPath (vpath);
240                         return UserControlParser.GetCompiledType (vpath, realpath, Context);
241 #endif
242                 }
243
244                 public Control LoadControl (string virtualPath)
245                 {
246 #if NET_2_0
247                         if (virtualPath == null)
248                                 throw new ArgumentNullException ("virtualPath");
249 #else
250                         if (virtualPath == null)
251                                 throw new HttpException ("virtualPath is null");
252 #endif
253                         Type type = GetTypeFromControlPath (virtualPath);
254                         
255                         return LoadControl (type, null);
256                 }
257
258                 public Control LoadControl (Type type, object[] parameters) 
259                 {
260                         object [] attrs = null;
261
262                         if (type != null)
263                                 type.GetCustomAttributes (typeof (PartialCachingAttribute), true);
264                         if (attrs != null && attrs.Length == 1) {
265                                 PartialCachingAttribute attr = (PartialCachingAttribute) attrs [0];
266                                 PartialCachingControl ctrl = new PartialCachingControl (type, parameters);
267                                 ctrl.VaryByParams = attr.VaryByParams;
268                                 ctrl.VaryByControls = attr.VaryByControls;
269                                 ctrl.VaryByCustom = attr.VaryByCustom;
270                                 return ctrl;
271                         }
272
273                         object control = Activator.CreateInstance (type, parameters);
274                         if (control is UserControl)
275                                 ((UserControl) control).InitializeAsUserControl (Page);
276
277                         return (Control) control;
278                 }
279
280                 public ITemplate LoadTemplate (string virtualPath)
281                 {
282 #if NET_2_0
283                         if (virtualPath == null)
284                                 throw new ArgumentNullException ("virtualPath");
285 #else
286                         if (virtualPath == null)
287                                 throw new HttpException ("virtualPath is null");
288 #endif
289                         Type t = GetTypeFromControlPath (virtualPath);
290                         return new SimpleTemplate (t);
291                 }
292
293                 protected virtual void OnAbortTransaction (EventArgs e)
294                 {
295                         EventHandler eh = Events [abortTransaction] as EventHandler;
296                         if (eh != null)
297                                 eh (this, e);
298                 }
299
300                 protected virtual void OnCommitTransaction (EventArgs e)
301                 {
302                         EventHandler eh = Events [commitTransaction] as EventHandler;
303                         if (eh != null)
304                                 eh (this, e);
305                 }
306
307                 protected virtual void OnError (EventArgs e)
308                 {
309                         EventHandler eh = Events [error] as EventHandler;
310                         if (eh != null)
311                                 eh (this, e);
312                 }
313
314 #if !NET_2_0
315                 [MonoTODO ("Not implemented, always returns null")]
316 #endif
317                 public Control ParseControl (string content)
318                 {
319                         if (content == null)
320                                 throw new ArgumentNullException ("content");
321
322 #if NET_2_0
323                         // FIXME: This method needs to be rewritten in some sane way - the way it is now,
324                         // is a kludge. New version should not use
325                         // UserControlParser.GetCompiledType, but instead resort to some other way
326                         // of creating the content (template instantiation? BuildManager? TBD)
327                         TextReader reader = new StringReader (content);
328                         Type control = UserControlParser.GetCompiledType (reader, content.GetHashCode (), HttpContext.Current);
329                         if (control == null)
330                                 return null;
331
332                         TemplateControl parsedControl = Activator.CreateInstance (control, null) as TemplateControl;
333                         if (parsedControl == null)
334                                 return null;
335
336                         if (this is System.Web.UI.Page)
337                                 parsedControl.Page = (System.Web.UI.Page) this;
338                         parsedControl.FrameworkInitialize ();
339                         
340                         Control ret = new Control ();
341                         int count = parsedControl.Controls.Count;
342                         Control[] parsedControlControls = new Control [count];
343                         parsedControl.Controls.CopyTo (parsedControlControls, 0);
344
345                         for (int i = 0; i < count; i++)
346                                 ret.Controls.Add (parsedControlControls [i]);
347
348                         parsedControl = null;
349                         return ret;
350 #else
351                         return null;
352 #endif
353                 }
354
355 #if NET_2_0
356                 [MonoTODO ("Parser filters not implemented yet. Calls ParseControl (string) for now.")]
357                 public Control ParseControl (string content, bool ignoreParserFilter)
358                 {
359                         return ParseControl (content);
360                 }
361 #endif
362         
363                 [EditorBrowsable (EditorBrowsableState.Never)]
364                 public 
365 #if !NET_2_0
366                 static
367 #endif
368                 object ReadStringResource ()
369                 {
370                         throw new NotSupportedException ();
371                 }
372
373 #if NET_2_0
374                 protected object GetGlobalResourceObject (string className, string resourceKey)
375                 {
376                         return HttpContext.GetGlobalResourceObject (className, resourceKey);
377                 }
378
379                 protected object GetGlobalResourceObject (string className, string resourceKey, Type objType, string propName)
380                 {
381                         if (String.IsNullOrEmpty (resourceKey) || String.IsNullOrEmpty (propName) ||
382                             String.IsNullOrEmpty (className) || objType == null)
383                                 return null;
384
385                         object globalObject = GetGlobalResourceObject (className, resourceKey);
386                         if (globalObject == null)
387                                 return null;
388                         
389                         TypeConverter converter = TypeDescriptor.GetProperties (objType) [propName].Converter;
390                         if (converter == null || !converter.CanConvertFrom (globalObject.GetType ()))
391                                 return null;
392                         
393                         return converter.ConvertFrom (globalObject);
394                 }
395
396                 protected object GetLocalResourceObject (string resourceKey)
397                 {
398                         return HttpContext.GetLocalResourceObject (VirtualPathUtility.ToAbsolute (this.AppRelativeVirtualPath),
399                                                                    resourceKey);
400                 }
401                 
402                 protected object GetLocalResourceObject (string resourceKey, Type objType, string propName)
403                 {
404                         if (String.IsNullOrEmpty (resourceKey) || String.IsNullOrEmpty (propName) || objType == null)
405                                 return null;
406
407                         object localObject = GetLocalResourceObject (resourceKey);
408                         if (localObject == null)
409                                 return null;
410                         
411                         TypeConverter converter = TypeDescriptor.GetProperties (objType) [propName].Converter;
412                         if (converter == null || !converter.CanConvertFrom (localObject.GetType ()))
413                                 return null;
414                         
415                         return converter.ConvertFrom (localObject);
416                 }
417
418                 internal override TemplateControl TemplateControlInternal {
419                         get { return this; }
420                 }
421 #endif
422                 
423                 [EditorBrowsable (EditorBrowsableState.Never)]
424                 public static object ReadStringResource (Type t)
425                 {
426                         throw new NotSupportedException ();
427                 }
428
429                 [MonoTODO ("Not implemented, does nothing")]
430                 [EditorBrowsable (EditorBrowsableState.Never)]
431                 protected void SetStringResourcePointer (object stringResourcePointer,
432                                                          int maxResourceOffset)
433                 {
434                 }
435
436                 [MonoTODO ("Not implemented, does nothing")]
437                 [EditorBrowsable (EditorBrowsableState.Never)]
438                 protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset,
439                                                         int size, bool fAsciiOnly)
440                 {
441                 }
442
443                 #endregion
444
445                 #region Events
446
447                 [WebSysDescription ("Raised when the user aborts a transaction.")]
448                 public event EventHandler AbortTransaction {
449                         add { Events.AddHandler (abortTransaction, value); }
450                         remove { Events.RemoveHandler (abortTransaction, value); }
451                 }
452
453                 [WebSysDescription ("Raised when the user initiates a transaction.")]
454                 public event EventHandler CommitTransaction {
455                         add { Events.AddHandler (commitTransaction, value); }
456                         remove { Events.RemoveHandler (commitTransaction, value); }
457                 }
458
459                 [WebSysDescription ("Raised when an exception occurs that cannot be handled.")]
460                 public event EventHandler Error {
461                         add { Events.AddHandler (error, value); }
462                         remove { Events.RemoveHandler (error, value); }
463                 }
464
465                 #endregion
466
467                 class SimpleTemplate : ITemplate
468                 {
469                         Type type;
470
471                         public SimpleTemplate (Type type)
472                         {
473                                 this.type = type;
474                         }
475
476                         public void InstantiateIn (Control control)
477                         {
478                                 Control template = Activator.CreateInstance (type) as Control;
479                                 template.SetBindingContainer (false);
480                                 control.Controls.Add (template);
481                         }
482                 }
483
484 #if NET_2_0
485                 protected internal object Eval (string expression)
486                 {
487                         return DataBinder.Eval (Page.GetDataItem(), expression);
488                 }
489         
490                 protected internal string Eval (string expression, string format)
491                 {
492                         return DataBinder.Eval (Page.GetDataItem(), expression, format);
493                 }
494         
495                 protected internal object XPath (string xpathexpression)
496                 {
497                         return XPathBinder.Eval (Page.GetDataItem(), xpathexpression);
498                 }
499         
500                 protected internal object XPath (string xpathexpression, IXmlNamespaceResolver resolver)
501                 {
502                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, null, resolver);
503                 }
504
505                 protected internal string XPath (string xpathexpression, string format)
506                 {
507                         return XPathBinder.Eval (Page.GetDataItem(), xpathexpression, format);
508                 }
509         
510                 protected internal string XPath (string xpathexpression, string format, IXmlNamespaceResolver resolver)
511                 {
512                         return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format, resolver);
513                 }
514
515                 protected internal IEnumerable XPathSelect (string xpathexpression)
516                 {
517                         return XPathBinder.Select (Page.GetDataItem(), xpathexpression);
518                 }
519
520                 protected internal IEnumerable XPathSelect (string xpathexpression, IXmlNamespaceResolver resolver)
521                 {
522                         return XPathBinder.Select (Page.GetDataItem (), xpathexpression, resolver);
523                 }
524
525                 // IFilterResolutionService
526
527                 [MonoTODO ("Not implemented")]
528                 int IFilterResolutionService.CompareFilters (string filter1, string filter2)
529                 {
530                         throw new NotImplementedException ();
531                 }
532
533                 [MonoTODO ("Not implemented")]
534                 bool IFilterResolutionService.EvaluateFilter (string filterName)
535                 {
536                         throw new NotImplementedException ();
537                 }
538 #endif
539         }
540 }