package org.sigmah.client.ui.presenter.admin.models; /* * #%L * Sigmah * %% * Copyright (C) 2010 - 2016 URD * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ import com.allen_sauer.gwt.log.client.Log; import com.extjs.gxt.ui.client.data.BaseModelData; import com.extjs.gxt.ui.client.event.BaseEvent; import com.extjs.gxt.ui.client.event.ButtonEvent; import com.extjs.gxt.ui.client.event.Events; import com.extjs.gxt.ui.client.event.FieldEvent; import com.extjs.gxt.ui.client.event.Listener; import com.extjs.gxt.ui.client.event.MessageBoxEvent; import com.extjs.gxt.ui.client.event.SelectionChangedEvent; import com.extjs.gxt.ui.client.event.SelectionChangedListener; import com.extjs.gxt.ui.client.event.SelectionListener; import com.extjs.gxt.ui.client.store.ListStore; import com.extjs.gxt.ui.client.widget.Dialog; import com.extjs.gxt.ui.client.widget.MessageBox; import com.extjs.gxt.ui.client.widget.Text; import com.extjs.gxt.ui.client.widget.form.CheckBox; import com.extjs.gxt.ui.client.widget.form.ComboBox; import com.extjs.gxt.ui.client.widget.form.Field; import com.extjs.gxt.ui.client.widget.form.SimpleComboBox; import com.extjs.gxt.ui.client.widget.form.TextField; import com.extjs.gxt.ui.client.widget.form.Validator; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.FlexTable; import com.google.inject.ImplementedBy; import com.google.inject.Inject; import com.google.inject.Singleton; import org.sigmah.client.dispatch.CommandResultHandler; import org.sigmah.client.dispatch.monitor.LoadingMask; import org.sigmah.client.event.UpdateEvent; import org.sigmah.client.event.handler.UpdateHandler; import org.sigmah.client.i18n.I18N; import org.sigmah.client.inject.Injector; import org.sigmah.client.page.Page; import org.sigmah.client.page.PageRequest; import org.sigmah.client.page.RequestParameter; import org.sigmah.client.ui.notif.N10N; import org.sigmah.client.ui.presenter.base.AbstractPagePresenter; import org.sigmah.client.ui.presenter.base.HasForm; import org.sigmah.client.ui.res.icon.IconImageBundle; import org.sigmah.client.ui.view.admin.models.EditFlexibleElementAdminView; import org.sigmah.client.ui.view.base.ViewPopupInterface; import org.sigmah.client.ui.widget.HasGrid; import org.sigmah.client.ui.widget.button.Button; import org.sigmah.client.ui.widget.form.FormPanel; import org.sigmah.client.ui.widget.form.ListComboBox; import org.sigmah.client.util.AdminUtil; import org.sigmah.client.util.ClientUtils; import org.sigmah.client.util.EnumModel; import org.sigmah.client.util.TypeModel; import org.sigmah.shared.command.CreateEntity; import org.sigmah.shared.command.GetCategories; import org.sigmah.shared.command.GetContactModels; import org.sigmah.shared.command.GetPrivacyGroups; import org.sigmah.shared.command.GetReportModels; import org.sigmah.shared.command.UpdateEntity; import org.sigmah.shared.command.result.CreateResult; import org.sigmah.shared.command.result.ListResult; import org.sigmah.shared.command.result.VoidResult; import org.sigmah.shared.computation.Computation; import org.sigmah.shared.computation.Computations; import org.sigmah.shared.computation.value.ComputedValues; import org.sigmah.shared.dto.ContactModelDTO; import org.sigmah.shared.dto.IsModel; import org.sigmah.shared.dto.OrgUnitBannerDTO; import org.sigmah.shared.dto.ProjectBannerDTO; import org.sigmah.shared.dto.base.AbstractModelDataEntityDTO; import org.sigmah.shared.dto.category.CategoryTypeDTO; import org.sigmah.shared.dto.element.BudgetElementDTO; import org.sigmah.shared.dto.element.BudgetRatioElementDTO; import org.sigmah.shared.dto.element.BudgetSubFieldDTO; import org.sigmah.shared.dto.element.ComputationElementDTO; import org.sigmah.shared.dto.element.ContactListElementDTO; import org.sigmah.shared.dto.element.FilesListElementDTO; import org.sigmah.shared.dto.element.FlexibleElementDTO; import org.sigmah.shared.dto.element.QuestionChoiceElementDTO; import org.sigmah.shared.dto.element.QuestionElementDTO; import org.sigmah.shared.dto.element.ReportElementDTO; import org.sigmah.shared.dto.element.ReportListElementDTO; import org.sigmah.shared.dto.element.TextAreaElementDTO; import org.sigmah.shared.dto.layout.LayoutConstraintDTO; import org.sigmah.shared.dto.layout.LayoutDTO; import org.sigmah.shared.dto.layout.LayoutGroupDTO; import org.sigmah.shared.dto.profile.PrivacyGroupDTO; import org.sigmah.shared.dto.referential.BudgetSubFieldType; import org.sigmah.shared.dto.referential.ContactModelType; import org.sigmah.shared.dto.referential.DefaultFlexibleElementType; import org.sigmah.shared.dto.referential.ElementTypeEnum; import org.sigmah.shared.dto.referential.LogicalElementType; import org.sigmah.shared.dto.referential.LogicalElementTypes; import org.sigmah.shared.dto.referential.TextAreaType; import org.sigmah.shared.dto.report.ReportModelDTO; import org.sigmah.shared.util.Collections; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; import org.sigmah.shared.computation.dependency.SingleDependency; /** * Presenter in charge of creating/editing a flexible element. * * @author Denis Colliot (dcolliot@ideia.fr) (v2.0) */ @Singleton public class EditFlexibleElementAdminPresenter extends AbstractPagePresenter<EditFlexibleElementAdminPresenter.View> implements HasForm { /** * Description of the view managed by this presenter. */ @ImplementedBy(EditFlexibleElementAdminView.class) public static interface View extends ViewPopupInterface, HasGrid<FlexibleElementDTO> { // -- // Common form components. // -- FormPanel getCommonForm(); Field<String> getNameField(); Field<Object> getNameReadOnlyField(); ComboBox<TypeModel> getTypeField(); ComboBox<BaseModelData> getContainerField(); ComboBox<LayoutGroupDTO> getLayoutGroupField(); Field<Number> getOrderField(); Field<Boolean> getMandatoryField(); ComboBox<PrivacyGroupDTO> getPrivacyGroupField(); Field<Boolean> getAmendableField(); Field<Boolean> getExportableField(); // -- // Specific form components. // -- FormPanel getSpecificForm(); Field<Boolean> getBannerField(); SimpleComboBox<Integer> getBannerPositionField(); Field<String> getCodeField(); Field<Number> getLengthField(); Field<Boolean> getDecimalField(); Field<Number> getMinLimitField(); Field<Number> getMaxLimitField(); Field<Date> getMinDateField(); Field<Date> getMaxDateField(); ComboBox<ReportModelDTO> getReportModelField(); Field<Boolean> getMultipleChoicesField(); Field<Boolean> getQualityLinkField(); ComboBox<CategoryTypeDTO> getCategoryTypeField(); Field<String> getCustomChoiceField(); Button getCustomChoiceAddButton(); FlexTable getBudgetFields(); FlexTable getRatioFlexTable(); ComboBox<FlexibleElementDTO> getBudgetSubFieldSpentCombo(); ComboBox<FlexibleElementDTO> getBudgetSubFieldPlannedCombo(); ComboBox<BudgetSubFieldDTO> getUpBudgetSubFieldCombo(); ComboBox<BudgetSubFieldDTO> getDownBudgetSubFieldCombo(); ListStore<BudgetSubFieldDTO> getUpBudgetSubFieldStore(); ListStore<FlexibleElementDTO> getBudgetSubFieldSpentStore(); ListStore<FlexibleElementDTO> getBudgetSubFieldPlannedStore(); ListStore<BudgetSubFieldDTO> getDownBudgetSubFieldStore(); Anchor getAnchorAddSubField(); void clearBudgetFields(); TextField<String> getFormulaField(); ComboBox<EnumModel<ContactModelType>> getContactListTypeFilter(); ListComboBox<ContactModelDTO> getContactListModelsFilter(); TextField<Number> getContactListLimit(); CheckBox getContactIsMember(); // -- // Methods. // -- Button getSaveButton(); /** * Clears the forms. */ void clear(); /** * Initializes the given {@code elementType} specific form fields. * * @param elementType * The flexible element type, may be {@code null}. */ void setSpecificFieldsVisibility(LogicalElementType elementType); /** * Initializes the given {@code textAreaType} specific form fields. * * @param textAreaType * The text area type, may be {@code null}. */ void setTextAreaSpecificFieldsVisibility(TextAreaType textAreaType); /** * Adds the given {@code customChoice} as a new custom choice label. * * @param customChoice * The custom choice label. * @param deleteHandler * The delete handler triggered if the label is deleted. */ void addCustomChoice(String customChoice, ClickHandler deleteHandler); /** * Adds the given {@code customChoice} as an existing custom that can't be deleted. * * @param customChoice * The custom choice label. * @param checked * Initial value of the checkbox. * @param disableHandler * The disable handler triggered if the associated checkbox is selected. */ void addUndeletableCustomChoice(String customChoice, boolean checked, Listener<FieldEvent> disableHandler); /** * Sets the custom choices add fields enabled state. * * @param enabled * {@code true} to enable the fields, {@code false} to disable them. */ void setCustomChoiceAddFieldEnabled(boolean enabled); } /** * Banner positions. */ private static final int BANNER_POSITIONS_MIN = 1; private static final int BANNER_POSITIONS_MAX = 6; private static final int CARD_POSITIONS_MIN = 1; private static final int CARD_POSITIONS_MAX = 10; /** * Default category type. */ private static final CategoryTypeDTO DEFAULT_CATEGORY_TYPE = new CategoryTypeDTO(I18N.CONSTANTS.adminFlexibleNoLinkedCategory()); /** * HTML new line tag. */ private static final String HTML_TAG_NEW_LINE = "<br>"; /** * The current model. Should never be {@code null}. */ private IsModel currentModel; /** * The edited {@link FlexibleElementDTO}, or {@code null} in case of creation. */ private FlexibleElementDTO flexibleElement; /** * Old flexible element properties map. */ private Map<String, Object> oldFieldProperties;; /** * Custom choices labels. */ private Set<String> customChoices; /** * Disabled custom choices labels. */ private Set<String> disabledCustomChoices; /** * List of every other flexible elements of this model. */ private List<FlexibleElementDTO> otherElements; private List<ContactModelDTO> availableContactModels; /** * Presenter's initialization. * * @param view * The view managed by the presenter. * @param injector * The application injector. */ @Inject protected EditFlexibleElementAdminPresenter(final View view, final Injector injector) { super(view, injector); } /** * {@inheritDoc} */ @Override public Page getPage() { return Page.ADMIN_EDIT_FLEXIBLE_ELEMENT; } /** * {@inheritDoc} */ @Override public void onBind() { customChoices = new HashSet<String>(); disabledCustomChoices = new HashSet<String>(); // -- // Type field select handler. // -- view.getTypeField().addListener(Events.Select, new Listener<BaseEvent>() { @Override public void handleEvent(final BaseEvent be) { final String code = view.getCodeField().getValue(); final LogicalElementType type = TypeModel.getType(view.getTypeField().getValue()); loadFlexibleElementSpecificFields(flexibleElement, type); if (type == ElementTypeEnum.FILES_LIST || type == ElementTypeEnum.REPORT || type == ElementTypeEnum.REPORT_LIST) { view.getExportableField().hide(); view.getExportableField().clear(); } else { view.getExportableField().show(); view.getExportableField().setValue(flexibleElement != null ? flexibleElement.getExportable() : null); } view.getCodeField().setValue(code); } }); // -- // Container field change handler. // -- view.getContainerField().addListener(Events.Select, new Listener<BaseEvent>() { @Override public void handleEvent(final BaseEvent be) { final BaseModelData hasLayout = view.getContainerField().getValue(); final LayoutDTO selectedContainer = EditLayoutGroupAdminPresenter.getLayout(hasLayout); if (hasLayout instanceof ProjectBannerDTO || hasLayout instanceof OrgUnitBannerDTO) { view.getBannerField().setValue(true); // Updates the bannerPosition field. } view.getLayoutGroupField().getStore().removeAll(); view.getLayoutGroupField().disable(); if (selectedContainer != null) { List<LayoutGroupDTO> groups = selectedContainer.getGroups(); if(flexibleElement != null && (flexibleElement.getElementType() == ElementTypeEnum.DEFAULT || flexibleElement.getElementType() == ElementTypeEnum.DEFAULT_CONTACT)) { // iterative groups are not available for default fields Iterator<LayoutGroupDTO> it = groups.iterator(); while(it.hasNext()) { LayoutGroupDTO group = it.next(); if(group.getHasIterations()) { it.remove(); } } } view.getLayoutGroupField().getStore().add(groups); view.getLayoutGroupField().getStore().commitChanges(); view.getLayoutGroupField().setValue(view.getLayoutGroupField().getStore().getAt(0)); view.getLayoutGroupField().enable(); } } }); // -- // Banner field change handler. // -- view.getBannerField().addListener(Events.Change, new Listener<BaseEvent>() { @Override public void handleEvent(final BaseEvent be) { final boolean checked = ClientUtils.isTrue(view.getBannerField().getValue()); view.getBannerPositionField().setValue(null); view.getBannerPositionField().setEnabled(checked); view.getBannerPositionField().setAllowBlank(!checked); } }); // -- // Custom choice add button handler. // -- view.getCustomChoiceAddButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(final ButtonEvent ce) { onAddCustomChoice(view.getCustomChoiceField().getValue()); } }); // -- // Category type. // -- view.getCategoryTypeField().addListener(Events.Select, new Listener<FieldEvent>() { @Override public void handleEvent(final FieldEvent event) { final CategoryTypeDTO value = view.getCategoryTypeField().getValue(); view.setCustomChoiceAddFieldEnabled(value == null || DEFAULT_CATEGORY_TYPE.equals(value)); } }); // -- // add sub budget field // -- view.getAnchorAddSubField().addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { if (flexibleElement instanceof BudgetElementDTO) { BudgetElementDTO budgetElementDTO = (BudgetElementDTO) flexibleElement; BudgetSubFieldDTO budgetSubFieldDTO = new BudgetSubFieldDTO(); budgetElementDTO.getBudgetSubFields().add(budgetSubFieldDTO); eventBus.navigateRequest(Page.ADMIN_EDIT_FLEXIBLE_ELEMENT_ADD_BUDGETSUBFIELD.request().addData(RequestParameter.DTO, budgetSubFieldDTO)); } } }); // -- // Button save handler. // -- view.getSaveButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(final ButtonEvent ce) { onSaveAction(); } }); // -- // Handlers // -- registerHandler(eventBus.addHandler(UpdateEvent.getType(), new UpdateHandler() { @Override public void onUpdate(final UpdateEvent event) { if (event.concern(UpdateEvent.EDIT_FLEXIBLEELEMNT_EDIT_BUDGETSUBFIELD)) { loadFlexibleElement(flexibleElement); } } })); // -- // Computation rule validation. // -- view.getFormulaField().setValidator(new Validator() { @Override public String validate(Field<?> field, String value) { if (value == null || value.trim().isEmpty()) { return null; } final Computation computation = Computations.parse(value, otherElements); if (computation != null && !computation.isBadFormula()) { final Set<String> badReferences = computation.getBadReferences(); if (!badReferences.isEmpty()) { final String references = Collections.join(badReferences, ", "); if (computation.getBadReferences().size() == 1) { return I18N.MESSAGES.adminFlexibleComputationRuleBadReference(references); } else { return I18N.MESSAGES.adminFlexibleComputationRuleBadReferences(references); } } } else { return I18N.CONSTANTS.adminFlexibleComputationRuleBadFormula(); } return null; } }); // -- // Code edition. // -- view.setGridEventHandler(new HasGrid.GridEventHandler<FlexibleElementDTO>() { @Override public void onRowClickEvent(final FlexibleElementDTO rowElement) { MessageBox.prompt(I18N.CONSTANTS.adminFlexibleCode(), I18N.MESSAGES.adminFlexibleEditCode(rowElement.getFormattedLabel()), false, new Listener<MessageBoxEvent>() { @Override public void handleEvent(MessageBoxEvent be) { // OK. if (Dialog.OK.equals(be.getButtonClicked().getItemId())) { final String code = be.getValue(); onRenameCodeAction(rowElement, code); } } }); } }); } /** * {@inheritDoc} */ @Override public void onPageRequest(final PageRequest request) { setPageTitle(I18N.CONSTANTS.adminFlexible()); oldFieldProperties = new HashMap<String, Object>(); // Reads parameters/data from request. currentModel = request.getData(RequestParameter.MODEL); flexibleElement = request.getData(RequestParameter.DTO); otherElements = request.getData(RequestParameter.ELEMENTS); if (currentModel == null) { hideView(); throw new IllegalArgumentException("Invalid required model."); } // Forms reset. view.clear(); // Loads static values. loadStaticValues(); // Loads containers. loadContainers(currentModel); // Change the form according to the maintenance state. loadUnderMaintenanceState(currentModel); // Loads the privacy groups. loadPrivacyGroups(flexibleElement); // Loads reports models. loadReportModels(flexibleElement); // Loads category types. loadCategoryTypes(flexibleElement); // Loads the other fields of the flexible element. loadFlexibleElement(flexibleElement); } /** * {@inheritDoc} */ @Override public FormPanel[] getForms() { return new FormPanel[] { view.getCommonForm(), view.getSpecificForm() }; } // --------------------------------------------------------------------------------------------------------------- // // UTILITY METHODS. // // --------------------------------------------------------------------------------------------------------------- /** * Returns <code>true</code> if the user is updating an existing flexible * element and its creation date is prior to the maintenance start date. * * @return <code>true</code> if updating an existing flexible element and */ private boolean isUpdateAndUnderMaintenance() { return flexibleElement != null && currentModel.isUnderMaintenance() && (flexibleElement.getCreationDate() == null || flexibleElement.getCreationDate().before(currentModel.getDateMaintenance())); } /** * <p> * Loads the given {@code flexibleElement} <b>common fields</b> and sets the corresponding form fields values. * </p> * <p> * Executes {@link #loadFlexibleElementSpecificFields(FlexibleElementDTO, ElementTypeEnum)} method. * </p> * * @param flexibleElement * The edited flexible element, may be {@code null}. */ private void loadFlexibleElement(final FlexibleElementDTO flexibleElement) { final LogicalElementType type = LogicalElementTypes.of(flexibleElement); final boolean defaultFlexibleElement = type.toDefaultFlexibleElementType() != null; boolean isBudgetRatioElement = type == DefaultFlexibleElementType.BUDGET_RATIO; view.getNameField().setVisible(!defaultFlexibleElement || isBudgetRatioElement); view.getNameReadOnlyField().setVisible(defaultFlexibleElement && !isBudgetRatioElement); view.getTypeField().setEnabled(flexibleElement == null); view.getExportableField().setValue(true); loadFlexibleElementSpecificFields(flexibleElement, type); view.getCodeField().setValue("field" + otherElements.size()); if (flexibleElement != null) { // -- // Common properties. // -- view.getNameField().setValue(flexibleElement.getFormattedLabel()); view.getNameReadOnlyField().setValue(DefaultFlexibleElementType.getName(type.toDefaultFlexibleElementType())); view.getTypeField().setValue(new TypeModel(type)); view.getCodeField().setValue(flexibleElement.getCode()); // Banner constraint. final LayoutConstraintDTO bannerConstraint = flexibleElement.getBannerConstraint(); view.getBannerField().setValue(bannerConstraint != null); // Updates the bannerPosition field. view.getBannerPositionField().setSimpleValue(bannerConstraint != null ? bannerConstraint.getSortOrder() : null); // Layout constraint. final LayoutConstraintDTO constraint = flexibleElement.getConstraint(); view.getContainerField().setValue(flexibleElement.getContainerModel()); view.getLayoutGroupField().setValue(constraint != null ? constraint.getParentLayoutGroup() : null); view.getOrderField().setValue(constraint != null ? constraint.getSortOrder() : null); if (currentModel.getModelType().canHaveMandatoryFields()) { view.getMandatoryField().setValue(flexibleElement.getValidates()); } else { view.getMandatoryField().hide(); } view.getAmendableField().setValue(flexibleElement.getAmendable()); view.getExportableField().setValue(flexibleElement.getExportable()); // -- // Current ('OLD') properties map initialization. // Relies on the form fields values to avoid retrieving the data once again. // // This map initialization should be executed ONLY ONCE during presenter load process. // -- // Common properties. oldFieldProperties.put(AdminUtil.PROP_FX_NAME, view.getNameField().getValue()); oldFieldProperties.put(AdminUtil.PROP_FX_TYPE, type.toElementTypeEnum()); oldFieldProperties.put(AdminUtil.PROP_FX_IN_BANNER, view.getBannerField().getValue()); oldFieldProperties.put(AdminUtil.PROP_FX_POS_IN_BANNER, ClientUtils.getSimpleValue(view.getBannerPositionField())); oldFieldProperties.put(AdminUtil.PROP_FX_GROUP, view.getLayoutGroupField().getValue()); oldFieldProperties.put(AdminUtil.PROP_FX_ORDER_IN_GROUP, ClientUtils.getInteger(view.getOrderField().getValue())); oldFieldProperties.put(AdminUtil.PROP_FX_LC, constraint); // BUGFIX #719: sending the current banner constraint to avoid a null pointer exception. oldFieldProperties.put(AdminUtil.PROP_FX_LC_BANNER, flexibleElement.getBannerConstraint()); oldFieldProperties.put(AdminUtil.PROP_FX_IS_COMPULSARY, view.getMandatoryField().getValue()); oldFieldProperties.put(AdminUtil.PROP_FX_AMENDABLE, view.getAmendableField().getValue()); oldFieldProperties.put(AdminUtil.PROP_FX_EXPORTABLE, view.getExportableField().getValue()); // Specific properties. oldFieldProperties.put(AdminUtil.PROP_FX_TEXT_TYPE, TextAreaType.getCode(type.toTextAreaType())); oldFieldProperties.put(AdminUtil.PROP_FX_MIN_LIMIT, view.getMinLimitField().getValue()); oldFieldProperties.put(AdminUtil.PROP_FX_MAX_LIMIT, view.getMaxLimitField().getValue()); oldFieldProperties.put(AdminUtil.PROP_FX_LENGTH, ClientUtils.getInteger(view.getLengthField().getValue())); oldFieldProperties.put(AdminUtil.PROP_FX_DECIMAL, view.getDecimalField().getValue()); oldFieldProperties.put(AdminUtil.PROP_FX_Q_QUALITY, view.getQualityLinkField().getValue()); oldFieldProperties.put(AdminUtil.PROP_FX_Q_MULTIPLE, view.getMultipleChoicesField().getValue()); } } /** * <p> * Loads the given {@code flexibleElement} <b>specific fields</b> and sets the corresponding form fields values. * </p> * <p> * Executes {@link #loadFlexibleElementTextAreaFields(FlexibleElementDTO, TextAreaType)} method if the * {@code flexibleElement} is an instance of {@link TextAreaElementDTO}. * </p> * * @param flexibleElement * The edited flexible element, may be {@code null}. * @param type * The element type, may be {@code null}. */ private void loadFlexibleElementSpecificFields(final FlexibleElementDTO flexibleElement, final LogicalElementType type) { // clear specific element for bubget view.getBudgetFields().setVisible(false); view.getAnchorAddSubField().setVisible(false); view.getRatioFlexTable().setVisible(false); view.clearBudgetFields(); view.getUpBudgetSubFieldCombo().clearSelections(); view.getDownBudgetSubFieldCombo().clearSelections(); view.getUpBudgetSubFieldStore().removeAll(); view.getUpBudgetSubFieldStore().commitChanges(); view.getDownBudgetSubFieldStore().removeAll(); view.getDownBudgetSubFieldStore().commitChanges(); // Specific fields visibility. view.setSpecificFieldsVisibility(type); view.getBannerPositionField().disable(); view.getBannerPositionField().setAllowBlank(true); customChoices.clear(); disabledCustomChoices.clear(); if (flexibleElement instanceof FilesListElementDTO) { view.getMaxLimitField().setValue(((FilesListElementDTO) flexibleElement).getLimit()); } else if (flexibleElement instanceof TextAreaElementDTO || type.toElementTypeEnum() == ElementTypeEnum.TEXT_AREA) { loadFlexibleElementTextAreaFields(flexibleElement, type.toTextAreaType()); } else if (flexibleElement instanceof QuestionElementDTO) { final QuestionElementDTO questionElement = (QuestionElementDTO) flexibleElement; view.setCustomChoiceAddFieldEnabled(true); view.getQualityLinkField().setValue(questionElement.getQualityCriterion() != null); view.getMultipleChoicesField().setValue(questionElement.getMultiple()); view.getMultipleChoicesField().setEnabled(!isUpdateAndUnderMaintenance()); if (ClientUtils.isNotEmpty(questionElement.getChoices())) { for (final QuestionChoiceElementDTO choice : questionElement.getChoices()) { if(!isUpdateAndUnderMaintenance()) { onAddCustomChoice(choice.getLabel()); } else { onAddUndeletableCustomChoice(choice.getLabel(), !choice.isDisabled()); } } } } else if (flexibleElement instanceof BudgetElementDTO) { final BudgetElementDTO budgetElement = (BudgetElementDTO) flexibleElement; // Showing or hiding the fields depending on the maintenance state of the current model. view.getBudgetFields().setVisible(!isUpdateAndUnderMaintenance()); view.getUpBudgetSubFieldCombo().setVisible(!isUpdateAndUnderMaintenance()); view.getDownBudgetSubFieldCombo().setVisible(!isUpdateAndUnderMaintenance()); int row = 1; for (final BudgetSubFieldDTO budgetField : budgetElement.getBudgetSubFields()) { final Text budgetText = new Text(); budgetText.setData("budgetField", budgetField); budgetText.addStyleName("budget-sub-fields-text"); if (budgetField.getType() != null) { budgetField.setLabel(BudgetSubFieldType.getName(budgetField.getType())); } budgetText.setText(budgetField.getLabel()); view.getBudgetFields().setWidget(row, 0, budgetText); view.getBudgetFields().setWidget(row, 1, new TextField<String>()); if (budgetField.getType() == null) { Anchor anchorEditSubField = new Anchor(IconImageBundle.ICONS.editPage().getSafeHtml()); Anchor anchorDeleteSubField = new Anchor(IconImageBundle.ICONS.delete().getSafeHtml()); view.getBudgetFields().setWidget(row, 2, anchorEditSubField); view.getBudgetFields().setWidget(row, 3, anchorDeleteSubField); anchorEditSubField.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { eventBus.navigateRequest(Page.ADMIN_EDIT_FLEXIBLE_ELEMENT_ADD_BUDGETSUBFIELD.request().addData(RequestParameter.DTO, budgetField)); } }); anchorDeleteSubField.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { budgetElement.getBudgetSubFields().remove(budgetField); loadFlexibleElement(flexibleElement); } }); } budgetText.show(); if (budgetField.getId() != null) { view.getUpBudgetSubFieldStore().add(budgetField); view.getDownBudgetSubFieldStore().add(budgetField); } row++; } view.getUpBudgetSubFieldStore().commitChanges(); view.getDownBudgetSubFieldStore().commitChanges(); for (BudgetSubFieldDTO budgetField : budgetElement.getBudgetSubFields()) { // BUGFIX #706 if(budgetField.getId() != null) { if (budgetField.getId().equals(budgetElement.getRatioDividend().getId())) { view.getUpBudgetSubFieldCombo().setValue(budgetField); } if (budgetField.getId().equals(budgetElement.getRatioDivisor().getId())) { view.getDownBudgetSubFieldCombo().setValue(budgetField); } } } view.getSpecificForm().recalculate(); } else if (flexibleElement instanceof ComputationElementDTO) { final ComputationElementDTO computationElement = (ComputationElementDTO) flexibleElement; // Computation rule. final String formattedRule = Computations.formatRuleForEdition(computationElement.getRule(), otherElements); view.getFormulaField().setValue(formattedRule); // Minimum and maximum value. view.getMinLimitField().setValue(ComputedValues.from(computationElement.getMinimumValue(), false).get()); view.getMaxLimitField().setValue(ComputedValues.from(computationElement.getMaximumValue(), false).get()); } if (type == ElementTypeEnum.COMPUTATION) { // Related flexible elements code grid. addNumberTypeToStore(view.getStore()); } else if (type == ElementTypeEnum.CONTACT_LIST) { loadContactListOptions((ContactListElementDTO) flexibleElement); } if (type == DefaultFlexibleElementType.BUDGET_RATIO) { addNumberTypeToStore(view.getBudgetSubFieldSpentStore(), view.getBudgetSubFieldPlannedStore()); } if (flexibleElement instanceof BudgetRatioElementDTO) { final BudgetRatioElementDTO budgetRatioElementDTO = (BudgetRatioElementDTO) flexibleElement; if (budgetRatioElementDTO.getSpentBudget() != null) { view.getBudgetSubFieldSpentCombo().setSelection( java.util.Collections.singletonList(budgetRatioElementDTO.getSpentBudget())); } if (budgetRatioElementDTO.getPlannedBudget() != null) { view.getBudgetSubFieldPlannedCombo().setSelection( java.util.Collections.singletonList(budgetRatioElementDTO.getPlannedBudget())); } } } private void addNumberTypeToStore(ListStore<FlexibleElementDTO>... stores){ for (ListStore<FlexibleElementDTO> store : stores) { store.removeAll(); } for (final FlexibleElementDTO otherElement : otherElements) { // fields in iterative groups cannot be part of formula if(otherElement.getGroup().getHasIterations()) { continue; } final LogicalElementType otherType = LogicalElementTypes.of(otherElement); final ElementTypeEnum otherElementType = otherType.toElementTypeEnum(); if ((otherElementType == ElementTypeEnum.TEXT_AREA && otherType.toTextAreaType() == TextAreaType.NUMBER) || otherElementType == ElementTypeEnum.COMPUTATION) { for (ListStore<FlexibleElementDTO> store : stores) { store.add(otherElement); } } } } /** * Loads the given {@code flexibleElement} <b>text area fields</b> and sets the corresponding form fields values. * * @param flexibleElement * The edited flexible element of type {@link ElementTypeEnum#TEXT_AREA}. * @param textAreaType * The text area type, may be {@code null}. */ private void loadFlexibleElementTextAreaFields(final FlexibleElementDTO flexibleElement, final TextAreaType textAreaType) { view.setTextAreaSpecificFieldsVisibility(textAreaType); view.getMinDateField().setEnabled(!isUpdateAndUnderMaintenance()); view.getMaxDateField().setEnabled(!isUpdateAndUnderMaintenance()); view.getMinLimitField().setEnabled(!isUpdateAndUnderMaintenance()); view.getMaxLimitField().setEnabled(!isUpdateAndUnderMaintenance()); // Fires change event. if (flexibleElement instanceof TextAreaElementDTO) { final TextAreaElementDTO textAreaElement = (TextAreaElementDTO) flexibleElement; final Long minValue = textAreaElement.getMinValue(); final Long maxValue = textAreaElement.getMaxValue(); view.getMinLimitField().setValue(minValue); view.getMaxLimitField().setValue(maxValue); view.getLengthField().setValue(textAreaElement.getLength()); view.getDecimalField().setValue(textAreaElement.getIsDecimal()); view.getMinDateField().setValue(minValue != null ? new Date(minValue) : null); view.getMaxDateField().setValue(maxValue != null ? new Date(maxValue) : null); } } /** * Loads the static field values. */ private void loadStaticValues() { // Loads element types. final ListStore<TypeModel> store = view.getTypeField().getStore(); store.removeAll(); for (final LogicalElementType type : getLogicalElementTypes()) { if (type != ElementTypeEnum.DEFAULT && type != ElementTypeEnum.INDICATORS) { store.add(new TypeModel(type)); } } // Loads banner positions. view.getBannerPositionField().removeAll(); int minPosition; int maxPosition; switch (currentModel.getModelType()) { case ContactModel: minPosition = CARD_POSITIONS_MIN; maxPosition = CARD_POSITIONS_MAX; view.getBannerField().setFieldLabel(I18N.CONSTANTS.Admin_CARD()); view.getBannerPositionField().setFieldLabel(I18N.CONSTANTS.adminFlexibleCardPosition()); break; case OrgUnitModel: case ProjectModel: minPosition = BANNER_POSITIONS_MIN; maxPosition = BANNER_POSITIONS_MAX; view.getBannerField().setFieldLabel(I18N.CONSTANTS.Admin_BANNER()); view.getBannerPositionField().setFieldLabel(I18N.CONSTANTS.adminFlexibleBannerPosition()); break; default: throw new IllegalStateException("Unknown ModelType : " + currentModel.getModelType()); } for (int position = minPosition; position <= maxPosition; position++) { view.getBannerPositionField().add(position); } } /** * Loads and sort the logical element types. * * @return A collection of every logical element types. */ private Collection<LogicalElementType> getLogicalElementTypes() { final TreeSet<LogicalElementType> types = new TreeSet<LogicalElementType>(new Comparator<LogicalElementType>() { @Override public int compare(LogicalElementType o1, LogicalElementType o2) { return o1.getDescription().compareTo(o2.getDescription()); } }); for (final ElementTypeEnum type : ElementTypeEnum.values()) { if (type != ElementTypeEnum.TEXT_AREA) { types.add(type); } } for (final TextAreaType type : TextAreaType.values()) { types.add(type); } return types; } /** * Loads the containers and populates the corresponding form field. * * @param currentModel * The current model. */ private void loadContainers(final IsModel currentModel) { view.getContainerField().getStore().removeAll(); if (ClientUtils.isNotEmpty(currentModel.getHasLayoutElements())) { for (final AbstractModelDataEntityDTO<?> hasLayout : currentModel.getHasLayoutElements()) { view.getContainerField().getStore().add(hasLayout); } } view.getContainerField().getStore().commitChanges(); } /** * Change the state of the fields if the current model is under maintenance. * * @param currentModel * The current model. */ private void loadUnderMaintenanceState(final IsModel currentModel) { view.getAmendableField().setVisible(!currentModel.isUnderMaintenance()); } /** * Loads the privacy groups and populates the corresponding form field.<br> * If an edited flexible element is provided, the form field is set on the corresponding value. * * @param flexibleElement * The edited flexible element, or {@code null} in case of creation. */ private void loadPrivacyGroups(final FlexibleElementDTO flexibleElement) { view.getPrivacyGroupField().getStore().removeAll(); dispatch.execute(new GetPrivacyGroups(), new CommandResultHandler<ListResult<PrivacyGroupDTO>>() { @Override public void onCommandFailure(final Throwable caught) { if (Log.isErrorEnabled()) { Log.error("Error while loading the privacy groups.", caught); } N10N.error(I18N.CONSTANTS.adminChoiceProblem()); } @Override public void onCommandSuccess(final ListResult<PrivacyGroupDTO> result) { if (result == null || result.isEmpty()) { return; } view.getPrivacyGroupField().getStore().add(result.getList()); view.getPrivacyGroupField().getStore().commitChanges(); if (flexibleElement != null) { final PrivacyGroupDTO privacyGroup = flexibleElement.getPrivacyGroup(); view.getPrivacyGroupField().setValue(privacyGroup); oldFieldProperties.put(AdminUtil.PROP_FX_PRIVACY_GROUP, privacyGroup); } view.getPrivacyGroupField().clearInvalid(); } }); } /** * Loads the reports models and populates the corresponding form field.<br> * If an edited flexible element is provided, the form field is set on the corresponding value. * * @param flexibleElement * The edited flexible element, or {@code null} in case of creation. */ private void loadReportModels(final FlexibleElementDTO flexibleElement) { view.getReportModelField().getStore().removeAll(); dispatch.execute(new GetReportModels(), new CommandResultHandler<ListResult<ReportModelDTO>>() { @Override public void onCommandFailure(final Throwable caught) { if (Log.isErrorEnabled()) { Log.error("Error while loading the report models.", caught); } N10N.error(I18N.CONSTANTS.adminChoiceProblem()); } @Override public void onCommandSuccess(final ListResult<ReportModelDTO> result) { if (result == null || result.isEmpty()) { return; } // Retrieves report model id (in case of flexible element edition). final Integer reportModelId; if (flexibleElement instanceof ReportElementDTO || flexibleElement instanceof ReportListElementDTO) { reportModelId = flexibleElement.get(ReportElementDTO.MODEL_ID); } else { reportModelId = null; } ReportModelDTO selectedValue = null; // Populates the field store and detects selected value (if any). for (final ReportModelDTO reportModel : result.getList()) { view.getReportModelField().getStore().add(reportModel); if (reportModelId != null && reportModel.getId().equals(reportModelId)) { selectedValue = reportModel; } } view.getReportModelField().getStore().commitChanges(); view.getReportModelField().setValue(selectedValue); view.getReportModelField().clearInvalid(); oldFieldProperties.put(AdminUtil.PROP_FX_REPORT_MODEL, selectedValue); } }); } /** * Loads the category types and populates the corresponding form field.<br> * If an edited flexible element is provided, the form field is set on the corresponding value. * * @param flexibleElement * The edited flexible element, or {@code null} in case of creation. */ private void loadCategoryTypes(final FlexibleElementDTO flexibleElement) { view.getCategoryTypeField().getStore().removeAll(); dispatch.execute(new GetCategories(), new CommandResultHandler<ListResult<CategoryTypeDTO>>() { @Override public void onCommandFailure(final Throwable caught) { if (Log.isErrorEnabled()) { Log.error("Error while loading the category types.", caught); } N10N.error(I18N.CONSTANTS.adminChoiceProblem()); } @Override public void onCommandSuccess(final ListResult<CategoryTypeDTO> result) { if (result == null || result.isEmpty()) { return; } view.getCategoryTypeField().getStore().add(DEFAULT_CATEGORY_TYPE); view.getCategoryTypeField().getStore().add(result.getList()); view.getCategoryTypeField().getStore().commitChanges(); if (flexibleElement instanceof QuestionElementDTO) { view.getCategoryTypeField().setValue(((QuestionElementDTO) flexibleElement).getCategoryType()); } if (view.getCategoryTypeField().getValue() == null) { // If no value selected, default one is automatically selected. view.getCategoryTypeField().setValue(DEFAULT_CATEGORY_TYPE); } view.getCategoryTypeField().clearInvalid(); oldFieldProperties.put(AdminUtil.PROP_FX_Q_CATEGORY, view.getCategoryTypeField().getValue()); } }); } public void loadContactListOptions(final ContactListElementDTO flexibleElement) { view.getContactListModelsFilter().getListStore().removeAll(); view.getContactListModelsFilter().getAvailableValuesStore().removeAll(); dispatch.execute(new GetContactModels(null, true), new AsyncCallback<ListResult<ContactModelDTO>>() { @Override public void onFailure(Throwable caught) { Log.error("Error while getting available contact models.", caught); } @Override public void onSuccess(ListResult<ContactModelDTO> result) { availableContactModels = result.getList(); filterContactListModels(view.getContactListTypeFilter().getValue()); if (flexibleElement == null) { return; } Set<Integer> allowedModels = flexibleElement.getAllowedModelIds(); if (allowedModels == null || allowedModels.isEmpty()) { return; } for (ContactModelDTO contactModelDTO : result.getList()) { if (allowedModels.contains(contactModelDTO.getId())) { view.getContactListModelsFilter().getListStore().add(contactModelDTO); view.getContactListModelsFilter().getAvailableValuesStore().remove(contactModelDTO); } } } }); view.getContactListTypeFilter().getStore().removeAll(); for (ContactModelType contactModelType : ContactModelType.values()) { EnumModel<ContactModelType> enumModel = new EnumModel<ContactModelType>(contactModelType); view.getContactListTypeFilter().getStore().add(enumModel); if (flexibleElement != null && contactModelType == flexibleElement.getAllowedType()) { view.getContactListTypeFilter().setValue(enumModel); } } view.getContactListTypeFilter().removeAllListeners(); view.getContactListTypeFilter().addSelectionChangedListener(new SelectionChangedListener<EnumModel<ContactModelType>>() { @Override public void selectionChanged(final SelectionChangedEvent<EnumModel<ContactModelType>> event) { view.getContactListModelsFilter().getListStore().removeAll(); filterContactListModels(event.getSelectedItem()); if (event.getSelectedItem() != null && event.getSelectedItem().getEnum() == ContactModelType.ORGANIZATION) { view.getContactIsMember().show(); } else { view.getContactIsMember().hide(); view.getContactIsMember().setValue(false); } } }); view.getContactListLimit().setValue(flexibleElement != null ? flexibleElement.getLimit() : null); if (flexibleElement != null && flexibleElement.isMember()) { view.getContactIsMember().show(); view.getContactIsMember().setValue(true); } } private void filterContactListModels(final EnumModel<ContactModelType> type) { view.getContactListModelsFilter().getAvailableValuesStore().removeAll(); if (type == null) { view.getContactListModelsFilter().getAvailableValuesStore().add(availableContactModels); return; } for (ContactModelDTO contactModel : availableContactModels) { if (contactModel.getType() == type.getEnum()) { view.getContactListModelsFilter().getAvailableValuesStore().add(contactModel); } } } /** * Callback executed on custom choice add action.<br> * Does nothing if one of the arguments is {@code null} or if the {@code customChoice} is already present. * * @param customChoice * The custom choice value. */ private void onAddCustomChoice(final String customChoice) { view.getCustomChoiceField().clear(); if (ClientUtils.isBlank(customChoice) || customChoices.contains(customChoice)) { return; } view.addCustomChoice(customChoice, new ClickHandler() { @Override public void onClick(final ClickEvent event) { customChoices.remove(customChoice); view.getCategoryTypeField().setEnabled(ClientUtils.isEmpty(customChoices)); } }); customChoices.add(customChoice); view.getCategoryTypeField().setEnabled(false); } /** * Callback executed on custom choice add action.<br> * Does nothing if one of the arguments is {@code null} or if the {@code customChoice} is already present. * * @param customChoice * The custom choice value. */ private void onAddUndeletableCustomChoice(final String customChoice, boolean checked) { view.getCustomChoiceField().clear(); if (ClientUtils.isBlank(customChoice) || customChoices.contains(customChoice)) { return; } if(!checked) { disabledCustomChoices.add(customChoice); } view.addUndeletableCustomChoice(customChoice, checked, new Listener<FieldEvent>() { @Override public void handleEvent(FieldEvent be) { final Boolean value = (Boolean) be.getValue(); if(value != null && value) { disabledCustomChoices.remove(customChoice); } else { disabledCustomChoices.add(customChoice); } } }); customChoices.add(customChoice); view.getCategoryTypeField().setEnabled(false); } /** * Callback exectued when renaming an other flexible element. * * @param selectedElement * Flexible element to edit. * @param code * Code to set. */ private void onRenameCodeAction(final FlexibleElementDTO selectedElement, final String code) { final Map<String, Object> newFieldProperties = new HashMap<String, Object>(); newFieldProperties.put(AdminUtil.PROP_FX_CODE, code); newFieldProperties.put(AdminUtil.PROP_FX_FLEXIBLE_ELEMENT, selectedElement); newFieldProperties.put(AdminUtil.ADMIN_PROJECT_MODEL, currentModel); newFieldProperties.put(AdminUtil.ADMIN_ORG_UNIT_MODEL, currentModel); newFieldProperties.put(AdminUtil.ADMIN_CONTACT_MODEL, currentModel); newFieldProperties.put(AdminUtil.PROP_FX_OLD_FIELDS, new HashMap<String, Object>()); dispatch.execute(new UpdateEntity(currentModel, newFieldProperties), new CommandResultHandler<VoidResult>() { @Override protected void onCommandSuccess(VoidResult result) { selectedElement.setCode(code); view.getStore().update(selectedElement); } }, new LoadingMask(view.getGrid())); } /** * Callback executed on save button action. */ private void onSaveAction() { final String htmlName = ClientUtils.removeLastSuffix(view.getNameField().getValue(), HTML_TAG_NEW_LINE); // -- // Forms validation. // -- if (!FormPanel.valid(view.getCommonForm(), view.getSpecificForm())) { // Form(s) validation failed. return; } if (htmlName != null && htmlName.isEmpty()) { // Invalid HTML name. N10N.warn(I18N.CONSTANTS.form_validation_ko()); return; } // -- // Common properties. // -- final LogicalElementType logicalElementType = flexibleElement != null ? // BUGFIX #849: When disabled, GXT combo box can't be set and thus return null. // So instead of using the value of the combo box, the type is set from the edited element. LogicalElementTypes.of(flexibleElement) : TypeModel.getType(view.getTypeField().getValue()); final ElementTypeEnum type = logicalElementType.toElementTypeEnum(); final LayoutGroupDTO group = view.getLayoutGroupField().getValue(); final Integer order = ClientUtils.getInteger(view.getOrderField().getValue().intValue()); final Boolean mandatory = view.getMandatoryField().getValue(); final PrivacyGroupDTO privacyGroup = view.getPrivacyGroupField().getValue(); final Boolean amendable = view.getAmendableField().getValue(); final Boolean exportable = view.getExportableField().getValue(); final String code = view.getCodeField().getValue(); // A field cannot be in an iterative group AND in a computation field // + a computation field cannot be in an iterative group // + a core field cannot be in an iterative group LayoutGroupDTO groupToTest = group == null ? flexibleElement.getGroup() : group; if(groupToTest != null && groupToTest.getHasIterations() != null && groupToTest.getHasIterations()) { if(type == ElementTypeEnum.COMPUTATION) { N10N.warn(I18N.CONSTANTS.cannotAddComputationElementToIterativeGroup()); return; } if(amendable) { N10N.warn(I18N.CONSTANTS.cannotAddCoreElementToIterativeGroup()); return; } Collection<ComputationElementDTO> computationFields = getComputationElementsUsingField(flexibleElement); if(!computationFields.isEmpty()) { N10N.warn(I18N.MESSAGES.cannotAddComputationElementFormulaFieldToIterativeGroup( Collections.join(computationFields, new Collections.Mapper<ComputationElementDTO, String>() { @Override public String forEntry(ComputationElementDTO entry) { return "<span style=\"font-weight: bold\">" + entry.getLabel() + "</span>"; } }, ", "))); return; } } // -- // Specific properties. // -- final Boolean banner = view.getBannerField().getValue(); final Integer bannerPosition = ClientUtils.getSimpleValue(view.getBannerPositionField()); final TextAreaType textAreaType = logicalElementType.toTextAreaType(); final Integer length = ClientUtils.getInteger(view.getLengthField().getValue()); final Boolean decimal = view.getDecimalField().getValue(); final Integer maxLimit = ClientUtils.getInteger(view.getMaxLimitField().getValue()); final Integer minLimit = ClientUtils.getInteger(view.getMinLimitField().getValue()); final Long minLimitDate = ClientUtils.getTimestamp(view.getMinDateField().getValue()); final Long maxLimitDate = ClientUtils.getTimestamp(view.getMaxDateField().getValue()); final ReportModelDTO reportModel = view.getReportModelField().getValue(); final Boolean multiple = view.getMultipleChoicesField().getValue(); final CategoryTypeDTO category = view.getCategoryTypeField().getValue(); final FlexibleElementDTO budgetSpent = view.getBudgetSubFieldSpentCombo().getValue(); final FlexibleElementDTO budgetPlanned = view.getBudgetSubFieldPlannedCombo().getValue(); final String computationRule = Computations.formatRuleForServer(view.getFormulaField().getValue(), otherElements); final Number contactListLimit = view.getContactListLimit().getValue(); final boolean contactListIsMember = view.getContactIsMember().getValue(); final ContactModelType contactListType = view.getContactListTypeFilter().getValue() != null ? view.getContactListTypeFilter().getValue().getEnum() : null; final Set<Integer> contactListModelIds = new HashSet<Integer>(); for (ContactModelDTO contactModelDTO : view.getContactListModelsFilter().getListStore().getModels()) { contactListModelIds.add(contactModelDTO.getId()); } // -- // Initializing 'NEW' properties map. // -- final Map<String, Object> newFieldProperties = new HashMap<String, Object>(); newFieldProperties.put(AdminUtil.PROP_FX_NAME, htmlName); newFieldProperties.put(AdminUtil.PROP_FX_CODE, code); newFieldProperties.put(AdminUtil.PROP_FX_TYPE, (flexibleElement instanceof BudgetElementDTO) ? ElementTypeEnum.DEFAULT : type); newFieldProperties.put(AdminUtil.PROP_FX_GROUP, group); newFieldProperties.put(AdminUtil.PROP_FX_ORDER_IN_GROUP, order); newFieldProperties.put(AdminUtil.PROP_FX_IN_BANNER, banner); newFieldProperties.put(AdminUtil.PROP_FX_POS_IN_BANNER, bannerPosition); // Layout id for banner. newFieldProperties.put(AdminUtil.PROP_FX_IS_COMPULSARY, mandatory); newFieldProperties.put(AdminUtil.PROP_FX_PRIVACY_GROUP, privacyGroup); newFieldProperties.put(AdminUtil.PROP_FX_AMENDABLE, amendable); newFieldProperties.put(AdminUtil.PROP_FX_EXPORTABLE, exportable); newFieldProperties.put(AdminUtil.PROP_FX_TEXT_TYPE, textAreaType != null ? textAreaType.getCode() : null); newFieldProperties.put(AdminUtil.PROP_FX_LENGTH, length); newFieldProperties.put(AdminUtil.PROP_FX_MAX_LIMIT, maxLimit); newFieldProperties.put(AdminUtil.PROP_FX_MIN_LIMIT, minLimit); newFieldProperties.put(AdminUtil.PROP_BUDGET_SPENT, budgetSpent); newFieldProperties.put(AdminUtil.PROP_BUDGET_PLANNED, budgetPlanned); if (textAreaType == TextAreaType.DATE) { newFieldProperties.put(AdminUtil.PROP_FX_MAX_LIMIT, maxLimitDate); newFieldProperties.put(AdminUtil.PROP_FX_MIN_LIMIT, minLimitDate); } if (type == ElementTypeEnum.TEXT_AREA && decimal != null) { newFieldProperties.put(AdminUtil.PROP_FX_DECIMAL, decimal); } newFieldProperties.put(AdminUtil.PROP_FX_REPORT_MODEL, reportModel); newFieldProperties.put(AdminUtil.PROP_FX_Q_MULTIPLE, multiple); if (category != null && !DEFAULT_CATEGORY_TYPE.equals(category)) { newFieldProperties.put(AdminUtil.PROP_FX_Q_CATEGORY, category); } if (ClientUtils.isNotEmpty(customChoices)) { newFieldProperties.put(AdminUtil.PROP_FX_Q_CHOICES, new ArrayList<String>(customChoices)); } if (ClientUtils.isNotEmpty(disabledCustomChoices)) { newFieldProperties.put(AdminUtil.PROP_FX_Q_CHOICES_DISABLED, disabledCustomChoices); } List<BudgetSubFieldDTO> budgetSubFieldsToUpdate = new ArrayList<BudgetSubFieldDTO>(); if (view.getBudgetFields().getRowCount() > 0) { for (int i = 1; i < view.getBudgetFields().getRowCount(); i++) { if (view.getBudgetFields().getWidget(i, 0) != null) { Object budgetFieldData = ((Text) view.getBudgetFields().getWidget(i, 0)).getData("budgetField"); if (budgetFieldData != null) { ((BudgetSubFieldDTO) budgetFieldData).setFieldOrder(i); budgetSubFieldsToUpdate.add((BudgetSubFieldDTO) budgetFieldData); } } } newFieldProperties.put(AdminUtil.PROP_FX_B_BUDGETSUBFIELDS, budgetSubFieldsToUpdate); newFieldProperties.put(AdminUtil.PROP_FX_B_BUDGET_RATIO_DIVIDEND, view.getUpBudgetSubFieldCombo().getValue()); newFieldProperties.put(AdminUtil.PROP_FX_B_BUDGET_RATIO_DIVISOR, view.getDownBudgetSubFieldCombo().getValue()); } newFieldProperties.put(AdminUtil.PROP_FX_COMPUTATION_RULE, computationRule); newFieldProperties.put(AdminUtil.PROP_FX_CONTACT_LIST_LIMIT, contactListLimit); newFieldProperties.put(AdminUtil.PROP_FX_CONTACT_LIST_ALLOWED_TYPE, contactListType); newFieldProperties.put(AdminUtil.PROP_FX_CONTACT_LIST_ALLOWED_MODEL_IDS, contactListModelIds); newFieldProperties.put(AdminUtil.PROP_FX_CONTACT_LIST_IS_MEMBER, contactListIsMember); // -- // Logging old/new properties & filtering actual modifications. // -- if (Log.isDebugEnabled()) { final StringBuilder message = new StringBuilder(); message.append("New : ("); for (Map.Entry<String, Object> newP : newFieldProperties.entrySet()) { message.append(newP.getKey()).append('=').append(newP.getValue()).append(", "); } Log.debug(message.append(')').toString()); // Only keep actual changes. if (flexibleElement != null) { message.setLength(0); message.append("Old : ("); for (final Entry<String, Object> old : oldFieldProperties.entrySet()) { message.append(old.getKey()).append('=').append(old.getValue()).append(", "); if ((old.getValue() != null && old.getValue().equals(newFieldProperties.get(old.getKey()))) || (old.getValue() == null && newFieldProperties.get(old.getKey()) == null)) { newFieldProperties.remove(old.getKey()); } } Log.debug(message.append(')').toString()); } message.setLength(0); message.append("Register : ("); for (final Entry<String, Object> newP : newFieldProperties.entrySet()) { message.append(newP.getKey()).append('=').append(newP.getValue()).append(", "); } Log.debug(message.append(')').toString()); } // -- // Last properties map adjustments. // -- if (newFieldProperties.get(AdminUtil.PROP_FX_ORDER_IN_GROUP) != null) { // If order has changed force putting group. newFieldProperties.put(AdminUtil.PROP_FX_GROUP, group); } newFieldProperties.put(AdminUtil.PROP_FX_FLEXIBLE_ELEMENT, (flexibleElement != null) ? flexibleElement : new TextAreaElementDTO()); newFieldProperties.put(AdminUtil.ADMIN_PROJECT_MODEL, currentModel); newFieldProperties.put(AdminUtil.ADMIN_ORG_UNIT_MODEL, currentModel); newFieldProperties.put(AdminUtil.ADMIN_CONTACT_MODEL, currentModel); newFieldProperties.put(AdminUtil.PROP_FX_OLD_FIELDS, oldFieldProperties); // -- // Executing creation/update command. // -- dispatch.execute(new CreateEntity(currentModel.getEntityName(), newFieldProperties), new CommandResultHandler<CreateResult>() { @Override public void onCommandFailure(final Throwable caught) { N10N.error(I18N.CONSTANTS.adminFlexibleCreationBox(), I18N.MESSAGES.adminStandardCreationFailure(I18N.CONSTANTS.adminStandardFlexibleName() + " '" + htmlName + "'")); } @Override public void onCommandSuccess(final CreateResult result) { if (result == null) { N10N.warn(I18N.CONSTANTS.adminFlexibleCreationBox(), I18N.MESSAGES.adminStandardCreationNull(I18N.CONSTANTS.adminStandardFlexibleName() + " '" + htmlName + "'")); return; } final boolean update = flexibleElement != null; final IsModel updatedModel = (IsModel) result.getEntity(); FlexibleElementDTO updatedOrCreatedFlexibleElement = null; if (update) { // -- // UPDATE CASE - Retrieving 'updated' flexible element id. // -- for (final FlexibleElementDTO updatedFlexibleElement : updatedModel.getAllElements()) { if (updatedFlexibleElement.getId().equals(flexibleElement.getId())) { updatedOrCreatedFlexibleElement = updatedFlexibleElement; } } N10N.infoNotif(I18N.CONSTANTS.adminFlexibleCreationBox(), I18N.MESSAGES.adminStandardUpdateSuccess(I18N.CONSTANTS.adminStandardFlexibleName() + " '" + htmlName + "'")); } else { // -- // CREATION CASE - Retrieving 'created' flexible element id. // -- final List<Integer> oldFlexibleIds = new ArrayList<Integer>(); // Collects 'OLD' flexible elements ids. for (final FlexibleElementDTO oldFlexibleElement : otherElements) { oldFlexibleIds.add(oldFlexibleElement.getId()); } // Compares 'NEW' flexible elements ids with 'OLD' ones. for (final FlexibleElementDTO newFlexibleElement : updatedModel.getAllElements()) { if (!oldFlexibleIds.contains(newFlexibleElement.getId())) { updatedOrCreatedFlexibleElement = newFlexibleElement; } } N10N.infoNotif(I18N.CONSTANTS.adminFlexibleCreationBox(), I18N.MESSAGES.adminStandardCreationSuccess(I18N.CONSTANTS.adminStandardFlexibleName() + " '" + htmlName + "'")); } // Sends an update event to notify registered components. eventBus.fireEvent(new UpdateEvent(UpdateEvent.FLEXIBLE_ELEMENT_UPDATE, updatedModel, update, updatedOrCreatedFlexibleElement)); // Send an update event to reload necessary data. eventBus.fireEvent(new UpdateEvent(UpdateEvent.LAYOUT_GROUP_UPDATE, group)); hideView(); } }, view.getSaveButton()); } // --------------------------------------------------------------------------------------------------------------- // // UTILITY METHODS. // // --------------------------------------------------------------------------------------------------------------- /** * Find the computation fields using the given flexible element. * * @param flexibleElement * Flexible element. * @return A collection of every computation element using the given element. */ private Collection<ComputationElementDTO> getComputationElementsUsingField(final FlexibleElementDTO flexibleElement) { // FIXME: Should also search in the database since other project models may reference the given element. final ArrayList<ComputationElementDTO> computationElements = new ArrayList<ComputationElementDTO>(); final List<FlexibleElementDTO> allElements = view.getStore().getModels(); final SingleDependency dependency = new SingleDependency(flexibleElement); for (final FlexibleElementDTO other : otherElements) { if (other instanceof ComputationElementDTO) { final ComputationElementDTO computationElement = (ComputationElementDTO) other; final Computation computation = Computations.parse(computationElement.getRule(), allElements); if (computation.getDependencies().contains(dependency)) { computationElements.add(computationElement); } } } return computationElements; } }