1 // 2 // MetaColumn.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 // 10 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 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.Linq; 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; 44 45 namespace System.Web.DynamicData 46 { 47 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] 48 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] 49 public class MetaColumn : IFieldFormattingOptions 50 { 51 // (Int32.MaxValue / 2) - 5 52 const int SHORT_STRING_MAX_LENGTH = 0x3ffffffa; 53 54 bool? scaffold; 55 bool? scaffoldReflected; 56 bool? applyFormatInEditMode; 57 bool? convertEmptyStringToNull; 58 bool dataTypeReflected; 59 bool defaultValueReflected; 60 bool descriptionReflected; 61 bool requiredReflected; 62 bool uiHintReflected; 63 64 string dataFormatString; 65 object defaultValue; 66 string description; 67 string displayName; 68 bool? readOnly; 69 int? maxLength; 70 string nullDisplayText; 71 string requiredErrorMessage; 72 string uiHint; 73 74 // Attributes 75 AttributeCollection attributes; 76 77 DisplayFormatAttribute displayFormatAttr; 78 DataTypeAttribute dataTypeAttr; 79 ScaffoldColumnAttribute scaffoldAttr; 80 RequiredAttribute requiredAttr; 81 MetaColumn(MetaTable table, ColumnProvider provider)82 internal MetaColumn (MetaTable table, ColumnProvider provider) 83 { 84 Table = table; 85 Provider = provider; 86 Model = table.Model; 87 HtmlEncode = true; 88 89 Type columnType = ColumnType; 90 TypeCode code = Type.GetTypeCode (columnType); 91 TypeCode = code; 92 switch (code) { 93 case TypeCode.Single: 94 case TypeCode.Double: 95 case TypeCode.Decimal: 96 IsFloatingPoint = true; 97 break; 98 99 case TypeCode.Byte: 100 case TypeCode.Int16: 101 case TypeCode.Int32: 102 case TypeCode.Int64: 103 IsInteger = true; 104 break; 105 106 case TypeCode.String: 107 IsString = true; 108 break; 109 110 case TypeCode.Object: 111 // So far only byte[] seems to be treated as a binary type 112 if (columnType.IsArray && columnType.GetArrayRank () == 1 && columnType.GetElementType () == typeof (byte)) 113 IsBinaryData = true; 114 break; 115 116 default: 117 TypeCode = TypeCode.Object; 118 break; 119 } 120 121 IsLongString = MaxLength > SHORT_STRING_MAX_LENGTH; 122 } 123 124 public bool ApplyFormatInEditMode { 125 get { 126 if (applyFormatInEditMode == null) 127 applyFormatInEditMode = CheckApplyFormatInEditMode (); 128 129 return (bool)applyFormatInEditMode; 130 } 131 } 132 133 public AttributeCollection Attributes { 134 get { 135 if (attributes == null) 136 attributes = LoadAttributes (); 137 138 return attributes; 139 } 140 141 } 142 143 public Type ColumnType { 144 get { return Provider.ColumnType; } 145 } 146 147 public bool ConvertEmptyStringToNull { 148 get { 149 if (convertEmptyStringToNull == null) 150 convertEmptyStringToNull = CheckConvertEmptyStringToNull (); 151 152 return (bool)convertEmptyStringToNull; 153 } 154 155 } 156 157 public string DataFormatString { 158 get { 159 if (dataFormatString == null) 160 dataFormatString = CheckDataFormatString (); 161 162 return dataFormatString; 163 } 164 } 165 166 public DataTypeAttribute DataTypeAttribute { 167 get { 168 if (!dataTypeReflected && dataTypeAttr == null) 169 dataTypeAttr = CheckDataTypeAttribute (); 170 171 return dataTypeAttr; 172 } 173 174 } 175 176 public Object DefaultValue { 177 get { 178 if (!defaultValueReflected && defaultValue == null) { 179 DefaultValueAttribute defaultValueAttr = CheckDefaultValueAttribute (); 180 if (defaultValueAttr != null) 181 defaultValue = defaultValueAttr.Value; 182 } 183 184 return defaultValue; 185 } 186 } 187 188 public string Description { 189 get { 190 if (!descriptionReflected && description == null) { 191 DescriptionAttribute descriptionAttr = CheckDescriptionAttribute (); 192 if (descriptionAttr != null) 193 description = descriptionAttr.Description; 194 } 195 196 return description; 197 } 198 } 199 200 public string DisplayName { 201 get { 202 if (displayName == null) 203 displayName = CheckDisplayName (); 204 205 return displayName; 206 } 207 } 208 209 public PropertyInfo EntityTypeProperty { 210 get { return Provider.EntityTypeProperty; } 211 } 212 213 public bool HtmlEncode { get; private set; } 214 215 public bool IsBinaryData { get; private set; } 216 217 public bool IsCustomProperty { 218 get { return Provider.IsCustomProperty; } 219 } 220 221 public bool IsFloatingPoint { get; private set; } 222 223 public bool IsForeignKeyComponent { 224 get { return Provider.IsForeignKeyComponent; } 225 } 226 227 public bool IsGenerated { 228 get { return Provider.IsGenerated; } 229 } 230 231 public bool IsInteger { get; private set; } 232 233 public bool IsLongString { get; private set; } 234 235 public bool IsPrimaryKey { 236 get { return Provider.IsPrimaryKey; } 237 } 238 239 public bool IsReadOnly { 240 get { 241 if (readOnly == null) 242 readOnly = CheckReadOnlyAttribute (); 243 244 return (bool)readOnly; 245 } 246 } 247 248 // It appears that all columns are required unless Provider.Nullable is true for 249 // them. We could skip checking for the RequiredAttribute for that reason, but that 250 // way we wouldn't be forward-compatible. 251 // What's more, it appears that a RequiredAttribute instance is always included in 252 // Attributes, whether or not the corresponding field is decorataed with it. 253 public bool IsRequired { 254 get { 255 if (!requiredReflected && requiredAttr == null) 256 requiredAttr = CheckRequiredAttribute (); 257 258 return requiredAttr != null; 259 } 260 } 261 262 public bool IsString { get; private set; } 263 264 public int MaxLength { 265 get { 266 if (maxLength == null) 267 maxLength = CheckMaxLength (); 268 269 return (int)maxLength; 270 } 271 } 272 273 public MetaModel Model { get; private set; } 274 275 public string Name { 276 get { return Provider.Name; } 277 } 278 279 public string NullDisplayText { 280 get { 281 if (nullDisplayText == null) 282 nullDisplayText = CheckNullDisplayText (); 283 284 return nullDisplayText; 285 } 286 } 287 288 public ColumnProvider Provider { get; private set; } 289 290 public string RequiredErrorMessage { 291 get { 292 if (requiredErrorMessage == null) { 293 RequiredAttribute attr = CheckRequiredAttribute (); 294 if (attr == null) 295 requiredErrorMessage = String.Empty; 296 else 297 requiredErrorMessage = attr.ErrorMessage; 298 } 299 300 return requiredErrorMessage; 301 } 302 } 303 304 public bool Scaffold { 305 get { 306 if (scaffold != null) 307 return (bool)scaffold; 308 if (scaffoldReflected != null) 309 return (bool)scaffoldReflected; 310 311 MetaModel.GetDataFieldAttribute <ScaffoldColumnAttribute> (Attributes, ref scaffoldAttr); 312 if (scaffoldAttr != null) { 313 scaffoldReflected = scaffoldAttr.Scaffold; 314 return (bool)scaffoldReflected; 315 } 316 317 string uiHint = UIHint; 318 if (!String.IsNullOrEmpty (uiHint)) 319 scaffoldReflected = true; 320 // LAMESPEC: IsForeignKeyComponent does NOT set Scaffold=false 321 else if (IsGenerated || IsCustomProperty) 322 scaffoldReflected = false; 323 else if (Table.ScaffoldAllTables) 324 scaffoldReflected = true; 325 else 326 scaffoldReflected = true; 327 328 return (bool)scaffoldReflected; 329 } 330 331 set { scaffold = value; } 332 } 333 334 public string SortExpression { 335 get { 336 ColumnProvider provider = Provider; 337 if (provider.IsSortable) 338 return Name; 339 340 return String.Empty; 341 } 342 } 343 344 public MetaTable Table { get; private set; } 345 346 public TypeCode TypeCode { get; private set; } 347 348 // LAMESPEC: if there's no attribute, null is returned 349 public string UIHint { 350 get { 351 if (!uiHintReflected && uiHint == null) 352 uiHint = CheckUIHintAttribute (); 353 354 return uiHint; 355 } 356 } 357 CheckUIHintAttribute()358 string CheckUIHintAttribute () 359 { 360 if (uiHintReflected) 361 return uiHint; 362 363 uiHintReflected = true; 364 UIHintAttribute attr = null; 365 MetaModel.GetDataFieldAttribute <UIHintAttribute> (Attributes, ref attr); 366 367 if (attr == null) 368 return null; 369 370 return attr.UIHint; 371 } 372 CheckApplyFormatInEditMode()373 bool CheckApplyFormatInEditMode () 374 { 375 var displayFormat = GetDisplayFormat (); 376 if (displayFormat == null) 377 return false; 378 379 return displayFormat.ApplyFormatInEditMode; 380 } 381 CheckConvertEmptyStringToNull()382 bool CheckConvertEmptyStringToNull () 383 { 384 var displayFormat = GetDisplayFormat (); 385 if (displayFormat == null) 386 return true; 387 388 return displayFormat.ConvertEmptyStringToNull; 389 } 390 CheckDataFormatString()391 string CheckDataFormatString () 392 { 393 var displayFormat = GetDisplayFormat (); 394 if (displayFormat == null) 395 return String.Empty; 396 397 return displayFormat.DataFormatString; 398 } 399 CheckDataTypeAttribute()400 DataTypeAttribute CheckDataTypeAttribute () 401 { 402 if (dataTypeReflected) 403 return dataTypeAttr; 404 405 dataTypeReflected = true; 406 MetaModel.GetDataFieldAttribute <DataTypeAttribute> (Attributes, ref dataTypeAttr); 407 if (dataTypeAttr == null && (ColumnType == typeof (string))) 408 return new DataTypeAttribute (IsLongString ? DataType.MultilineText : DataType.Text); 409 410 return dataTypeAttr; 411 } 412 CheckDefaultValueAttribute()413 DefaultValueAttribute CheckDefaultValueAttribute () 414 { 415 defaultValueReflected = true; 416 DefaultValueAttribute dummy = null; 417 MetaModel.GetDataFieldAttribute <DefaultValueAttribute> (Attributes, ref dummy); 418 if (dummy == null) 419 return null; 420 421 return dummy; 422 } 423 CheckDescriptionAttribute()424 DescriptionAttribute CheckDescriptionAttribute () 425 { 426 descriptionReflected = true; 427 DescriptionAttribute dummy = null; 428 MetaModel.GetDataFieldAttribute <DescriptionAttribute> (Attributes, ref dummy); 429 if (dummy == null) 430 return null; 431 432 return dummy; 433 } 434 CheckDisplayName()435 string CheckDisplayName () 436 { 437 DisplayNameAttribute attr = null; 438 MetaModel.GetDataFieldAttribute <DisplayNameAttribute> (Attributes, ref attr); 439 if (attr != null) 440 return attr.DisplayName; 441 442 return Name; 443 } 444 CheckRequiredAttribute()445 RequiredAttribute CheckRequiredAttribute () 446 { 447 if (requiredReflected) 448 return requiredAttr; 449 450 requiredReflected = true; 451 MetaModel.GetDataFieldAttribute <RequiredAttribute> (Attributes, ref requiredAttr); 452 453 return requiredAttr; 454 } 455 CheckReadOnlyAttribute()456 bool CheckReadOnlyAttribute () 457 { 458 ReadOnlyAttribute attr = null; 459 MetaModel.GetDataFieldAttribute <ReadOnlyAttribute> (Attributes, ref attr); 460 461 // Apparently attr.IsReadOnly and/or comparisons to 462 // ReadOnlyAttribute.{Yes,No} don't matter. The sole presence of the 463 // attribute marks column as read-only 464 return attr != null; 465 } 466 CheckMaxLength()467 int CheckMaxLength () 468 { 469 StringLengthAttribute attr = null; 470 MetaModel.GetDataFieldAttribute <StringLengthAttribute> (Attributes, ref attr); 471 472 if (attr != null) 473 return attr.MaximumLength; 474 475 return Provider.MaxLength; 476 } 477 CheckNullDisplayText()478 string CheckNullDisplayText () 479 { 480 DisplayFormatAttribute displayFormat = GetDisplayFormat (); 481 482 if (displayFormat == null) 483 return String.Empty; 484 485 return displayFormat.NullDisplayText; 486 } 487 GetDisplayFormat()488 DisplayFormatAttribute GetDisplayFormat () 489 { 490 MetaModel.GetDataFieldAttribute <DisplayFormatAttribute> (Attributes, ref displayFormatAttr); 491 if (displayFormatAttr == null) { 492 var dta = DataTypeAttribute; 493 displayFormatAttr = dta == null ? null : dta.DisplayFormat; 494 } 495 496 return displayFormatAttr; 497 } 498 Init()499 internal virtual void Init () 500 { 501 } 502 LoadAttributes()503 AttributeCollection LoadAttributes () 504 { 505 var props = MetaModel.GetTypeDescriptor (Table.EntityType).GetProperties (); 506 AttributeCollection reflected; 507 508 int propsCount = props == null ? 0 : props.Count; 509 if (propsCount == 0) 510 reflected = AttributeCollection.Empty; 511 else { 512 var property = props.Find (Name, true); 513 if (property == null) 514 reflected = AttributeCollection.Empty; 515 else 516 reflected = property.Attributes; 517 } 518 519 if (!Provider.Nullable && reflected.OfType <RequiredAttribute> ().Count () == 0) 520 reflected = AttributeCollection.FromExisting (reflected, new Attribute[] { new RequiredAttribute () }); 521 522 return reflected; 523 } 524 ToString()525 public override string ToString () 526 { 527 return Name; 528 } 529 } 530 } 531