001 // Copyright 2005 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.tapestry.form.translator; 016 017 import org.apache.hivemind.util.PropertyUtils; 018 import org.apache.tapestry.IMarkupWriter; 019 import org.apache.tapestry.IRequestCycle; 020 import org.apache.tapestry.form.FormComponentContributorContext; 021 import org.apache.tapestry.form.IFormComponent; 022 import org.apache.tapestry.json.JSONLiteral; 023 import org.apache.tapestry.json.JSONObject; 024 import org.apache.tapestry.valid.ValidationConstants; 025 import org.apache.tapestry.valid.ValidationConstraint; 026 import org.apache.tapestry.valid.ValidationStrings; 027 028 import java.text.DecimalFormat; 029 import java.text.DecimalFormatSymbols; 030 import java.text.Format; 031 import java.util.Locale; 032 033 /** 034 * A {@link java.text.DecimalFormat}-based {@link Translator} implementation. 035 * 036 * @author Paul Ferraro 037 * @since 4.0 038 */ 039 public class NumberTranslator extends FormatTranslator 040 { 041 private boolean _omitZero = false; 042 043 public NumberTranslator() 044 { 045 } 046 047 //TODO: Needed until HIVEMIND-134 fix is available 048 public NumberTranslator(String initializer) 049 { 050 PropertyUtils.configureProperties(this, initializer); 051 } 052 053 protected String formatObject(IFormComponent field, Locale locale, Object object) 054 { 055 Number number = (Number) object; 056 057 if (_omitZero) 058 { 059 if (number.doubleValue() == 0) 060 return ""; 061 } 062 063 return super.formatObject(field, locale, object); 064 } 065 066 protected Object getValueForEmptyInput() 067 { 068 return _omitZero ? null : new Double(0); 069 } 070 071 /** 072 * @see org.apache.tapestry.form.translator.FormatTranslator#defaultPattern() 073 */ 074 protected String defaultPattern() 075 { 076 return "#"; 077 } 078 079 /** 080 * @see org.apache.tapestry.form.translator.FormatTranslator#getFormat(java.util.Locale) 081 */ 082 protected Format getFormat(Locale locale) 083 { 084 return getDecimalFormat(locale); 085 } 086 087 public DecimalFormat getDecimalFormat(Locale locale) 088 { 089 return new DecimalFormat(getPattern(), new DecimalFormatSymbols(locale)); 090 } 091 092 /** 093 * @see org.apache.tapestry.form.translator.FormatTranslator#getMessageKey() 094 */ 095 protected String getMessageKey() 096 { 097 return ValidationStrings.INVALID_NUMBER; 098 } 099 100 /** 101 * @see org.apache.tapestry.form.translator.AbstractTranslator#getMessageParameters(java.util.Locale, 102 * java.lang.String) 103 */ 104 protected Object[] getMessageParameters(Locale locale, String label) 105 { 106 String pattern = getDecimalFormat(locale).toLocalizedPattern(); 107 108 return new Object[] { label, pattern }; 109 } 110 111 /** 112 * @see org.apache.tapestry.form.FormComponentContributor#renderContribution(org.apache.tapestry.IMarkupWriter, 113 * org.apache.tapestry.IRequestCycle, FormComponentContributorContext, 114 * org.apache.tapestry.form.IFormComponent) 115 */ 116 public void renderContribution(IMarkupWriter writer, IRequestCycle cycle, 117 FormComponentContributorContext context, IFormComponent field) 118 { 119 super.renderContribution(writer, cycle, context, field); 120 121 String message = buildMessage(context, field, getMessageKey()); 122 123 JSONObject profile = context.getProfile(); 124 if (!profile.has(ValidationConstants.CONSTRAINTS)) { 125 profile.put(ValidationConstants.CONSTRAINTS, new JSONObject()); 126 } 127 JSONObject cons = profile.getJSONObject(ValidationConstants.CONSTRAINTS); 128 129 context.addInitializationScript(field, "dojo.require(\"dojo.i18n.number\");"); 130 131 DecimalFormat format = getDecimalFormat(context.getLocale()); 132 133 String grouping = ""; 134 if (format.isGroupingUsed()) { 135 136 grouping += ",separator:" + JSONObject.quote(format.getDecimalFormatSymbols().getGroupingSeparator()); 137 grouping += ",groupSize:" + format.getGroupingSize(); 138 } else { 139 140 grouping += ",separator:\"\""; 141 } 142 143 cons.accumulate(field.getClientId(), 144 new JSONLiteral("[dojo.i18n.number.isReal,null,{" 145 + "places:" + format.getMaximumFractionDigits() + "," 146 + "decimal:" 147 + JSONObject.quote(format.getDecimalFormatSymbols().getDecimalSeparator()) 148 + grouping 149 + "}]")); 150 151 accumulateProfileProperty(field, profile, ValidationConstants.CONSTRAINTS, message); 152 } 153 154 /** 155 * @see org.apache.tapestry.form.translator.FormatTranslator#getConstraint() 156 */ 157 protected ValidationConstraint getConstraint() 158 { 159 return ValidationConstraint.NUMBER_FORMAT; 160 } 161 162 /** 163 * If true (which is the default for the property), then values that are 0 are rendered to an 164 * empty string, not "0" or "0.00". This is useful in most cases where the field is optional; it 165 * allows the field to render blank when no value is present. 166 * 167 * @param omitZero 168 * Whether or not to omit zero. 169 */ 170 171 public void setOmitZero(boolean omitZero) 172 { 173 _omitZero = omitZero; 174 } 175 176 public boolean isOmitZero() 177 { 178 return _omitZero; 179 } 180 }