1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.MonoRail
.ActiveRecordScaffold
.Helpers
18 using System
.Collections
;
19 using System
.Collections
.Specialized
;
21 using System
.Reflection
;
22 using Castle
.ActiveRecord
;
23 using Castle
.ActiveRecord
.Framework
.Internal
;
24 using Castle
.MonoRail
.Framework
;
25 using Castle
.MonoRail
.Framework
.Helpers
;
27 public class ARFormHelper
: FormHelper
29 private StringBuilder stringBuilder
= new StringBuilder(1024);
31 private IDictionary model2nestedInstance
= new Hashtable();
33 private static readonly int[] Months
= { 1,2,3,4,5,6,7,8,9,10,11,12 }
;
34 private static readonly int[] Days
= { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
35 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
36 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
37 private static readonly int[] Years
;
41 int lastYear
= DateTime
.Now
.Year
;
43 Years
= new int[lastYear
- 1950 + 50];
45 for(int year
= 1950; year
< lastYear
+ 50; year
++)
47 Years
[year
- 1950] = year
;
51 public ICollection
GetModelHierarchy(ActiveRecordModel model
, object instance
)
53 ArrayList list
= new ArrayList();
55 ActiveRecordModel hierarchy
= model
;
57 while(hierarchy
!= null)
61 hierarchy
= ActiveRecordModel
.GetModel(hierarchy
.Type
.BaseType
);
66 while(hierarchy
!= null)
68 foreach(NestedModel nested
in hierarchy
.Components
)
70 object nestedInstance
= nested
.Property
.GetValue(instance
, null);
72 if (nestedInstance
== null)
74 nestedInstance
= CreationUtil
.Create(nested
.Property
.PropertyType
);
77 if (nestedInstance
!= null)
79 model2nestedInstance
[nested
.Model
] = nestedInstance
;
82 list
.Add(nested
.Model
);
85 hierarchy
= ActiveRecordModel
.GetModel(hierarchy
.Type
.BaseType
);
91 #region CanHandle methods
93 public bool CanHandle(FieldModel field
)
95 return CanHandleType(field
.Field
.FieldType
);
98 public bool CanHandle(PropertyModel propModel
)
100 return CanHandleType(propModel
.Property
.PropertyType
);
103 public bool CanHandle(PropertyInfo propInfo
)
105 return CanHandleType(propInfo
.PropertyType
);
108 public bool CanHandle(BelongsToModel model
)
110 return CheckModelAndKeyAreAccessible(model
.BelongsToAtt
.Type
);
113 public bool CanHandle(HasManyModel model
)
115 if (!model
.HasManyAtt
.Inverse
)
117 return CheckModelAndKeyAreAccessible(model
.HasManyAtt
.MapType
);
122 public bool CanHandle(HasAndBelongsToManyModel model
)
124 if (!model
.HasManyAtt
.Inverse
)
126 return CheckModelAndKeyAreAccessible(model
.HasManyAtt
.MapType
);
131 private bool CheckModelAndKeyAreAccessible(Type type
)
133 ActiveRecordModel otherModel
= ActiveRecordModel
.GetModel(type
);
135 PrimaryKeyModel keyModel
= ObtainPKProperty(otherModel
);
137 if (otherModel
== null || keyModel
== null)
145 private PrimaryKeyModel
ObtainPKProperty(ActiveRecordModel model
)
147 if (model
== null) return null;
149 ActiveRecordModel curModel
= model
;
151 while(curModel
!= null)
153 PrimaryKeyModel keyModel
= curModel
.PrimaryKey
;
155 if (keyModel
!= null)
160 curModel
= curModel
.Parent
;
166 private bool CanHandleType(Type type
)
168 return (type
.IsPrimitive
||
169 type
== typeof(String
) ||
170 type
== typeof(Decimal
) ||
171 type
== typeof(Single
) ||
172 type
== typeof(Double
) ||
173 type
== typeof(Byte
) ||
174 type
== typeof(SByte
) ||
175 type
== typeof(bool) ||
176 type
== typeof(Enum
) ||
177 type
== typeof(DateTime
));
182 #region CreateControl methods
184 public String
CreateControl(ActiveRecordModel model
, String prefix
,
185 FieldModel fieldModel
, object instance
)
187 stringBuilder
.Length
= 0;
189 FieldInfo fieldInfo
= fieldModel
.Field
;
191 String propName
= CreatePropName(model
, prefix
, fieldInfo
.Name
);
193 if (fieldInfo
.FieldType
== typeof(DateTime
))
195 stringBuilder
.Append(LabelFor(propName
+ "day", fieldInfo
.Name
+ ": "));
199 stringBuilder
.Append(LabelFor(propName
, fieldInfo
.Name
+ ": "));
202 FieldAttribute propAtt
= fieldModel
.FieldAtt
;
204 RenderAppropriateControl(model
, fieldInfo
.FieldType
, propName
, null, null,
205 propAtt
.Unique
, propAtt
.NotNull
, propAtt
.ColumnType
, propAtt
.Length
);
207 return stringBuilder
.ToString();
210 public String
CreateControl(ActiveRecordModel model
, String prefix
,
211 PropertyModel propertyModel
, object instance
)
213 stringBuilder
.Length
= 0;
215 PropertyInfo prop
= propertyModel
.Property
;
217 // Skip non standard properties
218 if (!prop
.CanWrite
|| !prop
.CanRead
) return String
.Empty
;
221 if (prop
.GetIndexParameters().Length
!= 0) return String
.Empty
;
223 String propName
= CreatePropName(model
, prefix
, prop
.Name
);
225 if (prop
.PropertyType
== typeof(DateTime
))
227 stringBuilder
.Append(LabelFor(propName
+ "day", prop
.Name
+ ": "));
231 stringBuilder
.Append(LabelFor(propName
, prop
.Name
+ ": "));
234 PropertyAttribute propAtt
= propertyModel
.PropertyAtt
;
236 RenderAppropriateControl(model
, prop
.PropertyType
, propName
, prop
, null,
237 propAtt
.Unique
, propAtt
.NotNull
, propAtt
.ColumnType
, propAtt
.Length
);
239 return stringBuilder
.ToString();
242 public String
CreateControl(ActiveRecordModel model
, String prefix
,
243 PropertyInfo prop
, object instance
)
245 stringBuilder
.Length
= 0;
247 // Skip non standard properties
248 if (!prop
.CanWrite
|| !prop
.CanRead
) return String
.Empty
;
251 if (prop
.GetIndexParameters().Length
!= 0) return String
.Empty
;
253 String propName
= CreatePropName(model
, prefix
, prop
.Name
);
255 if (prop
.PropertyType
== typeof(DateTime
))
257 stringBuilder
.Append(LabelFor(propName
+ "day", prop
.Name
+ ": "));
261 stringBuilder
.Append(LabelFor(propName
, prop
.Name
+ ": "));
264 RenderAppropriateControl(model
, prop
.PropertyType
,
265 propName
, prop
, null, false, false, null, 0);
267 return stringBuilder
.ToString();
270 public String
CreateControl(ActiveRecordModel model
, String prefix
,
271 BelongsToModel belongsToModel
, object instance
)
273 stringBuilder
.Length
= 0;
275 PropertyInfo prop
= belongsToModel
.Property
;
277 prefix
+= "." + prop
.Name
;
279 ActiveRecordModel otherModel
= ActiveRecordModel
.GetModel(belongsToModel
.BelongsToAtt
.Type
);
281 PrimaryKeyModel keyModel
= ObtainPKProperty(otherModel
);
283 if (otherModel
== null || keyModel
== null)
285 return "Model not found or PK not found";
288 object[] items
= CommonOperationUtils
.FindAll(otherModel
.Type
);
290 String propName
= CreatePropName(model
, prefix
, keyModel
.Property
.Name
);
292 stringBuilder
.Append(LabelFor(propName
, prop
.Name
+ ": "));
294 IDictionary attrs
= new HybridDictionary(true);
296 attrs
["value"] = keyModel
.Property
.Name
;
298 if (!belongsToModel
.BelongsToAtt
.NotNull
)
300 attrs
.Add("firstOption", "Empty");
301 attrs
.Add("firstOptionValue", "");
304 stringBuilder
.Append(Select(propName
, items
, attrs
));
306 return stringBuilder
.ToString();
309 public String
CreateControl(ActiveRecordModel model
, String prefix
,
310 HasManyModel hasManyModel
, object instance
)
312 stringBuilder
.Length
= 0;
314 PropertyInfo prop
= hasManyModel
.Property
;
316 prefix
+= "." + prop
.Name
;
318 ActiveRecordModel otherModel
= ActiveRecordModel
.GetModel(hasManyModel
.HasManyAtt
.MapType
);
320 PrimaryKeyModel keyModel
= ObtainPKProperty(otherModel
);
322 if (otherModel
== null || keyModel
== null)
324 return "Model not found or PK not found";
327 object[] source
= CommonOperationUtils
.FindAll(otherModel
.Type
);
329 stringBuilder
.Append(prop
.Name
+ ": ");
330 stringBuilder
.Append("<br/>\r\n");
332 IDictionary attrs
= new HybridDictionary(true);
334 attrs
["value"] = keyModel
.Property
.Name
;
336 FormHelper
.CheckboxList list
= CreateCheckboxList(prefix
, source
, attrs
);
338 foreach(object item
in list
)
340 stringBuilder
.Append(list
.Item());
342 stringBuilder
.Append(item
.ToString());
344 stringBuilder
.Append("<br/>\r\n");
347 return stringBuilder
.ToString();
350 public String
CreateControl(ActiveRecordModel model
, String prefix
,
351 HasAndBelongsToManyModel hasAndBelongsModel
, object instance
)
353 stringBuilder
.Length
= 0;
355 PropertyInfo prop
= hasAndBelongsModel
.Property
;
357 prefix
+= "." + prop
.Name
;
359 ActiveRecordModel otherModel
= ActiveRecordModel
.GetModel(hasAndBelongsModel
.HasManyAtt
.MapType
);
361 PrimaryKeyModel keyModel
= ObtainPKProperty(otherModel
);
363 if (otherModel
== null || keyModel
== null)
365 return "Model not found or PK not found";
368 object[] source
= CommonOperationUtils
.FindAll(otherModel
.Type
);
370 stringBuilder
.Append(prop
.Name
+ ": ");
371 stringBuilder
.Append("<br/>\r\n");
373 IDictionary attrs
= new HybridDictionary(true);
375 attrs
["value"] = keyModel
.Property
.Name
;
377 FormHelper
.CheckboxList list
= CreateCheckboxList(prefix
, source
, attrs
);
379 foreach(object item
in list
)
381 stringBuilder
.Append(list
.Item());
383 stringBuilder
.Append(item
.ToString());
385 stringBuilder
.Append("<br/>\r\n");
388 return stringBuilder
.ToString();
393 private void RenderAppropriateControl(ActiveRecordModel model
,
394 Type propType
, string propName
, PropertyInfo property
,
395 object value, bool unique
, bool notNull
, String columnType
, int length
)
397 IDictionary htmlAttributes
= new Hashtable();
399 if (propType
== typeof(String
))
401 if (String
.Compare("stringclob", columnType
, true) == 0)
403 stringBuilder
.AppendFormat(TextArea(propName
));
409 htmlAttributes
["maxlength"] = length
.ToString();
412 stringBuilder
.AppendFormat(TextField(propName
, htmlAttributes
));
415 else if (propType
== typeof(Int16
) || propType
== typeof(Int32
) || propType
== typeof(Int64
))
417 stringBuilder
.AppendFormat(NumberField(propName
, htmlAttributes
));
419 else if (propType
== typeof(Single
) || propType
== typeof(Double
))
421 stringBuilder
.AppendFormat(NumberField(propName
, htmlAttributes
));
423 else if (propType
== typeof(DateTime
))
425 stringBuilder
.AppendFormat(Select(propName
+ "month", Months
, htmlAttributes
));
426 stringBuilder
.AppendFormat(Select(propName
+ "day", Days
, htmlAttributes
));
427 stringBuilder
.AppendFormat(Select(propName
+ "year", Years
, htmlAttributes
));
429 else if (propType
== typeof(bool))
431 stringBuilder
.Append(CheckboxField(propName
));
433 else if (propType
== typeof(Enum
))
435 // TODO: Support flags as well
437 String
[] names
= System
.Enum
.GetNames(propType
);
439 IList options
= new ArrayList();
441 foreach(String name
in names
)
443 options
.Add(String
.Format("{0} {1}\r\n",
444 RadioField(propName
, name
), LabelFor(name
, name
)));
449 private static string CreatePropName(ActiveRecordModel model
, String prefix
, String name
)
453 if (model
.IsNestedType
)
455 propName
= String
.Format("{0}.{1}.{2}", prefix
, model
.Type
.Name
, name
);
459 propName
= String
.Format("{0}.{1}", prefix
, name
);