001 // Copyright 2004, 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; 016 017 import org.apache.tapestry.IMarkupWriter; 018 import org.apache.tapestry.IRequestCycle; 019 import org.apache.tapestry.Tapestry; 020 import org.apache.tapestry.valid.ValidatorException; 021 022 /** 023 * A component used to render a drop-down list of options that the user may select. [ <a 024 * href="../../../../../ComponentReference/PropertySelection.html">Component Reference </a>] 025 * <p> 026 * Earlier versions of PropertySelection (through release 2.2) were more flexible, they included a 027 * <b>renderer </b> property that controlled how the selection was rendered. Ultimately, this proved 028 * of little value and this portion of functionality was deprecated in 2.3 and will be removed in 029 * 2.3. 030 * <p> 031 * Typically, the values available to be selected are defined using an 032 * {@link org.apache.commons.lang.enum.Enum}. A PropertySelection is dependent on an 033 * {@link IPropertySelectionModel} to provide the list of possible values. 034 * <p> 035 * Often, this is used to select a particular {@link org.apache.commons.lang.enum.Enum} to assign to 036 * a property; the {@link EnumPropertySelectionModel} class simplifies this. 037 * <p> 038 * Often, a drop-down list will contain an initial option that serves both as a label and to represent 039 * that nothing is selected. This can behavior can easily be achieved by decorating an existing 040 * {@link IPropertySelectionModel} with a {@link LabeledPropertySelectionModel}. 041 * <p> 042 * As of 4.0, this component can be validated. 043 * 044 * @author Howard Lewis Ship 045 * @author Paul Ferraro 046 */ 047 public abstract class PropertySelection extends AbstractFormComponent implements ValidatableField 048 { 049 /** 050 * @see org.apache.tapestry.form.AbstractFormComponent#renderFormComponent(org.apache.tapestry.IMarkupWriter, org.apache.tapestry.IRequestCycle) 051 */ 052 protected void renderFormComponent(IMarkupWriter writer, IRequestCycle cycle) 053 { 054 renderDelegatePrefix(writer, cycle); 055 056 writer.begin("select"); 057 writer.attribute("name", getName()); 058 059 if (isDisabled()) 060 writer.attribute("disabled", "disabled"); 061 062 if (getSubmitOnChange()) 063 writer.attribute("onchange", "javascript: this.form.events.submit();"); 064 065 renderIdAttribute(writer, cycle); 066 067 renderDelegateAttributes(writer, cycle); 068 069 getValidatableFieldSupport().renderContributions(this, writer, cycle); 070 071 // Apply informal attributes. 072 renderInformalParameters(writer, cycle); 073 074 writer.println(); 075 076 IPropertySelectionModel model = getModel(); 077 078 if (model == null) 079 throw Tapestry.createRequiredParameterException(this, "model"); 080 081 int count = model.getOptionCount(); 082 boolean foundSelected = false; 083 Object value = getValue(); 084 085 for (int i = 0; i < count; i++) 086 { 087 Object option = model.getOption(i); 088 089 writer.begin("option"); 090 writer.attribute("value", model.getValue(i)); 091 092 if (!foundSelected && isEqual(option, value)) 093 { 094 writer.attribute("selected", "selected"); 095 096 foundSelected = true; 097 } 098 099 writer.print(model.getLabel(i)); 100 101 writer.end(); 102 103 writer.println(); 104 } 105 106 writer.end(); // <select> 107 108 renderDelegateSuffix(writer, cycle); 109 } 110 111 /** 112 * @see org.apache.tapestry.form.AbstractFormComponent#rewindFormComponent(org.apache.tapestry.IMarkupWriter, org.apache.tapestry.IRequestCycle) 113 */ 114 protected void rewindFormComponent(IMarkupWriter writer, IRequestCycle cycle) 115 { 116 String value = cycle.getParameter(getName()); 117 118 Object object = (value == null) ? null : getModel().translateValue(value); 119 120 try 121 { 122 getValidatableFieldSupport().validate(this, writer, cycle, object); 123 124 setValue(object); 125 } 126 catch (ValidatorException e) 127 { 128 getForm().getDelegate().record(e); 129 } 130 } 131 132 private boolean isEqual(Object left, Object right) 133 { 134 // Both null, or same object, then are equal 135 136 if (left == right) 137 return true; 138 139 // If one is null, the other isn't, then not equal. 140 141 if (left == null || right == null) 142 return false; 143 144 // Both non-null; use standard comparison. 145 146 return left.equals(right); 147 } 148 149 public abstract IPropertySelectionModel getModel(); 150 151 /** @since 2.2 * */ 152 public abstract boolean getSubmitOnChange(); 153 154 /** @since 2.2 * */ 155 public abstract Object getValue(); 156 157 /** @since 2.2 * */ 158 public abstract void setValue(Object value); 159 160 /** 161 * Injected. 162 */ 163 public abstract ValidatableFieldSupport getValidatableFieldSupport(); 164 165 /** 166 * @see org.apache.tapestry.form.AbstractFormComponent#isRequired() 167 */ 168 public boolean isRequired() 169 { 170 return getValidatableFieldSupport().isRequired(this); 171 } 172 }