Removed untyped contructor from ComponentRegistration and add a protected setter.
[castle.git] / MonoRail / Castle.MonoRail.ActiveRecordSupport / Scaffold / Helpers / ARFormHelper.cs
blob743d9acb62999fc9a267e519e9e4f66c2ec92a01
1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
2 //
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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
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.ActiveRecordSupport.Scaffold.Helpers
17 using System;
18 using System.Collections;
19 using System.Collections.Specialized;
20 using System.Text;
21 using System.Reflection;
22 using Castle.ActiveRecord;
23 using Castle.ActiveRecord.Framework.Internal;
24 using Castle.MonoRail.Framework.Helpers;
26 public class ARFormHelper : FormHelper
28 private StringBuilder stringBuilder = new StringBuilder(1024);
30 private IDictionary model2nestedInstance = new Hashtable();
32 private static readonly int[] Months = { 1,2,3,4,5,6,7,8,9,10,11,12 };
33 private static readonly int[] Days = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
34 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
35 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
36 private static readonly int[] Years;
37 private TextHelper textHelper = new TextHelper();
39 static ARFormHelper()
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 TextHelper TextHelper
53 get { return textHelper; }
56 public ICollection GetModelHierarchy(ActiveRecordModel model, object instance)
58 ArrayList list = new ArrayList();
60 ActiveRecordModel hierarchy = model;
62 while(hierarchy != null)
64 list.Add(hierarchy);
66 hierarchy = ActiveRecordModel.GetModel(hierarchy.Type.BaseType);
69 hierarchy = model;
71 while(hierarchy != null)
73 foreach(NestedModel nested in hierarchy.Components)
75 object nestedInstance = nested.Property.GetValue(instance, null);
77 if (nestedInstance == null)
79 nestedInstance = CreationUtil.Create(nested.Property.PropertyType);
82 if (nestedInstance != null)
84 model2nestedInstance[nested.Model] = nestedInstance;
87 list.Add(nested.Model);
90 hierarchy = ActiveRecordModel.GetModel(hierarchy.Type.BaseType);
93 return list;
96 #region CanHandle methods
98 public bool CanHandle(FieldModel field)
100 return CanHandleType(field.Field.FieldType);
103 public bool CanHandle(PropertyModel propModel)
105 return CanHandleType(propModel.Property.PropertyType);
108 public bool CanHandle(PropertyInfo propInfo)
110 return CanHandleType(propInfo.PropertyType);
113 public bool CanHandle(BelongsToModel model)
115 return CheckModelAndKeyAreAccessible(model.BelongsToAtt.Type);
118 public bool CanHandle(HasManyModel model)
120 if (!model.HasManyAtt.Inverse)
122 return CheckModelAndKeyAreAccessible(model.HasManyAtt.MapType);
124 return false;
127 public bool CanHandle(HasAndBelongsToManyModel model)
129 if (!model.HasManyAtt.Inverse)
131 return CheckModelAndKeyAreAccessible(model.HasManyAtt.MapType);
133 return false;
136 private bool CheckModelAndKeyAreAccessible(Type type)
138 ActiveRecordModel otherModel = ActiveRecordModel.GetModel(type);
140 PrimaryKeyModel keyModel = ObtainPKProperty(otherModel);
142 if (otherModel == null || keyModel == null)
144 return false;
147 return true;
150 private PrimaryKeyModel ObtainPKProperty(ActiveRecordModel model)
152 if (model == null) return null;
154 ActiveRecordModel curModel = model;
156 while(curModel != null)
158 PrimaryKeyModel keyModel = curModel.PrimaryKey;
160 if (keyModel != null)
162 return keyModel;
165 curModel = curModel.Parent;
168 return null;
171 private bool CanHandleType(Type type)
173 return (type.IsPrimitive ||
174 type == typeof(String) ||
175 type == typeof(Decimal) ||
176 type == typeof(Single) ||
177 type == typeof(Double) ||
178 type == typeof(Byte) ||
179 type == typeof(SByte) ||
180 type == typeof(bool) ||
181 type == typeof(Enum) ||
182 type == typeof(DateTime));
185 #endregion
187 #region CreateControl methods
189 public String CreateControl(ActiveRecordModel model, String prefix,
190 FieldModel fieldModel, object instance)
192 stringBuilder.Length = 0;
194 FieldInfo fieldInfo = fieldModel.Field;
196 String propName = CreatePropName(model, prefix, fieldInfo.Name);
198 if (fieldInfo.FieldType == typeof(DateTime))
200 stringBuilder.Append(LabelFor(propName + "day", TextHelper.PascalCaseToWord(fieldInfo.Name) + ": &nbsp;"));
202 else
204 stringBuilder.Append(LabelFor(propName, TextHelper.PascalCaseToWord(fieldInfo.Name) + ": &nbsp;"));
207 FieldAttribute propAtt = fieldModel.FieldAtt;
209 RenderAppropriateControl(model, fieldInfo.FieldType, propName, null, null,
210 propAtt.Unique, propAtt.NotNull, propAtt.ColumnType, propAtt.Length);
212 return stringBuilder.ToString();
215 public String CreateControl(ActiveRecordModel model, String prefix,
216 PropertyModel propertyModel, object instance)
218 stringBuilder.Length = 0;
220 PropertyInfo prop = propertyModel.Property;
222 // Skip non standard properties
223 if (!prop.CanWrite || !prop.CanRead) return String.Empty;
225 // Skip indexers
226 if (prop.GetIndexParameters().Length != 0) return String.Empty;
228 String propName = CreatePropName(model, prefix, prop.Name);
230 if (prop.PropertyType == typeof(DateTime))
232 stringBuilder.Append(LabelFor(propName + "day", TextHelper.PascalCaseToWord(prop.Name) + ": &nbsp;"));
234 else
236 stringBuilder.Append(LabelFor(propName, TextHelper.PascalCaseToWord(prop.Name) + ": &nbsp;"));
239 PropertyAttribute propAtt = propertyModel.PropertyAtt;
241 RenderAppropriateControl(model, prop.PropertyType, propName, prop, null,
242 propAtt.Unique, propAtt.NotNull, propAtt.ColumnType, propAtt.Length);
244 return stringBuilder.ToString();
247 public String CreateControl(ActiveRecordModel model, String prefix,
248 PropertyInfo prop, object instance)
250 stringBuilder.Length = 0;
252 // Skip non standard properties
253 if (!prop.CanWrite || !prop.CanRead) return String.Empty;
255 // Skip indexers
256 if (prop.GetIndexParameters().Length != 0) return String.Empty;
258 String propName = CreatePropName(model, prefix, prop.Name);
260 if (prop.PropertyType == typeof(DateTime))
262 stringBuilder.Append(LabelFor(propName + "day", TextHelper.PascalCaseToWord(prop.Name) + ": &nbsp;"));
264 else
266 stringBuilder.Append(LabelFor(propName, TextHelper.PascalCaseToWord(prop.Name) + ": &nbsp;"));
269 RenderAppropriateControl(model, prop.PropertyType,
270 propName, prop, null, false, false, null, 0);
272 return stringBuilder.ToString();
275 public String CreateControl(ActiveRecordModel model, String prefix,
276 BelongsToModel belongsToModel, object instance)
278 stringBuilder.Length = 0;
280 PropertyInfo prop = belongsToModel.Property;
282 prefix += "." + prop.Name;
284 ActiveRecordModel otherModel = ActiveRecordModel.GetModel(belongsToModel.BelongsToAtt.Type);
286 PrimaryKeyModel keyModel = ObtainPKProperty(otherModel);
288 if (otherModel == null || keyModel == null)
290 return "Model not found or PK not found";
293 object[] items = CommonOperationUtils.FindAll(otherModel.Type);
295 String propName = CreatePropName(model, prefix, keyModel.Property.Name);
297 stringBuilder.Append(LabelFor(propName, TextHelper.PascalCaseToWord(prop.Name) + ": &nbsp;"));
299 IDictionary attrs = new HybridDictionary(true);
301 attrs["value"] = keyModel.Property.Name;
303 if (!belongsToModel.BelongsToAtt.NotNull)
305 attrs.Add("firstOption", "Empty");
306 attrs.Add("firstOptionValue", "");
309 stringBuilder.Append(Select(propName, items, attrs));
311 return stringBuilder.ToString();
314 public String CreateControl(ActiveRecordModel model, String prefix,
315 HasManyModel hasManyModel, object instance)
317 stringBuilder.Length = 0;
319 PropertyInfo prop = hasManyModel.Property;
321 prefix += "." + prop.Name;
323 ActiveRecordModel otherModel = ActiveRecordModel.GetModel(hasManyModel.HasManyAtt.MapType);
325 PrimaryKeyModel keyModel = ObtainPKProperty(otherModel);
327 if (otherModel == null || keyModel == null)
329 return "Model not found or PK not found";
332 object[] source = CommonOperationUtils.FindAll(otherModel.Type);
334 stringBuilder.Append(prop.Name + ": &nbsp;");
335 stringBuilder.Append("<br/>\r\n");
337 IDictionary attrs = new HybridDictionary(true);
339 attrs["value"] = keyModel.Property.Name;
341 FormHelper.CheckboxList list = CreateCheckboxList(prefix, source, attrs);
343 foreach(object item in list)
345 stringBuilder.Append(list.Item());
347 stringBuilder.Append(item.ToString());
349 stringBuilder.Append("<br/>\r\n");
352 return stringBuilder.ToString();
355 public String CreateControl(ActiveRecordModel model, String prefix,
356 HasAndBelongsToManyModel hasAndBelongsModel, object instance)
358 stringBuilder.Length = 0;
360 PropertyInfo prop = hasAndBelongsModel.Property;
362 prefix += "." + prop.Name;
364 ActiveRecordModel otherModel = ActiveRecordModel.GetModel(hasAndBelongsModel.HasManyAtt.MapType);
366 PrimaryKeyModel keyModel = ObtainPKProperty(otherModel);
368 if (otherModel == null || keyModel == null)
370 return "Model not found or PK not found";
373 object[] source = CommonOperationUtils.FindAll(otherModel.Type);
375 stringBuilder.Append(prop.Name + ": &nbsp;");
376 stringBuilder.Append("<br/>\r\n");
378 IDictionary attrs = new HybridDictionary(true);
380 attrs["value"] = keyModel.Property.Name;
382 FormHelper.CheckboxList list = CreateCheckboxList(prefix, source, attrs);
384 foreach(object item in list)
386 stringBuilder.Append(list.Item());
388 stringBuilder.Append(item.ToString());
390 stringBuilder.Append("<br/>\r\n");
393 return stringBuilder.ToString();
396 #endregion
398 private void RenderAppropriateControl(ActiveRecordModel model,
399 Type propType, string propName, PropertyInfo property,
400 object value, bool unique, bool notNull, String columnType, int length)
402 IDictionary htmlAttributes = new Hashtable();
404 if (propType == typeof(String))
406 if (String.Compare("stringclob", columnType, true) == 0)
408 stringBuilder.AppendFormat(TextArea(propName));
410 else
412 if (length > 0)
414 htmlAttributes["maxlength"] = length.ToString();
417 stringBuilder.AppendFormat(TextField(propName, htmlAttributes));
420 else if (propType == typeof(Int16) || propType == typeof(Int32) || propType == typeof(Int64))
422 stringBuilder.AppendFormat(NumberField(propName, htmlAttributes));
424 else if (propType == typeof(Single) || propType == typeof(Double) || propType == typeof(Decimal))
426 stringBuilder.AppendFormat(NumberField(propName, htmlAttributes));
428 else if (propType == typeof(DateTime))
430 stringBuilder.AppendFormat(Select(propName + "month", Months, htmlAttributes));
431 stringBuilder.AppendFormat(Select(propName + "day", Days, htmlAttributes));
432 stringBuilder.AppendFormat(Select(propName + "year", Years, htmlAttributes));
434 else if (propType == typeof(bool))
436 stringBuilder.Append(CheckboxField(propName));
438 else if (propType == typeof(Enum))
440 // TODO: Support flags as well
442 String[] names = System.Enum.GetNames(propType);
444 IList options = new ArrayList();
446 foreach(String name in names)
448 options.Add(String.Format("{0} {1}\r\n",
449 RadioField(propName, name), LabelFor(name, TextHelper.PascalCaseToWord(name))));
454 private static string CreatePropName(ActiveRecordModel model, String prefix, String name)
456 string propName;
458 if (model.IsNestedType)
460 propName = String.Format("{0}.{1}.{2}", prefix, model.ParentNested.Property.Name, name);
462 else
464 propName = String.Format("{0}.{1}", prefix, name);
467 return propName;