disable broken tests on net_4_0
[mcs.git] / class / System.Web.DynamicData / System.Web.DynamicData / FieldTemplateFactory.cs
blobabff575054dc79a9bfca2a76917f917577755dbf
1 //
2 // FieldTemplateFactory.cs
3 //
4 // Author:
5 // Atsushi Enomoto <atsushi@ximian.com>
6 // Marek Habersack <mhabersack@novell.com>
7 //
8 // Copyright (C) 2008-2009 Novell Inc. http://novell.com
9 //
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.
31 using System;
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.Collections.Specialized;
35 using System.ComponentModel;
36 using System.ComponentModel.DataAnnotations;
37 using System.Globalization;
38 using System.IO;
39 using System.Security.Permissions;
40 using System.Security.Principal;
41 using System.Web.Caching;
42 using System.Web.Compilation;
43 using System.Web.Hosting;
44 using System.Web.UI.WebControls;
46 namespace System.Web.DynamicData
48 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
49 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
50 public class FieldTemplateFactory : IFieldTemplateFactory
52 const string DEFAULT_TEMPLATE_FOLDER_VIRTUAL_PATH = "FieldTemplates/";
54 static readonly Dictionary <Type, Type> typeFallbacks = new Dictionary <Type, Type> () {
55 {typeof (float), typeof (decimal)},
56 {typeof (double), typeof (decimal)},
57 {typeof (short), typeof (int)},
58 {typeof (long), typeof (int)},
59 {typeof (byte), typeof (int)},
60 {typeof (char), typeof (string)},
61 {typeof (int), typeof (string)},
62 {typeof (decimal), typeof (string)},
63 {typeof (Guid), typeof (string)},
64 {typeof (DateTime), typeof (string)},
65 {typeof (DateTimeOffset), typeof (string)},
66 {typeof (TimeSpan), typeof (string)}
69 string templateFolderVirtualPath;
70 string userTemplateVirtualPath;
72 public MetaModel Model { get; private set; }
74 public string TemplateFolderVirtualPath {
75 get {
76 if (templateFolderVirtualPath == null) {
77 MetaModel m = Model;
78 string virtualPath = userTemplateVirtualPath == null ? DEFAULT_TEMPLATE_FOLDER_VIRTUAL_PATH : userTemplateVirtualPath;
80 if (m != null)
81 templateFolderVirtualPath = VirtualPathUtility.Combine (m.DynamicDataFolderVirtualPath, virtualPath);
82 else
83 templateFolderVirtualPath = virtualPath;
85 templateFolderVirtualPath = VirtualPathUtility.AppendTrailingSlash (templateFolderVirtualPath);
88 return templateFolderVirtualPath;
91 set {
92 userTemplateVirtualPath = value;
93 templateFolderVirtualPath = null;
97 public virtual string BuildVirtualPath (string templateName, MetaColumn column, DataBoundControlMode mode)
99 // Tests show the 'column' parameter is not used here
101 if (String.IsNullOrEmpty (templateName))
102 throw new ArgumentNullException ("templateName");
104 string basePath = TemplateFolderVirtualPath;
105 string suffix;
107 switch (mode) {
108 default:
109 case DataBoundControlMode.ReadOnly:
110 suffix = String.Empty;
111 break;
113 case DataBoundControlMode.Edit:
114 suffix = "_Edit";
115 break;
117 case DataBoundControlMode.Insert:
118 suffix = "_Insert";
119 break;
122 return basePath + templateName + suffix + ".ascx";
125 public virtual IFieldTemplate CreateFieldTemplate (MetaColumn column, DataBoundControlMode mode, string uiHint)
127 // NO checks are made on parameters in .NET, but well "handle" the NREX
128 // throws in the other methods
129 string virtualPath = GetFieldTemplateVirtualPath (column, mode, uiHint);
130 if (String.IsNullOrEmpty (virtualPath))
131 return null;
133 return BuildManager.CreateInstanceFromVirtualPath (virtualPath, typeof (IFieldTemplate)) as IFieldTemplate;
136 public virtual string GetFieldTemplateVirtualPath (MetaColumn column, DataBoundControlMode mode, string uiHint)
138 // NO checks are made on parameters in .NET, but well "handle" the NREX
139 // throws in the other methods
140 DataBoundControlMode newMode = PreprocessMode (column, mode);
142 // The algorithm is as follows:
144 // 1. If column has a DataTypeAttribute on it, get the data type
145 // - if it's Custom data type, uiHint is used unconditionally
146 // - if it's not a custom type, ignore uiHint and choose template based
147 // on type
149 // 2. If #1 is false and uiHint is not empty, use uiHint if the template
150 // exists
152 // 3. If #2 is false, look up type according to the following algorithm:
154 // 1. lookup column type's full name
155 // 2. if #1 fails, look up short type name
156 // 3. if #2 fails, map type to special type name (Int -> Integer, String
157 // -> Text etc)
158 // 4. if #3 fails, try to find a fallback type
159 // 5. if #4 fails, check if it's a foreign key or child column
160 // 6. if #5 fails, return null
162 // From: http://msdn.microsoft.com/en-us/library/cc488523.aspx (augmented)
165 DataTypeAttribute attr = column.DataTypeAttribute;
166 bool uiHintPresent = !String.IsNullOrEmpty (uiHint);
167 string templatePath = null;
168 int step = uiHintPresent ? 0 : 1;
169 Type columnType = column.ColumnType;
171 if (!uiHintPresent && attr == null) {
172 if (column is MetaChildrenColumn)
173 templatePath = GetExistingTemplateVirtualPath ("Children", column, newMode);
174 else if (column is MetaForeignKeyColumn)
175 templatePath = GetExistingTemplateVirtualPath ("ForeignKey", column, newMode);
178 while (step < 6 && templatePath == null) {
179 switch (step) {
180 case 0:
181 templatePath = GetExistingTemplateVirtualPath (uiHint, column, newMode);
182 break;
184 case 1:
185 if (attr != null)
186 templatePath = GetTemplateForDataType (attr.DataType, attr.GetDataTypeName (), uiHint, column, newMode);
187 break;
189 case 2:
190 templatePath = GetExistingTemplateVirtualPath (columnType.FullName, column, newMode);
191 break;
193 case 3:
194 templatePath = GetExistingTemplateVirtualPath (columnType.Name, column, newMode);
195 break;
197 case 4:
198 templatePath = ColumnTypeToSpecialName (columnType, column, newMode);
199 break;
201 case 5:
202 columnType = GetFallbackType (columnType, column, newMode);
203 if (columnType == null)
204 step = 5;
205 else
206 step = uiHintPresent ? 0 : 1;
207 break;
210 step++;
213 return templatePath;
216 Type GetFallbackType (Type columnType, MetaColumn column, DataBoundControlMode mode)
218 Type ret;
219 if (typeFallbacks.TryGetValue (columnType, out ret))
220 return ret;
222 return null;
225 string ColumnTypeToSpecialName (Type columnType, MetaColumn column, DataBoundControlMode mode)
227 if (columnType == typeof (int))
228 return GetExistingTemplateVirtualPath ("Integer", column, mode);
230 if (columnType == typeof (string))
231 return GetExistingTemplateVirtualPath ("Text", column, mode);
233 return null;
236 string GetExistingTemplateVirtualPath (string baseName, MetaColumn column, DataBoundControlMode mode)
238 string templatePath = BuildVirtualPath (baseName, column, mode);
239 if (String.IsNullOrEmpty (templatePath))
240 return null;
242 // TODO: cache positive hits (and watch for removal events on those)
243 string physicalPath = HostingEnvironment.MapPath (templatePath);
244 if (File.Exists (physicalPath))
245 return templatePath;
247 return null;
250 string GetTemplateForDataType (DataType dataType, string customDataType, string uiHint, MetaColumn column, DataBoundControlMode mode)
252 switch (dataType) {
253 case DataType.Custom:
254 return GetExistingTemplateVirtualPath (customDataType, column, mode);
256 case DataType.DateTime:
257 return GetExistingTemplateVirtualPath ("DateTime", column, mode);
259 case DataType.MultilineText:
260 return GetExistingTemplateVirtualPath ("MultilineText", column, mode);
262 default:
263 return GetExistingTemplateVirtualPath ("Text", column, mode);
267 public virtual void Initialize (MetaModel model)
269 Model = model;
272 public virtual DataBoundControlMode PreprocessMode (MetaColumn column, DataBoundControlMode mode)
274 // In good tradition of .NET's DynamicData, let's not check the
275 // parameters...
276 if (column == null)
277 throw new NullReferenceException ();
279 if (column.IsGenerated)
280 return DataBoundControlMode.ReadOnly;
282 if (column.IsPrimaryKey) {
283 if (mode == DataBoundControlMode.Edit)
284 return DataBoundControlMode.ReadOnly;
287 return mode;