/** * Copyright (C) 2015 Valkyrie RCP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.valkyriercp.form.builder; import org.springframework.util.Assert; import org.valkyriercp.form.binding.Binding; import org.valkyriercp.form.binding.BindingFactory; import org.valkyriercp.form.binding.swing.ComboBoxBinder; import org.valkyriercp.layout.TableLayoutBuilder; import org.valkyriercp.rules.constraint.Constraint; import javax.swing.*; import java.util.HashMap; import java.util.Map; /** * A TableFormBuilder builds a form by using a {@link TableLayoutBuilder} * * @author oliverh * @author Mathias Broekelmann */ public class TableFormBuilder extends AbstractFormBuilder { private static final String VALIGN_TOP = TableLayoutBuilder.VALIGN + "=top"; private TableLayoutBuilder builder; private String labelAttributes = TableLayoutBuilder.DEFAULT_LABEL_ATTRIBUTES; /** * Creates an instances of the TableFormBuilder by using a {@link BindingFactory} * * @param bindingFactory * the binding factory to use to create field bindings. */ public TableFormBuilder(BindingFactory bindingFactory) { this(bindingFactory, null); } /** * Creates an instances of the TableFormBuilder by using a {@link BindingFactory} and a given {@ TableLayoutBuilder} * * @param bindingFactory * the binding factory to use to create field bindings. */ public TableFormBuilder(BindingFactory bindingFactory, TableLayoutBuilder tableLayoutBuilder) { super(bindingFactory); this.builder = tableLayoutBuilder; } /** * adds a row to the form. All subsequent field additions will be placed in a new row */ public void row() { getLayoutBuilder().relatedGapRow(); } /** * Adds the field to the form. {@link #createDefaultBinding(String)} is used to create the binding for the field * * @param fieldName * the name of the field to add * @return an array containing the label and the component which where added to the form */ public JComponent[] add(String fieldName) { return add(fieldName, ""); } /** * Adds the field binding to the form. * * @param binding * the field binding to add * @return an array containing the label and the component of the binding which where added to the form */ public JComponent[] add(Binding binding) { return add(binding, ""); } /** * Adds the field to the form. {@link #createDefaultBinding(String)} is used to create the binding for the field * * @param fieldName * the name of the field to add * @param attributes * optional layout attributes for the component. See {@link TableLayoutBuilder} for syntax details * @return an array containing the label and the component which where added to the form */ public JComponent[] add(String fieldName, String attributes) { return addBinding(createDefaultBinding(fieldName), attributes, getLabelAttributes()); } /** * Adds the field binding to the form. * * @param binding * the field binding to add * @param attributes * optional layout attributes for the component. See {@link TableLayoutBuilder} for syntax details * @return an array containing the label and the component which where added to the form */ public JComponent[] add(Binding binding, String attributes) { return addBinding(binding, attributes, getLabelAttributes()); } /** * Adds the field to the form by using the provided component. * * @param fieldName * the name of the field to add * @param component * the component for the field * @return an array containing the label and the component which where added to the form */ public JComponent[] add(String fieldName, JComponent component) { return add(fieldName, component, ""); } /** * Adds the field to the form by using the provided component. {@link #createBinding(String, JComponent)} is used to * create the binding of the field * * @param fieldName * the name of the field to add * @param component * the component for the field * @param attributes * optional layout attributes for the component. See {@link TableLayoutBuilder} for syntax details * @return an array containing the label and the component which where added to the form */ public JComponent[] add(String fieldName, JComponent component, String attributes) { return addBinding(createBinding(fieldName, component), attributes, getLabelAttributes()); } /** * Adds the field to the form by using a selector component. {@link #createSelector(String, Constraint)} is used to * create the component for the selector * * @param fieldName * the name of the field to add * @param filter * optional filter constraint for the items of the selector * @return an array containing the label and the selector component which where added to the form * */ public JComponent[] addSelector(String fieldName, Constraint filter) { return addSelector(fieldName, filter, ""); } /** * Adds the field to the form by using a selector component. * * @param fieldName * the name of the field to add * @param filter * optional filter constraint for the items of the selector * @param attributes * optional layout attributes for the selector component. See {@link TableLayoutBuilder} for syntax * details * @return an array containing the label and the selector component which where added to the form * */ public JComponent[] addSelector(String fieldName, Constraint filter, String attributes) { Map context = new HashMap(); context.put(ComboBoxBinder.FILTER_KEY, filter); return addBinding(getBindingFactory().createBinding(JComboBox.class, fieldName), attributes, getLabelAttributes()); } /** * Adds the field to the form by using a password component. {@link #createPasswordField(String)} is used to create * the component for the password field * * @param fieldName * the name of the field to add * @return an array containing the label and the password component which where added to the form * * @see #createPasswordField(String) */ public JComponent[] addPasswordField(String fieldName) { return addPasswordField(fieldName, ""); } /** * Adds the field to the form by using a password component. {@link #createPasswordField(String)} is used to create * the component for the password field * * @param fieldName * the name of the field to add * @param attributes * optional layout attributes for the password component. See {@link TableLayoutBuilder} for syntax * details * @return an array containing the label and the password component which where added to the form * * @see #createPasswordField(String) */ public JComponent[] addPasswordField(String fieldName, String attributes) { return addBinding(createBinding(fieldName, createPasswordField(fieldName)), attributes, getLabelAttributes()); } /** * Adds the field to the form by using a text area component which is wrapped inside a scrollpane. * <p> * Note: this method ensures that the the label of the textarea has a top vertical alignment if <code>valign</code> * is not defined in the default label attributes * * @param fieldName * the name of the field to add * @return an array containing the label, the textarea and the scrollpane which where added to the form * * @see #createTextArea(String) */ public JComponent[] addTextArea(String fieldName) { return addTextArea(fieldName, ""); } /** * Adds the field to the form by using a text area component which is wrapped inside a scrollpane. * {@link #createTextArea(String)} is used to create the component for the text area field * <p> * Note: this method ensures that the the label of the textarea has a top vertical alignment if <code>valign</code> * is not defined in the default label attributes * * @param fieldName * the name of the field to add * @param attributes * optional layout attributes for the scrollpane. See {@link TableLayoutBuilder} for syntax details * @return an array containing the label, the textarea and the scrollpane and which where added to the form * * @see #createTextArea(String) */ public JComponent[] addTextArea(String fieldName, String attributes) { JComponent textArea = createTextArea(fieldName); String labelAttributes = getLabelAttributes(); if (labelAttributes == null) { labelAttributes = VALIGN_TOP; } else if (!labelAttributes.contains(TableLayoutBuilder.VALIGN)) { labelAttributes += " " + VALIGN_TOP; } return addBinding(createBinding(fieldName, textArea), new JScrollPane(textArea), attributes, labelAttributes); } /** * Adds the field to the form by using the default binding. The component will be placed inside a scrollpane. * * @param fieldName * the name of the field to add * @return an array containing the label, the component of the field binding and the scrollpane which where added to * the form */ public JComponent[] addInScrollPane(String fieldName) { return addInScrollPane(fieldName, ""); } /** * Adds the field to the form by using the default binding. The component will be placed inside a scrollpane. * * @param fieldName * the name of the field to add * @param attributes * optional layout attributes for the scrollpane. See {@link TableLayoutBuilder} for syntax details * @return an array containing the label, the component of the field binding and the scrollpane binding which where * added to the form * * @see #createScrollPane(String, JComponent) */ public JComponent[] addInScrollPane(String fieldName, String attributes) { return addInScrollPane(createDefaultBinding(fieldName), attributes); } /** * Adds the field binding to the form. The component will be placed inside a scrollpane. * * @param binding * the binding to use * @return an array containing the label, the component of the field binding and the scrollpane and the component of * the binding which where added to the form * * @see #createScrollPane(String, JComponent) */ public JComponent[] addInScrollPane(Binding binding) { return addInScrollPane(binding, ""); } /** * Adds the field binding to the form. The component will be placed inside a scrollpane. * {@link #createScrollPane(String, JComponent)} is used to create the component for the scrollpane * * @param binding * the binding to use * @param attributes * optional layout attributes for the scrollpane. See {@link TableLayoutBuilder} for syntax details * @return an array containing the label, the component of the field binding and the scrollpane and the component of * the binding which where added to the form * * @see #createScrollPane(String, JComponent) */ public JComponent[] addInScrollPane(Binding binding, String attributes) { Assert.isTrue(getFormModel() == binding.getFormModel(), "Binding's form model must match FormBuilder's form model"); return add(binding.getProperty(), createScrollPane(binding.getProperty(), binding.getControl()), attributes); } /** * Adds a labeled separator to the form. * * @param text * the key for the label. Must not be null */ public JComponent addSeparator(String text) { return addSeparator(text, ""); } /** * Adds a labeled separator to the form * * @param text * the key for the label. Must not be null * @param attributes * optional attributes. See {@link TableLayoutBuilder} for syntax details */ public JComponent addSeparator(String text, String attributes) { JComponent separator = getComponentFactory().createLabeledSeparator(text); getLayoutBuilder().cell(separator, attributes); return separator; } /** * Returns the layout builder which is used to build the layout of the added fields and labels * * @return The form containing the added fields, components and labels in the defined layout. Not null */ public TableLayoutBuilder getLayoutBuilder() { if (builder == null) { builder = new TableLayoutBuilder(getComponentFactory().createPanel()); } return builder; } /** * Returns the form which has been created by this builder * * @return The form containing the added fields and labels in the defined layout. Not null */ public JComponent getForm() { getBindingFactory().getFormModel().revert(); return getLayoutBuilder().getPanel(); } /** * returns the default label layout attributes for the form. * * @return layout attributes for the labels, can be null. */ public String getLabelAttributes() { return labelAttributes; } /** * defines the default label layout attributes for the form. * * @param labelAttributes * layout attributes for the labels, if null no layout attributes will be applied to the labels. See * {@link TableLayoutBuilder} for syntax details. */ public void setLabelAttributes(String labelAttributes) { this.labelAttributes = labelAttributes; } /** * adds a field binding to the form. This method does not use the default label attributes which may have been set * through {@link #setLabelAttributes(String)} * * @param binding * the binding of the field * @param attributes * optional layout attributes for the label. If null no layout attributes will be applied to the label. * See {@link TableLayoutBuilder} for syntax details * @return an array containing the label and the component of the binding */ public JComponent[] addBinding(Binding binding, String attributes, String labelAttributes) { return addBinding(binding, binding.getControl(), attributes, labelAttributes); } /** * adds a field binding to the form * * @param binding * the binding of the field * @param wrappedControl * the optional wrapped component. If null the component of the binding is used. This Parameter should be * used if the component of the binding is being wrapped inside this component * @param attributes * optional layout attributes for the label. If null no layout attributes will be applied to the label. * See {@link TableLayoutBuilder} for syntax details * @return an array containing the label, the component of the field binding and the wrapped component */ public JComponent[] addBinding(Binding binding, JComponent wrappedControl, String attributes) { return addBinding(binding, wrappedControl, attributes, getLabelAttributes()); } /** * adds a field binding to the form * * @param binding * the binding of the field * @param wrappedComponent * the optional wrapped component. If null the component of the binding is used. This Parameter should be * used if the component of the binding is being wrapped inside this component * @param attributes * optional layout attributes for the wrapped component. If null no layout attributes will be applied to * the component. See {@link TableLayoutBuilder} for syntax details * @param attributes * optional layout attributes for the label. If null no layout attributes will be applied to the label. * See {@link TableLayoutBuilder} for syntax details * @return an array containing the label, the component of the field binding and the wrapped component */ public JComponent[] addBinding(Binding binding, JComponent wrappedComponent, String attributes, String labelAttributes) { Assert.notNull(binding, "binding is null"); Assert.isTrue(getFormModel() == binding.getFormModel(), "Binding's form model must match FormBuilder's form model"); JComponent component = binding.getControl(); final JLabel label = createLabelFor(binding.getProperty(), component); if (wrappedComponent == null) { wrappedComponent = component; } TableLayoutBuilder layoutBuilder = getLayoutBuilder(); if (!layoutBuilder.hasGapToLeft()) { layoutBuilder.gapCol(); } layoutBuilder.cell(label, labelAttributes); layoutBuilder.labelGapCol(); layoutBuilder.cell(wrappedComponent, attributes); return new JComponent[] { label, component, wrappedComponent }; } }