001 /* 002 * Copyright 2002-2004 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016 package org.springframework.richclient.form.builder; 017 018 import java.util.HashMap; 019 import java.util.Map; 020 021 import javax.swing.JComboBox; 022 import javax.swing.JComponent; 023 import javax.swing.JLabel; 024 import javax.swing.JScrollPane; 025 026 import org.springframework.rules.constraint.Constraint; 027 import org.springframework.richclient.form.binding.Binding; 028 import org.springframework.richclient.form.binding.BindingFactory; 029 import org.springframework.richclient.form.binding.swing.ComboBoxBinder; 030 import org.springframework.richclient.layout.TableLayoutBuilder; 031 import org.springframework.util.Assert; 032 033 /** 034 * A TableFormBuilder builds a form by using a {@link TableLayoutBuilder} 035 * 036 * @author oliverh 037 * @author Mathias Broekelmann 038 */ 039 public class TableFormBuilder extends AbstractFormBuilder { 040 041 private static final String VALIGN_TOP = TableLayoutBuilder.VALIGN + "=top"; 042 043 private TableLayoutBuilder builder; 044 045 private String labelAttributes = TableLayoutBuilder.DEFAULT_LABEL_ATTRIBUTES; 046 047 /** 048 * Creates an instances of the TableFormBuilder by using a {@link BindingFactory} 049 * 050 * @param bindingFactory 051 * the binding factory to use to create field bindings. 052 */ 053 public TableFormBuilder(BindingFactory bindingFactory) { 054 this(bindingFactory, null); 055 } 056 057 /** 058 * Creates an instances of the TableFormBuilder by using a {@link BindingFactory} and a given {@ TableLayoutBuilder} 059 * 060 * @param bindingFactory 061 * the binding factory to use to create field bindings. 062 */ 063 public TableFormBuilder(BindingFactory bindingFactory, TableLayoutBuilder tableLayoutBuilder) { 064 super(bindingFactory); 065 this.builder = tableLayoutBuilder; 066 } 067 068 /** 069 * adds a row to the form. All subsequent field additions will be placed in a new row 070 */ 071 public void row() { 072 getLayoutBuilder().relatedGapRow(); 073 } 074 075 /** 076 * Adds the field to the form. {@link #createDefaultBinding(String)} is used to create the binding for the field 077 * 078 * @param fieldName 079 * the name of the field to add 080 * @param attributes 081 * optional layout attributes for the component. See {@link TableLayoutBuilder} for syntax details 082 * @return an array containing the label and the component which where added to the form 083 */ 084 public JComponent[] add(String fieldName) { 085 return add(fieldName, ""); 086 } 087 088 /** 089 * Adds the field binding to the form. 090 * 091 * @param binding 092 * the field binding to add 093 * @return an array containing the label and the component of the binding which where added to the form 094 */ 095 public JComponent[] add(Binding binding) { 096 return add(binding, ""); 097 } 098 099 /** 100 * Adds the field to the form. {@link #createDefaultBinding(String)} is used to create the binding for the field 101 * 102 * @param fieldName 103 * the name of the field to add 104 * @param attributes 105 * optional layout attributes for the component. See {@link TableLayoutBuilder} for syntax details 106 * @return an array containing the label and the component which where added to the form 107 */ 108 public JComponent[] add(String fieldName, String attributes) { 109 return addBinding(createDefaultBinding(fieldName), attributes, getLabelAttributes()); 110 } 111 112 /** 113 * Adds the field binding to the form. 114 * 115 * @param binding 116 * the field binding to add 117 * @param attributes 118 * optional layout attributes for the component. See {@link TableLayoutBuilder} for syntax details 119 * @return an array containing the label and the component which where added to the form 120 */ 121 public JComponent[] add(Binding binding, String attributes) { 122 return addBinding(binding, attributes, getLabelAttributes()); 123 } 124 125 /** 126 * Adds the field to the form by using the provided component. 127 * 128 * @param fieldName 129 * the name of the field to add 130 * @param component 131 * the component for the field 132 * @return an array containing the label and the component which where added to the form 133 */ 134 public JComponent[] add(String fieldName, JComponent component) { 135 return add(fieldName, component, ""); 136 } 137 138 /** 139 * Adds the field to the form by using the provided component. {@link #createBinding(String, JComponent)} is used to 140 * create the binding of the field 141 * 142 * @param fieldName 143 * the name of the field to add 144 * @param component 145 * the component for the field 146 * @param attributes 147 * optional layout attributes for the component. See {@link TableLayoutBuilder} for syntax details 148 * @return an array containing the label and the component which where added to the form 149 */ 150 public JComponent[] add(String fieldName, JComponent component, String attributes) { 151 return addBinding(createBinding(fieldName, component), attributes, getLabelAttributes()); 152 } 153 154 /** 155 * Adds the field to the form by using a selector component. {@link #createSelector(String, Constraint)} is used to 156 * create the component for the selector 157 * 158 * @param fieldName 159 * the name of the field to add 160 * @param filter 161 * optional filter constraint for the items of the selector 162 * @return an array containing the label and the selector component which where added to the form 163 * 164 * @see #createSelector(String, org.springframework.rules.constraint.Constraint) 165 */ 166 public JComponent[] addSelector(String fieldName, Constraint filter) { 167 return addSelector(fieldName, filter, ""); 168 } 169 170 /** 171 * Adds the field to the form by using a selector component. 172 * 173 * @param fieldName 174 * the name of the field to add 175 * @param filter 176 * optional filter constraint for the items of the selector 177 * @param attributes 178 * optional layout attributes for the selector component. See {@link TableLayoutBuilder} for syntax 179 * details 180 * @return an array containing the label and the selector component which where added to the form 181 * 182 */ 183 public JComponent[] addSelector(String fieldName, Constraint filter, String attributes) { 184 Map context = new HashMap(); 185 context.put(ComboBoxBinder.FILTER_KEY, filter); 186 return addBinding(getBindingFactory().createBinding(JComboBox.class, fieldName), attributes, 187 getLabelAttributes()); 188 } 189 190 /** 191 * Adds the field to the form by using a password component. {@link #createPasswordField(String)} is used to create 192 * the component for the password field 193 * 194 * @param fieldName 195 * the name of the field to add 196 * @return an array containing the label and the password component which where added to the form 197 * 198 * @see #createPasswordField(String) 199 */ 200 public JComponent[] addPasswordField(String fieldName) { 201 return addPasswordField(fieldName, ""); 202 } 203 204 /** 205 * Adds the field to the form by using a password component. {@link #createPasswordField(String)} is used to create 206 * the component for the password field 207 * 208 * @param fieldName 209 * the name of the field to add 210 * @param attributes 211 * optional layout attributes for the password component. See {@link TableLayoutBuilder} for syntax 212 * details 213 * @return an array containing the label and the password component which where added to the form 214 * 215 * @see #createPasswordField(String) 216 */ 217 public JComponent[] addPasswordField(String fieldName, String attributes) { 218 return addBinding(createBinding(fieldName, createPasswordField(fieldName)), attributes, getLabelAttributes()); 219 } 220 221 /** 222 * Adds the field to the form by using a text area component which is wrapped inside a scrollpane. 223 * <p> 224 * Note: this method ensures that the the label of the textarea has a top vertical alignment if <code>valign</code> 225 * is not defined in the default label attributes 226 * 227 * @param fieldName 228 * the name of the field to add 229 * @return an array containing the label, the textarea and the scrollpane which where added to the form 230 * 231 * @see #createTextArea(String) 232 */ 233 public JComponent[] addTextArea(String fieldName) { 234 return addTextArea(fieldName, ""); 235 } 236 237 /** 238 * Adds the field to the form by using a text area component which is wrapped inside a scrollpane. 239 * {@link #createTextArea(String)} is used to create the component for the text area field 240 * <p> 241 * Note: this method ensures that the the label of the textarea has a top vertical alignment if <code>valign</code> 242 * is not defined in the default label attributes 243 * 244 * @param fieldName 245 * the name of the field to add 246 * @param attributes 247 * optional layout attributes for the scrollpane. See {@link TableLayoutBuilder} for syntax details 248 * @return an array containing the label, the textarea and the scrollpane and which where added to the form 249 * 250 * @see #createTextArea(String) 251 */ 252 public JComponent[] addTextArea(String fieldName, String attributes) { 253 JComponent textArea = createTextArea(fieldName); 254 String labelAttributes = getLabelAttributes(); 255 if (labelAttributes == null) { 256 labelAttributes = VALIGN_TOP; 257 } else if (!labelAttributes.contains(TableLayoutBuilder.VALIGN)) { 258 labelAttributes += " " + VALIGN_TOP; 259 } 260 return addBinding(createBinding(fieldName, textArea), new JScrollPane(textArea), attributes, labelAttributes); 261 } 262 263 /** 264 * Adds the field to the form by using the default binding. The component will be placed inside a scrollpane. 265 * 266 * @param fieldName 267 * the name of the field to add 268 * @return an array containing the label, the component of the field binding and the scrollpane which where added to 269 * the form 270 */ 271 public JComponent[] addInScrollPane(String fieldName) { 272 return addInScrollPane(fieldName, ""); 273 } 274 275 /** 276 * Adds the field to the form by using the default binding. The component will be placed inside a scrollpane. 277 * 278 * @param fieldName 279 * the name of the field to add 280 * @param attributes 281 * optional layout attributes for the scrollpane. See {@link TableLayoutBuilder} for syntax details 282 * @return an array containing the label, the component of the field binding and the scrollpane binding which where 283 * added to the form 284 * 285 * @see #createScrollPane(String, JComponent) 286 */ 287 public JComponent[] addInScrollPane(String fieldName, String attributes) { 288 return addInScrollPane(createDefaultBinding(fieldName), attributes); 289 } 290 291 /** 292 * Adds the field binding to the form. The component will be placed inside a scrollpane. 293 * 294 * @param binding 295 * the binding to use 296 * @return an array containing the label, the component of the field binding and the scrollpane and the component of 297 * the binding which where added to the form 298 * 299 * @see #createScrollPane(String, JComponent) 300 */ 301 public JComponent[] addInScrollPane(Binding binding) { 302 return addInScrollPane(binding, ""); 303 } 304 305 /** 306 * Adds the field binding to the form. The component will be placed inside a scrollpane. 307 * {@link #createScrollPane(String, JComponent)} is used to create the component for the scrollpane 308 * 309 * @param binding 310 * the binding to use 311 * @param attributes 312 * optional layout attributes for the scrollpane. See {@link TableLayoutBuilder} for syntax details 313 * @return an array containing the label, the component of the field binding and the scrollpane and the component of 314 * the binding which where added to the form 315 * 316 * @see #createScrollPane(String, JComponent) 317 */ 318 public JComponent[] addInScrollPane(Binding binding, String attributes) { 319 Assert.isTrue(getFormModel() == binding.getFormModel(), 320 "Binding's form model must match FormBuilder's form model"); 321 return add(binding.getProperty(), createScrollPane(binding.getProperty(), binding.getControl()), attributes); 322 } 323 324 /** 325 * Adds a labeled separator to the form. 326 * 327 * @param text 328 * the key for the label. Must not be null 329 */ 330 public JComponent addSeparator(String text) { 331 return addSeparator(text, ""); 332 } 333 334 /** 335 * Adds a labeled separator to the form 336 * 337 * @param text 338 * the key for the label. Must not be null 339 * @param attributes 340 * optional attributes. See {@link TableLayoutBuilder} for syntax details 341 */ 342 public JComponent addSeparator(String text, String attributes) { 343 JComponent separator = getComponentFactory().createLabeledSeparator(text); 344 getLayoutBuilder().cell(separator, attributes); 345 return separator; 346 } 347 348 /** 349 * Returns the layout builder which is used to build the layout of the added fields and labels 350 * 351 * @return The form containing the added fields, components and labels in the defined layout. Not null 352 */ 353 public TableLayoutBuilder getLayoutBuilder() { 354 if (builder == null) { 355 builder = new TableLayoutBuilder(getComponentFactory().createPanel()); 356 } 357 return builder; 358 } 359 360 /** 361 * Returns the form which has been created by this builder 362 * 363 * @return The form containing the added fields and labels in the defined layout. Not null 364 */ 365 public JComponent getForm() { 366 getBindingFactory().getFormModel().revert(); 367 return getLayoutBuilder().getPanel(); 368 } 369 370 /** 371 * returns the default label layout attributes for the form. 372 * 373 * @return layout attributes for the labels, can be null. 374 */ 375 public String getLabelAttributes() { 376 return labelAttributes; 377 } 378 379 /** 380 * defines the default label layout attributes for the form. 381 * 382 * @param labelAttributes 383 * layout attributes for the labels, if null no layout attributes will be applied to the labels. See 384 * {@link TableLayoutBuilder} for syntax details. 385 */ 386 public void setLabelAttributes(String labelAttributes) { 387 this.labelAttributes = labelAttributes; 388 } 389 390 /** 391 * adds a field binding to the form. This method does not use the default label attributes which may have been set 392 * through {@link #setLabelAttributes(String)} 393 * 394 * @param binding 395 * the binding of the field 396 * @param attributes 397 * optional layout attributes for the label. If null no layout attributes will be applied to the label. 398 * See {@link TableLayoutBuilder} for syntax details 399 * @return an array containing the label and the component of the binding 400 */ 401 public JComponent[] addBinding(Binding binding, String attributes, String labelAttributes) { 402 return addBinding(binding, binding.getControl(), attributes, labelAttributes); 403 } 404 405 /** 406 * adds a field binding to the form 407 * 408 * @param binding 409 * the binding of the field 410 * @param wrappedControl 411 * the optional wrapped component. If null the component of the binding is used. This Parameter should be 412 * used if the component of the binding is being wrapped inside this component 413 * @param attributes 414 * optional layout attributes for the label. If null no layout attributes will be applied to the label. 415 * See {@link TableLayoutBuilder} for syntax details 416 * @return an array containing the label, the component of the field binding and the wrapped component 417 */ 418 public JComponent[] addBinding(Binding binding, JComponent wrappedControl, String attributes) { 419 return addBinding(binding, wrappedControl, attributes, getLabelAttributes()); 420 } 421 422 /** 423 * adds a field binding to the form 424 * 425 * @param binding 426 * the binding of the field 427 * @param wrappedComponent 428 * the optional wrapped component. If null the component of the binding is used. This Parameter should be 429 * used if the component of the binding is being wrapped inside this component 430 * @param attributes 431 * optional layout attributes for the wrapped component. If null no layout attributes will be applied to 432 * the component. See {@link TableLayoutBuilder} for syntax details 433 * @param attributes 434 * optional layout attributes for the label. If null no layout attributes will be applied to the label. 435 * See {@link TableLayoutBuilder} for syntax details 436 * @return an array containing the label, the component of the field binding and the wrapped component 437 */ 438 public JComponent[] addBinding(Binding binding, JComponent wrappedComponent, String attributes, 439 String labelAttributes) { 440 Assert.notNull(binding, "binding is null"); 441 Assert.isTrue(getFormModel() == binding.getFormModel(), 442 "Binding's form model must match FormBuilder's form model"); 443 JComponent component = binding.getControl(); 444 final JLabel label = createLabelFor(binding.getProperty(), component); 445 if (wrappedComponent == null) { 446 wrappedComponent = component; 447 } 448 TableLayoutBuilder layoutBuilder = getLayoutBuilder(); 449 if (!layoutBuilder.hasGapToLeft()) { 450 layoutBuilder.gapCol(); 451 } 452 layoutBuilder.cell(label, labelAttributes); 453 layoutBuilder.labelGapCol(); 454 layoutBuilder.cell(wrappedComponent, attributes); 455 return new JComponent[] { label, component, wrappedComponent }; 456 } 457 }