5 // Atsushi Enomoto <atsushi@ximian.com>
6 // Marek Habersack <mhabersack@novell.com>
8 // Copyright (C) 2008-2009 Novell Inc. http://novell.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.
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;
39 using System.Reflection;
40 using System.Security.Permissions;
41 using System.Security.Principal;
42 using System.Web.Caching;
43 using System.Web.DynamicData.ModelProviders;
45 namespace System.Web.DynamicData
47 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
48 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
49 public class MetaColumn : IFieldFormattingOptions
51 // (Int32.MaxValue / 2) - 5
52 const int SHORT_STRING_MAX_LENGTH = 0x3ffffffa;
55 bool? scaffoldReflected;
56 bool? applyFormatInEditMode;
57 bool? convertEmptyStringToNull;
58 bool dataTypeReflected;
59 bool defaultValueReflected;
60 bool descriptionReflected;
61 bool requiredReflected;
64 string dataFormatString;
65 PropertyDescriptor property;
71 string nullDisplayText;
72 string requiredErrorMessage;
76 AttributeCollection attributes;
78 DisplayFormatAttribute displayFormatAttr;
79 DataTypeAttribute dataTypeAttr;
80 ScaffoldColumnAttribute scaffoldAttr;
81 RequiredAttribute requiredAttr;
83 internal MetaColumn (MetaTable table, ColumnProvider provider)
90 Type columnType = ColumnType;
91 TypeCode code = Type.GetTypeCode (columnType);
96 case TypeCode.Decimal:
97 IsFloatingPoint = true;
107 case TypeCode.String:
111 case TypeCode.Object:
112 // So far only byte[] seems to be treated as a binary type
113 if (columnType.IsArray && columnType.GetArrayRank () == 1 && columnType.GetElementType () == typeof (byte))
118 TypeCode = TypeCode.Object;
122 IsLongString = MaxLength > SHORT_STRING_MAX_LENGTH;
125 public bool ApplyFormatInEditMode {
127 if (applyFormatInEditMode == null)
128 applyFormatInEditMode = CheckApplyFormatInEditMode ();
130 return (bool)applyFormatInEditMode;
134 public AttributeCollection Attributes {
136 if (attributes == null)
137 attributes = LoadAttributes ();
144 public Type ColumnType {
145 get { return Provider.ColumnType; }
148 public bool ConvertEmptyStringToNull {
150 if (convertEmptyStringToNull == null)
151 convertEmptyStringToNull = CheckConvertEmptyStringToNull ();
153 return (bool)convertEmptyStringToNull;
158 public string DataFormatString {
160 if (dataFormatString == null)
161 dataFormatString = CheckDataFormatString ();
163 return dataFormatString;
167 public DataTypeAttribute DataTypeAttribute {
169 if (!dataTypeReflected && dataTypeAttr == null)
170 dataTypeAttr = CheckDataTypeAttribute ();
177 public Object DefaultValue {
179 if (!defaultValueReflected && defaultValue == null) {
180 DefaultValueAttribute defaultValueAttr = CheckDefaultValueAttribute ();
181 if (defaultValueAttr != null)
182 defaultValue = defaultValueAttr.Value;
189 public string Description {
191 if (!descriptionReflected && description == null) {
192 DescriptionAttribute descriptionAttr = CheckDescriptionAttribute ();
193 if (descriptionAttr != null)
194 description = descriptionAttr.Description;
201 public string DisplayName {
203 if (displayName == null)
204 displayName = CheckDisplayName ();
210 public PropertyInfo EntityTypeProperty {
211 get { return Provider.EntityTypeProperty; }
214 public bool HtmlEncode { get; private set; }
216 public bool IsBinaryData { get; private set; }
218 public bool IsCustomProperty {
219 get { return Provider.IsCustomProperty; }
222 public bool IsFloatingPoint { get; private set; }
224 public bool IsForeignKeyComponent {
225 get { return Provider.IsForeignKeyComponent; }
228 public bool IsGenerated {
229 get { return Provider.IsGenerated; }
232 public bool IsInteger { get; private set; }
234 public bool IsLongString { get; private set; }
236 public bool IsPrimaryKey {
237 get { return Provider.IsPrimaryKey; }
240 public bool IsReadOnly {
242 if (readOnly == null)
243 readOnly = CheckReadOnlyAttribute ();
245 return (bool)readOnly;
249 // It appears that all columns are required unless Provider.Nullable is true for
250 // them. We could skip checking for the RequiredAttribute for that reason, but that
251 // way we wouldn't be forward-compatible.
252 // What's more, it appears that a RequiredAttribute instance is always included in
253 // Attributes, whether or not the corresponding field is decorataed with it.
254 public bool IsRequired {
256 if (!requiredReflected && requiredAttr == null)
257 requiredAttr = CheckRequiredAttribute ();
259 return requiredAttr != null;
263 public bool IsString { get; private set; }
265 public int MaxLength {
267 if (maxLength == null)
268 maxLength = CheckMaxLength ();
270 return (int)maxLength;
274 public MetaModel Model { get; private set; }
277 get { return Provider.Name; }
280 public string NullDisplayText {
282 if (nullDisplayText == null)
283 nullDisplayText = CheckNullDisplayText ();
285 return nullDisplayText;
289 public ColumnProvider Provider { get; private set; }
291 public string RequiredErrorMessage {
293 if (requiredErrorMessage == null) {
294 RequiredAttribute attr = CheckRequiredAttribute ();
296 requiredErrorMessage = String.Empty;
298 requiredErrorMessage = attr.ErrorMessage;
301 return requiredErrorMessage;
305 public bool Scaffold {
307 if (scaffold != null)
308 return (bool)scaffold;
309 if (scaffoldReflected != null)
310 return (bool)scaffoldReflected;
312 MetaModel.GetDataFieldAttribute <ScaffoldColumnAttribute> (Attributes, ref scaffoldAttr);
313 if (scaffoldAttr != null) {
314 scaffoldReflected = scaffoldAttr.Scaffold;
315 return (bool)scaffoldReflected;
318 string uiHint = UIHint;
319 if (!String.IsNullOrEmpty (uiHint))
320 scaffoldReflected = true;
321 // LAMESPEC: IsForeignKeyComponent does NOT set Scaffold=false
322 else if (IsGenerated || IsCustomProperty)
323 scaffoldReflected = false;
324 else if (Table.ScaffoldAllTables)
325 scaffoldReflected = true;
327 scaffoldReflected = true;
329 return (bool)scaffoldReflected;
332 set { scaffold = value; }
335 public string SortExpression {
337 ColumnProvider provider = Provider;
338 if (provider.IsSortable)
345 public MetaTable Table { get; private set; }
347 public TypeCode TypeCode { get; private set; }
349 // LAMESPEC: if there's no attribute, null is returned
350 public string UIHint {
352 if (!uiHintReflected && uiHint == null)
353 uiHint = CheckUIHintAttribute ();
359 string CheckUIHintAttribute ()
364 uiHintReflected = true;
365 UIHintAttribute attr = null;
366 MetaModel.GetDataFieldAttribute <UIHintAttribute> (Attributes, ref attr);
374 bool CheckApplyFormatInEditMode ()
376 var displayFormat = GetDisplayFormat ();
377 if (displayFormat == null)
380 return displayFormat.ApplyFormatInEditMode;
383 bool CheckConvertEmptyStringToNull ()
385 var displayFormat = GetDisplayFormat ();
386 if (displayFormat == null)
389 return displayFormat.ConvertEmptyStringToNull;
392 string CheckDataFormatString ()
394 var displayFormat = GetDisplayFormat ();
395 if (displayFormat == null)
398 return displayFormat.DataFormatString;
401 DataTypeAttribute CheckDataTypeAttribute ()
403 if (dataTypeReflected)
406 dataTypeReflected = true;
407 MetaModel.GetDataFieldAttribute <DataTypeAttribute> (Attributes, ref dataTypeAttr);
408 if (dataTypeAttr == null && (ColumnType == typeof (string)))
409 return new DataTypeAttribute (DataType.Text);
414 DefaultValueAttribute CheckDefaultValueAttribute ()
416 defaultValueReflected = true;
417 DefaultValueAttribute dummy = null;
418 MetaModel.GetDataFieldAttribute <DefaultValueAttribute> (Attributes, ref dummy);
425 DescriptionAttribute CheckDescriptionAttribute ()
427 descriptionReflected = true;
428 DescriptionAttribute dummy = null;
429 MetaModel.GetDataFieldAttribute <DescriptionAttribute> (Attributes, ref dummy);
436 string CheckDisplayName ()
438 DisplayNameAttribute attr = null;
439 MetaModel.GetDataFieldAttribute <DisplayNameAttribute> (Attributes, ref attr);
441 return attr.DisplayName;
446 RequiredAttribute CheckRequiredAttribute ()
448 if (requiredReflected)
451 requiredReflected = true;
452 MetaModel.GetDataFieldAttribute <RequiredAttribute> (Attributes, ref requiredAttr);
457 bool CheckReadOnlyAttribute ()
459 ReadOnlyAttribute attr = null;
460 MetaModel.GetDataFieldAttribute <ReadOnlyAttribute> (Attributes, ref attr);
462 // Apparently attr.IsReadOnly and/or comparisons to
463 // ReadOnlyAttribute.{Yes,No} don't matter. The sole presence of the
464 // attribute marks column as read-only
468 int CheckMaxLength ()
470 StringLengthAttribute attr = null;
471 MetaModel.GetDataFieldAttribute <StringLengthAttribute> (Attributes, ref attr);
474 return attr.MaximumLength;
476 return Provider.MaxLength;
479 string CheckNullDisplayText ()
481 DisplayFormatAttribute displayFormat = GetDisplayFormat ();
483 if (displayFormat == null)
486 return displayFormat.NullDisplayText;
489 DisplayFormatAttribute GetDisplayFormat ()
491 MetaModel.GetDataFieldAttribute <DisplayFormatAttribute> (Attributes, ref displayFormatAttr);
492 if (displayFormatAttr == null) {
493 var dta = DataTypeAttribute;
494 displayFormatAttr = dta == null ? null : dta.DisplayFormat;
497 return displayFormatAttr;
500 AttributeCollection LoadAttributes ()
502 var props = MetaModel.GetTypeDescriptor (Table.EntityType).GetProperties ();
503 AttributeCollection reflected;
505 int propsCount = props == null ? 0 : props.Count;
507 reflected = AttributeCollection.Empty;
509 var property = props.Find (Name, true);
510 if (property == null)
511 reflected = AttributeCollection.Empty;
513 reflected = property.Attributes;
516 if (!Provider.Nullable && reflected.OfType <RequiredAttribute> ().Count () == 0)
517 reflected = AttributeCollection.FromExisting (reflected, new Attribute[] { new RequiredAttribute () });
522 public override string ToString ()