Java tutorial
/* * Copyright (c) 2012 Brown Bag Consulting. * This file is part of the ExpressUI project. * Author: Juan Osuna * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License Version 3 * as published by the Free Software Foundation with the addition of the * following permission added to Section 15 as permitted in Section 7(a): * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY * Brown Bag Consulting, Brown Bag Consulting DISCLAIMS THE WARRANTY OF * NON INFRINGEMENT OF THIRD PARTY RIGHTS. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License. * * You can be released from the requirements of the license by purchasing * a commercial license. Buying such a license is mandatory as soon as you * develop commercial activities involving the ExpressUI software without * disclosing the source code of your own applications. These activities * include: offering paid services to customers as an ASP, providing * services from a web application, shipping ExpressUI with a closed * source product. * * For more information, please contact Brown Bag Consulting at this * address: juan@brownbagconsulting.com. */ package com.expressui.core.view.form; import com.expressui.core.util.MethodDelegate; import com.expressui.core.util.assertion.Assert; import com.expressui.core.validation.AbstractConversionValidator; import com.expressui.core.view.field.DisplayField; import com.expressui.core.view.field.FieldSet; import com.expressui.core.view.field.FormField; import com.expressui.core.view.field.SelectField; import com.expressui.core.view.form.layout.FormGridLayout; import com.expressui.core.view.form.layout.LeftLabelGridLayout; import com.expressui.core.view.form.layout.TopLabelGridLayout; import com.vaadin.data.Validator; import com.vaadin.terminal.ErrorMessage; import com.vaadin.ui.*; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.*; import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; /** * Collection of fields for display in a form component, along with configuration information about * how to position and display these fields. */ @Component @Scope(SCOPE_PROTOTYPE) public class FormFieldSet extends FieldSet { private TypedForm form; private Map<String, AddRemoveTabMethodDelegate> optionalTabs = new HashMap<String, AddRemoveTabMethodDelegate>(); /** * Gets form component that contains these fields. * * @return form component containing these fields */ public TypedForm getForm() { return form; } /** * Sets the form component that contains these fields. * * @param form component containing these fields */ public void setForm(TypedForm form) { this.form = form; setType(form.getType()); } /** * Creates a form tab that contains a subset of these fields. * * @param tabName name of the tab * @return newly created form tab */ public FormTab createTab(String tabName) { Assert.PROGRAMMING.notNull(tabName); return new FormTab(this, tabName); } /** * Gets number of columns in this form, assuming form has no tabs. * * @return number of columns in this form */ public int getColumns() { return getColumns(""); } /** * Gets number of columns in this form's tab. * * @param tabName name of tab * @return number of columns in this form's tab */ public int getColumns(String tabName) { int columns = 0; Collection<DisplayField> displayFields = getFields(); for (DisplayField displayField : displayFields) { FormField formField = (FormField) displayField; if (formField.getTabName().equals(tabName)) { columns = Math.max(columns, formField.getColumnStart() - 1); if (formField.getColumnEnd() != null) { columns = Math.max(columns, formField.getColumnEnd() - 1); } } } return ++columns; } /** * Gets number of rows in this form, assuming form has no tabs. * * @return number of rows in this form */ public int getRows() { return getRows(""); } /** * Gets number of rows in this form's tab. * * @param tabName name of tab * @return number of rows in this form's tab */ public int getRows(String tabName) { int rows = 0; Collection<DisplayField> displayFields = getFields(); for (DisplayField displayField : displayFields) { FormField formField = (FormField) displayField; if (formField.getTabName().equals(tabName)) { rows = Math.max(rows, formField.getRowStart() - 1); if (formField.getRowEnd() != null) { rows = Math.max(rows, formField.getRowEnd() - 1); } } } return ++rows; } /** * Gets the name of the first tab in this form. * * @return name of first tab */ public String getFirstTabName() { return getTabNames().iterator().next(); } /** * Creates form grid layout for containing form fields, assuming form has no tabs. * * @return form grid layout */ public Layout createGridLayout() { return createGridLayout(getFirstTabName()); } /** * Creates form grid layout for containing form fields in given tab; * * @param tabName tab subsection of form * @return grid layout for tab */ public Layout createGridLayout(String tabName) { FormGridLayout gridLayout; if (form instanceof EntityForm) { gridLayout = new LeftLabelGridLayout(getColumns(tabName), getRows(tabName)); } else { gridLayout = new TopLabelGridLayout(getColumns(tabName), getRows(tabName)); } gridLayout.setMargin(true, true, true, true); gridLayout.setSpacing(true); gridLayout.setSizeUndefined(); return gridLayout; } @Override protected FormField createField(String propertyId) { Assert.PROGRAMMING.isTrue(!containsPropertyId(propertyId), "Field has already been created for property " + getType().getName() + "." + propertyId); FormField formField = new FormField(this, propertyId); addField(propertyId, formField); return formField; } /** * Sets the position of a field in the form's tab, where the field occupies just one cell. * * @param tabName tab to place field * @param propertyId property id in entity to bind field to * @param rowStart row start coordinate * @param columnStart column start coordinate */ public void setCoordinates(String tabName, String propertyId, int rowStart, int columnStart) { setCoordinates(tabName, propertyId, rowStart, columnStart, null, null); } /** * Sets the position of a field in the form, where the field occupies just one cell in form without tabs. * * @param propertyId property id in entity to bind field to * @param rowStart row start coordinate * @param columnStart column start coordinate */ public void setCoordinates(String propertyId, int rowStart, int columnStart) { setCoordinates(propertyId, rowStart, columnStart, null, null); } /** * Sets the position of a field in the form without tabs, where field can span multiple cells. * * @param propertyId property id in entity to bind field to * @param rowStart row start coordinate * @param columnStart column start coordinate * @param rowEnd row end coordinate, field height is stretched to row end coordinate * @param columnEnd column end coordinate, field width is stretched to column end coordinate */ public void setCoordinates(String propertyId, int rowStart, int columnStart, Integer rowEnd, Integer columnEnd) { setCoordinates("", propertyId, rowStart, columnStart, rowEnd, columnEnd); } /** * Sets the position of a field in the form's tab, where field can span multiple cells. * * @param tabName tab to place field * @param propertyId property id in entity to bind field to * @param rowStart row start coordinate * @param columnStart column start coordinate * @param rowEnd row end coordinate, field height is stretched to row end coordinate * @param columnEnd column end coordinate, field width is stretched to column end coordinate */ public void setCoordinates(String tabName, String propertyId, int rowStart, int columnStart, Integer rowEnd, Integer columnEnd) { Assert.PROGRAMMING.notNull(tabName, "tab name cannot be null for property " + getType().getName() + "." + propertyId); Assert.PROGRAMMING.isTrue(rowStart > 0, "rowStart arg must be greater than 0 for property " + getType().getName() + "." + propertyId + (tabName.isEmpty() ? "" : ", for tab " + tabName)); Assert.PROGRAMMING.isTrue(columnStart > 0, "columnStart arg must be greater than 0 for property " + getType().getName() + "." + propertyId + (tabName.isEmpty() ? "" : ", for tab " + tabName)); FormField formField = createField(propertyId); formField.setTabName(tabName); formField.setRowStart(rowStart); formField.setColumnStart(columnStart); formField.setRowEnd(rowEnd); formField.setColumnEnd(columnEnd); } /** * Asserts that all the FormFields in this form are valid. */ public void assertValid() { Collection<FormField> formFields = getFormFields(); for (FormField formField : formFields) { formField.assertValid(); } } /** * Finds FormField based on the Vaadin field it contains. * * @param field Vaadin field for looking up FormField * @return FormField */ public FormField findByField(Field field) { Collection<DisplayField> displayFields = getFields(); for (DisplayField displayField : displayFields) { FormField formField = (FormField) displayField; if (formField.getField().equals(field)) { return formField; } } return null; } /** * Gets method delegate that listens for adding and removing a tab. * * @param tabName name of tab to trigger the delegate * @return delegate */ public AddRemoveTabMethodDelegate getTabAddRemoveDelegate(String tabName) { return optionalTabs.get(tabName); } /** * Asks if the given tab is optional. * * @param tabName name of tab * @return true if optional */ public boolean isTabOptional(String tabName) { return optionalTabs.containsKey(tabName); } /** * Asks if form contains any optional tabs. * * @return true if form contains optional tabs */ public boolean hasOptionalTabs() { return !optionalTabs.isEmpty(); } /** * Sets a tab as optional. * * @param tabName name of tab to set * @param addTarget target object to invoke method on, when tab is added * @param addMethod method to invoke, when tab is added * @param removeTarget target object to invoke method on, when tab is removed * @param removeMethod method to invoke, when tab is removed */ public void setTabOptional(String tabName, Object addTarget, String addMethod, Object removeTarget, String removeMethod) { MethodDelegate addMethodDelegate = new MethodDelegate(addTarget, addMethod); MethodDelegate removeMethodDelegate = new MethodDelegate(removeTarget, removeMethod); AddRemoveTabMethodDelegate addRemoveTabMethodDelegate = new AddRemoveTabMethodDelegate(addMethodDelegate, removeMethodDelegate); optionalTabs.put(tabName, addRemoveTabMethodDelegate); } /** * Gets FormField bound to given property. * * @param propertyId property id (name) * @return FormField bound to property */ public FormField getFormField(String propertyId) { return (FormField) getField(propertyId); } /** * Sets Vaadin field to be displayed. * * @param propertyId property id to identify FormField * @param field Vaadin field */ public void setField(String propertyId, Field field) { FormField formField = (FormField) getField(propertyId); formField.setField(field); } /** * Asks if this form contains property in the given tab. * * @param tabName name of tab * @param propertyId property id * @return true if this form contains property in the given tab */ public boolean containsPropertyId(String tabName, String propertyId) { Assert.PROGRAMMING.notNull(getFormField(propertyId).getTabName(), "tab name cannot be null for " + getType().getName() + "." + propertyId); return containsPropertyId(propertyId) && getFormField(propertyId).getTabName().equals(tabName); } /** * Gets all the FormFields in given tab. * * @param tabName name of tab * @return all the FormField under the tab */ public Set<FormField> getFormFields(String tabName) { Set<FormField> formFields = new HashSet<FormField>(); Collection<DisplayField> displayFields = getFields(); for (DisplayField displayField : displayFields) { FormField formField = (FormField) displayField; if (formField.getTabName() != null && formField.getTabName().equals(tabName)) { formFields.add(formField); } } return formFields; } /** * Gets all the FormFields in all tabs. * * @return all FormFields */ public Set<FormField> getFormFields() { Set<FormField> formFields = new HashSet<FormField>(); Collection<DisplayField> displayFields = getFields(); for (DisplayField displayField : displayFields) { FormField formField = (FormField) displayField; formFields.add(formField); } return formFields; } /** * Clears all errors associated with all fields. * * @param clearConversionErrors true to clear conversion errors as well */ public void clearErrors(boolean clearConversionErrors) { Collection<DisplayField> displayFields = getFields(); for (DisplayField displayField : displayFields) { FormField formField = (FormField) displayField; formField.clearError(clearConversionErrors); } } /** * Asks if any field has an error in a tab. * * @param tabName name of tab * @return true if any field has an error in given tab */ public boolean hasError(String tabName) { Set<FormField> formFields = getFormFields(tabName); for (FormField formField : formFields) { if (formField.hasError()) { return true; } } return false; } /** * Gets names of all tabs in this form. * * @return names of all tabs */ public Set<String> getTabNames() { Set<String> tabNames = new LinkedHashSet<String>(); Collection<DisplayField> displayFields = getFields(); for (DisplayField displayField : displayFields) { FormField formField = (FormField) displayField; if (formField.getTabName() != null) { tabNames.add(formField.getTabName()); } } return tabNames; } /** * Asks if this form has tabs. * * @return true if this form has tabs */ public boolean hasTabs() { return getTabNames().size() > 1; } /** * Gets all tabs that are viewable, based on whether each tab contains viewable fields * according to security permissions. * * @return all viewable tabs */ public Set<String> getViewableTabNames() { if (getForm() instanceof SearchForm) return getTabNames(); Set<String> viewableTabNames = new LinkedHashSet<String>(); Set<String> tabNames = getTabNames(); for (String tabName : tabNames) { Set<FormField> fields = getFormFields(tabName); for (FormField field : fields) { if (securityService.getCurrentUser().isViewAllowed(getType().getName(), field.getPropertyId())) { viewableTabNames.add(tabName); break; } } } return viewableTabNames; } /** * Gets all viewable FormFields, based on security permissions. * * @return all viewable form fields */ public Set<FormField> getViewableFormFields() { if (getForm() instanceof SearchForm) return getFormFields(); Set<FormField> viewableFormFields = new LinkedHashSet<FormField>(); Set<FormField> formFields = getFormFields(); for (FormField formField : formFields) { if (securityService.getCurrentUser().isViewAllowed(getType().getName(), formField.getPropertyId())) { viewableFormFields.add(formField); break; } } return viewableFormFields; } /** * Gets all editable FormFields, based on security permissions. * * @return all editable form fields */ public Set<FormField> getEditableFormFields() { if (getForm() instanceof SearchForm) return getFormFields(); Set<FormField> editableFormFields = new LinkedHashSet<FormField>(); Set<FormField> formFields = getFormFields(); for (FormField formField : formFields) { if (securityService.getCurrentUser().isEditAllowed(getType().getName(), formField.getPropertyId())) { editableFormFields.add(formField); break; } } return editableFormFields; } @Override public String getLabel(String propertyId) { if (((FormField) getField(propertyId)).getFieldLabel().getValue() == null) { return null; } else { return ((FormField) getField(propertyId)).getFieldLabel().getValue().toString(); } } @Override public void setLabel(String propertyId, String label) { ((FormField) getField(propertyId)).setFieldLabel(label); } /** * Manually sets width of the field and turn off auto width adjustment. * * @param propertyId property id to identify field to set * @param width size of width * @param unit unit of measurement defined in Sizeable * @see com.vaadin.terminal.Sizeable */ public void setWidth(String propertyId, float width, int unit) { getFormField(propertyId).setWidth(width, unit); } /** * Sets height of the field. * * @param propertyId property id to identify field to set * @param height size of width * @param unit unit of measurement defined in Sizeable * @see com.vaadin.terminal.Sizeable */ public void setHeight(String propertyId, float height, int unit) { getFormField(propertyId).setHeight(height, unit); } /** * Automatically adjusts widths of fields based on their value contents. */ public void autoAdjustWidths() { Set<FormField> formFields = getFormFields(); for (FormField formField : formFields) { if (formField.getField() instanceof AbstractTextField) { formField.autoAdjustTextFieldWidth(); } else if (formField.getField() instanceof AbstractSelect) { formField.autoAdjustSelectWidth(); } } } /** * Sets auto-adjust-width mode. * * @param propertyId property id to identify field to set * @param autoAdjustWidthMode auto-adjust-width mode */ public void setAutoAdjustWidthMode(String propertyId, FormField.AutoAdjustWidthMode autoAdjustWidthMode) { getFormField(propertyId).setAutoAdjustWidthMode(autoAdjustWidthMode); } /** * Adds a validator to field. * * @param propertyId property id to identify field to be validated * @param validator validator to attach to field */ public void addValidator(String propertyId, Validator validator) { getFormField(propertyId).addValidator(validator); } /** * Adds a conversion validator to field by reflectively instantiating given class. * * @param propertyId property id to identify field to be validated * @param validatorClass class of the validator that to be instantiated and set on the field */ public void addConversionValidator(String propertyId, Class<? extends AbstractConversionValidator> validatorClass) { try { Constructor<? extends Validator> constructor = validatorClass.getConstructor(FormField.class); Validator validator = constructor.newInstance(getFormField(propertyId)); getFormField(propertyId).addValidator(validator); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** * Adds a conversion validator to field. * * @param propertyId property id to identify field to be validated * @param validator validator to be attached to the field */ public void addConversionValidator(String propertyId, AbstractConversionValidator validator) { validator.setFormField(getFormField(propertyId)); getFormField(propertyId).addValidator(validator); } /** * Gets the description displayed during mouse-over/hovering. * * @param propertyId property id to identify field to set * @return description displayed to user */ public String getToolTip(String propertyId) { return getFormField(propertyId).getToolTip(); } /** * Sets the description displayed during mouse-over/hovering. * * @param propertyId property id to identify field to set * @param toolTip description displayed to user */ public void setToolTip(String propertyId, String toolTip) { getFormField(propertyId).setToolTip(toolTip); } /** * Generates or re-generates tooltip, passing in arguments for interpolation using standard {0}, {1}, {2} * notation. This feature only works with resource bundle messages defined in domainMessages/. * * @param propertyId property id to identify field to set * @param args */ public void setToolTipArgs(String propertyId, Object... args) { getFormField(propertyId).setToolTipArgs(args); } /** * Clears the menu options in a select. * * @param propertyId property id to identify field to set */ public void clearSelectItems(String propertyId) { getFormField(propertyId).setSelectItems(new ArrayList()); } /** * Sets the menu options in a select. * * @param propertyId property id to identify field to set * @param items list of items * see com.expressui.core.entity.ReferenceEntity.DISPLAY_PROPERTY */ public void setSelectItems(String propertyId, List items) { getFormField(propertyId).setSelectItems(items); } /** * Sets menu options in a select. * * @param propertyId property id to identify field to set * @param items map of items where key is bound to entity and value is the display caption */ public void setSelectItems(String propertyId, Map<Object, String> items) { getFormField(propertyId).setSelectItems(items); } /** * Sets menu options in a select. * * @param propertyId property id to identify field to set * @param items map of items where key is bound to entity and value is the display caption * @param nullCaption caption displayed to represent null or no selection */ public void setSelectItems(String propertyId, Map<Object, String> items, String nullCaption) { getFormField(propertyId).setSelectItems(items, nullCaption); } /** * Sets the dimensions of a multi-select menu * * @param propertyId property id to identify field to set * @param rows height * @param columns width */ public void setMultiSelectDimensions(String propertyId, int rows, int columns) { getFormField(propertyId).setMultiSelectDimensions(rows, columns); } /** * Sets the visibility of this field and label. * * @param propertyId property id to identify field to set * @param isVisible true if visible */ public void setVisible(String propertyId, boolean isVisible) { getFormField(propertyId).setVisible(isVisible); } /** * Asks if this field is originally required, which is automatically set based on the bound bean's validation * annotations, or can be set programmatically. * * @param propertyId property id * @return true if required */ public boolean isOriginallyRequired(String propertyId) { return getFormField(propertyId).isOriginallyRequired(); } /** * Sets whether or not field is required. This value may also be set programmatically. * * @param propertyId property id to identify field to set * @param isRequired true if required */ public void setOriginallyRequired(String propertyId, boolean isRequired) { getFormField(propertyId).setOriginallyRequired(isRequired); } /** * Sets whether or not this field is dynamically required. Note that this may be false while * {@link #isOriginallyRequired(String)} is true. * This may happen in the case where this field is bound to nested property id where the leaf is required but * one of its ancestors is not required and is dynamically null. For example, street may be required in Address but * contact.mailingAddress is not required and dynamically null. In this scenario, the street field may be currently * not required, since it's ancestor (contact.mailingAddress) is null. If contact.mailingAddress is set, * then the street field becomes required. * * @param propertyId property id to identify field to set * @param isRequired true if required */ public void setDynamicallyRequired(String propertyId, boolean isRequired) { getFormField(propertyId).setDynamicallyRequired(isRequired); } /** * Sets whether or not field is enabled. * * @param propertyId property id to identify field to set * @param isEnabled true if enabled */ public void setEnabled(String propertyId, boolean isEnabled) { getFormField(propertyId).setEnabled(isEnabled); } /** * Asks if this field is originally read-only, irrespective of view-mode or security permissions. * * @param propertyId property id * @return true if this field is read-only */ public boolean isOriginallyReadOnly(String propertyId) { return getFormField(propertyId).isOriginallyReadOnly(); } /** * Sets whether or not field is read-only, irrespective of view-mode or security permissions. * * @param propertyId property id to identify field to set * @param isReadOnly true if read-only */ public void setOriginalReadOnly(String propertyId, boolean isReadOnly) { getFormField(propertyId).setOriginallyReadOnly(isReadOnly); } /** * Sets whether or not field is dynamically read-only, based on view-mode or security permissions. * * @param propertyId property id to identify field to set * @param isReadOnly true if read-only */ public void setDynamicallyReadOnly(String propertyId, boolean isReadOnly) { getFormField(propertyId).setDynamicallyReadOnly(isReadOnly); } /** * Sets whether or not all fields are read-only, based on view-mode or security permissions. * * @param isReadOnly true if read-only */ public void setDynamicallyReadOnly(boolean isReadOnly) { Collection<FormField> formFields = getFormFields(); for (FormField formField : formFields) { formField.setDynamicallyReadOnly(isReadOnly); } } /** * Restores original read-only setting for all fields, if they were temporarily changed for view-only mode or * security permissions. */ public void restoreIsReadOnly() { Collection<FormField> formFields = getFormFields(); for (FormField formField : formFields) { formField.restoreIsReadOnly(); } } /** * Applies security permissions to all fields. */ public void applySecurity() { Collection<FormField> formFields = getFormFields(); for (FormField formField : formFields) { if (formField.getField() instanceof SelectField) { SelectField selectField = (SelectField) formField.getField(); String toOneType = selectField.getEntitySelect().getType().getName(); if (!securityService.getCurrentUser().isEditAllowed(getType().getName(), formField.getPropertyId()) || !securityService.getCurrentUser().isViewAllowed(toOneType) || selectField.getEntitySelect().getResults().getResultsFieldSet().getViewablePropertyIds() .isEmpty()) { formField.setDynamicallyReadOnly(true); } else { formField.restoreIsReadOnly(); } } else { if (!securityService.getCurrentUser().isEditAllowed(getType().getName(), formField.getPropertyId())) { formField.setDynamicallyReadOnly(true); } else { formField.restoreIsReadOnly(); } } if (securityService.getCurrentUser().isViewAllowed(getType().getName(), formField.getPropertyId())) { formField.allowView(); } else { formField.denyView(); } } } /** * Applies security permissions to SelectFields only in SearchForm */ public void applySecurityToSearchFormFields() { Collection<FormField> formFields = getFormFields(); for (FormField formField : formFields) { if (formField.getField() instanceof SelectField) { SelectField selectField = (SelectField) formField.getField(); String toOneType = selectField.getEntitySelect().getType().getName(); if (!securityService.getCurrentUser().isViewAllowed(toOneType) || selectField.getEntitySelect() .getResults().getResultsFieldSet().getViewablePropertyIds().isEmpty()) { formField.setDynamicallyReadOnly(true); } else { formField.restoreIsReadOnly(); } formField.allowView(); } } } /** * Sets the value of the field. * * @param value value of field */ public void setValue(String propertyId, Object value) { getFormField(propertyId).setValue(value); } /** * Sets component error. * * @param propertyId property id to identify field to set * @param errorMessage error message */ public void setComponentError(String propertyId, ErrorMessage errorMessage) { Assert.PROGRAMMING.instanceOf(getFormField(propertyId).getField(), AbstractComponent.class); AbstractComponent abstractComponent = (AbstractComponent) getFormField(propertyId).getField(); abstractComponent.setComponentError(errorMessage); } /** * Adds change listener to field. * * @param propertyId property id to identify field to set * @param target target of the listener * @param methodName listener method to invoke */ public void addValueChangeListener(String propertyId, Object target, String methodName) { FormField formField = (FormField) getField(propertyId); formField.addValueChangeListener(target, methodName); } /** * Asks if this form is EntityForm. * * @return true if EntityForm */ public boolean isEntityForm() { return form instanceof EntityForm; } @Override public String toString() { return "FormFieldFieldSet{" + "type.name=" + getType().getName() + ", form.type.name=" + getForm().getType().getName() + '}'; } /** * Delegate that contains methods for handling add and remove actions */ public static class AddRemoveTabMethodDelegate { private MethodDelegate addTabMethodDelegate; private MethodDelegate removeTabMethodDelegate; private AddRemoveTabMethodDelegate(MethodDelegate addTabMethodDelegate, MethodDelegate removeTabMethodDelegate) { this.addTabMethodDelegate = addTabMethodDelegate; this.removeTabMethodDelegate = removeTabMethodDelegate; } /** * Gets delegate for handling add tab action. * * @return delegate for handling add tab action */ public MethodDelegate getAddTabMethodDelegate() { return addTabMethodDelegate; } /** * Gets delegate for handling remove tab action. * * @return delegate for handling remove tab action */ public MethodDelegate getRemoveTabMethodDelegate() { return removeTabMethodDelegate; } } }