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 }