/** * *************************************************************************** * Copyright (c) 2010 Qcadoo Limited * Project: Qcadoo Framework * Version: 1.4 * * This file is part of Qcadoo. * * Qcadoo is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero 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 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************** */ package com.qcadoo.view.internal.components.form; import com.qcadoo.model.api.*; import com.qcadoo.model.api.expression.ExpressionUtils; import com.qcadoo.model.api.validators.ErrorMessage; import com.qcadoo.model.internal.DetachedEntityTreeImpl; import com.qcadoo.security.api.SecurityRole; import com.qcadoo.security.api.SecurityRolesService; import com.qcadoo.view.api.ComponentState; import com.qcadoo.view.api.components.FieldComponent; import com.qcadoo.view.api.components.FormComponent; import com.qcadoo.view.internal.FieldEntityIdChangeListener; import com.qcadoo.view.internal.ScopeEntityIdChangeListener; import com.qcadoo.view.internal.components.FieldComponentState; import com.qcadoo.view.internal.components.lookup.LookupComponentState; import com.qcadoo.view.internal.components.tree.TreeComponentState; import com.qcadoo.view.internal.states.AbstractContainerState; import org.json.JSONException; import org.json.JSONObject; import java.util.*; public class FormComponentState extends AbstractContainerState implements FormComponent { public static final String JSON_ENTITY_ID = "entityId"; public static final String JSON_IS_ACTIVE = "isActive"; public static final String JSON_VALID = "valid"; public static final String JSON_BACK_REQUIRED = "performBackRequired"; public static final String JSON_HEADER = "header"; public static final String JSON_HEADER_ENTITY_IDENTIFIER = "headerEntityIdentifier"; public static final String INITIALIZE_EVENT_NAME = "initialize"; private Long entityId; private Long contextEntityId; private boolean active; private boolean valid = true; private final Map<String, Object> context = new HashMap<String, Object>(); private final FormEventPerformer eventPerformer = new FormEventPerformer(); private final String expressionEdit; private Map<String, FieldComponentState> fieldComponents; private final String expressionNew; private boolean performBackRequired = false; private final SecurityRole authorizationRole; private final SecurityRolesService securityRolesService; private final FormComponentPattern pattern; public FormComponentState(final FormComponentPattern pattern) { super(pattern); this.pattern = pattern; this.expressionNew = pattern.getExpressionNew(); this.expressionEdit = pattern.getExpressionEdit(); this.authorizationRole = pattern.getAuthorizationRole(); this.securityRolesService = pattern.getApplicationContext().getBean(SecurityRolesService.class); registerEvent("clear", eventPerformer, "clear"); registerEvent("save", eventPerformer, "save"); registerEvent("saveAndClear", eventPerformer, "saveAndClear"); registerEvent(INITIALIZE_EVENT_NAME, eventPerformer, INITIALIZE_EVENT_NAME); registerEvent("initializeAfterBack", eventPerformer, INITIALIZE_EVENT_NAME); registerEvent("reset", eventPerformer, INITIALIZE_EVENT_NAME); registerEvent("delete", eventPerformer, "delete"); registerEvent("copy", eventPerformer, "copy"); registerEvent("activate", eventPerformer, "activate"); registerEvent("deactivate", eventPerformer, "deactivate"); } @Override public void onFieldEntityIdChange(final Long entityId) { setFieldValue(entityId); eventPerformer.initialize(new String[0]); } @Override protected void initializeContent(final JSONObject json) throws JSONException { if (!json.has(JSON_ENTITY_ID)) { return; } if (json.isNull(JSON_ENTITY_ID)) { entityId = null; } else { entityId = json.getLong(JSON_ENTITY_ID); } } @Override @SuppressWarnings("unchecked") protected void initializeContext(final JSONObject json) throws JSONException { super.initializeContext(json); Iterator<String> iterator = json.keys(); while (iterator.hasNext()) { String field = iterator.next(); if ("id".equals(field)) { if (entityId == null) { contextEntityId = json.getLong(field); } } else if (!json.isNull(field)) { context.put(field, json.get(field)); } } } /* * (non-Javadoc) * @see com.qcadoo.view.components.form.EntityComponentState#getEntityId() */ @Override public Long getEntityId() { return entityId; } public void setEntityId(final Long entityId) { this.entityId = entityId; requestRender(); requestUpdateState(); notifyEntityIdChangeListeners(entityId); } @Override public void setFieldValue(final Object value) { setEntityId((Long) value); } /* * (non-Javadoc) * @see com.qcadoo.view.components.form.EntityComponentState#getEntity() */ @Override public Entity getEntity() { Entity entity = getDataDefinition().create(entityId); copyFieldsAndContextTo(entity); return entity; } @Override public Entity getPersistedEntityWithIncludedFormValues() { if (entityId == null) { return getEntity(); } Entity entity = getDataDefinition().get(entityId); if (entity == null) { return getEntity(); } copyFieldsAndContextTo(entity); return entity; } private void copyFieldsAndContextTo(final Entity entity) { copyFieldsToEntity(entity); copyContextToEntity(entity); } @Override public void setEntity(final Entity entity) { if (entity.isValid()) { active = entity.isActive(); } else { valid = false; requestRender(); copyMessages(entity.getGlobalErrors()); } copyEntityToFields(entity, entity.isValid()); setEntityId(entity.getId()); setFieldsRequiredAndDisables(); } @Override public boolean isValid() { return valid; } @Override public boolean isHasError() { // form never has error - its field can have for (ComponentState child : getChildren().values()) { if (child.isHasError()) { return true; } } return false; } @Override public Object getFieldValue() { return getEntityId(); } @Override public JSONObject render() throws JSONException { JSONObject json = super.render(); json.put(JSON_BACK_REQUIRED, performBackRequired); return json; } @Override protected JSONObject renderContent() throws JSONException { JSONObject json = new JSONObject(); json.put(JSON_VALID, isValid()); json.put(JSON_IS_ACTIVE, active); if (entityId == null) { json.put(JSON_ENTITY_ID, JSONObject.NULL); json.put(JSON_HEADER, getTranslationService().translate(getTranslationPath() + ".headerNew", getLocale())); json.put(JSON_HEADER_ENTITY_IDENTIFIER, getHeaderNew()); } else { json.put(JSON_ENTITY_ID, entityId); json.put(JSON_HEADER, getTranslationService().translate(getTranslationPath() + ".headerEdit", getLocale())); json.put(JSON_HEADER_ENTITY_IDENTIFIER, getHeaderEdit()); } return json; } private String getHeaderEdit() { Entity entity = getDataDefinition().get(entityId); return ExpressionUtils.getValue(entity, expressionEdit, getLocale()); } private Object getHeaderNew() { if (expressionNew == null) { return JSONObject.NULL; } else { return ExpressionUtils.getValue(getEntity(), expressionNew, getLocale()); } } private Map<String, FieldComponentState> getFieldComponents() { if (fieldComponents != null) { return fieldComponents; } fieldComponents = new HashMap<String, FieldComponentState>(); for (Map.Entry<String, FieldEntityIdChangeListener> field : getFieldEntityIdChangeListeners().entrySet()) { if (isValidFormField(field.getKey(), field.getValue())) { fieldComponents.put(field.getKey(), (FieldComponentState) field.getValue()); } } for (Map.Entry<String, ScopeEntityIdChangeListener> field : getScopeEntityIdChangeListeners().entrySet()) { if (!(field.getValue() instanceof FieldComponent)) { continue; } fieldComponents.put(field.getKey(), (FieldComponentState) field.getValue()); } return fieldComponents; } private boolean isValidFormField(final String fieldName, final FieldEntityIdChangeListener component) { if (!(component instanceof FieldComponent)) { return false; } FieldDefinition field = getDataDefinition().getField(fieldName); if (field == null) { return false; } return true; } private void copyFieldsToEntity(final Entity entity) { FieldComponentState fieldComponentState = null; for (Map.Entry<String, FieldComponentState> field : getFieldComponents().entrySet()) { fieldComponentState = field.getValue(); if (fieldComponentState.isPersistent()) { entity.setField(field.getKey(), convertFieldFromString(fieldComponentState.getFieldValue(), field.getKey())); } if (fieldComponentState.isHasError()) { entity.setNotValid(); } } } private void copyContextToEntity(final Entity entity) { for (String field : getDataDefinition().getFields().keySet()) { if (context.containsKey(field)) { entity.setField(field, convertFieldFromString(context.get(field), field)); } } } private void setFieldsRequiredAndDisables() { for (Map.Entry<String, FieldComponentState> field : getFieldComponents().entrySet()) { FieldDefinition fieldDefinition = getDataDefinition().getField(field.getKey()); if (fieldDefinition.isRequired()) { field.getValue().setRequired(true); } if (fieldDefinition.isReadOnly()) { field.getValue().setEnabled(false); } } } private Object convertFieldFromString(final Object value, final String field) { if (value instanceof String) { return getDataDefinition().getField(field).getType().fromString((String) value, getLocale()); } else { return value; } } private void copyFieldMessages(final EntityMessagesHolder messagesHolder) { for (Map.Entry<String, FieldComponentState> fieldComponentEntry : getFieldComponents().entrySet()) { ErrorMessage message = messagesHolder.getError(fieldComponentEntry.getKey()); copyMessage(fieldComponentEntry.getValue(), message); } } private void copyEntityToFields(final Entity entity, final boolean requestUpdateState) { for (Map.Entry<String, FieldComponentState> field : getFieldComponents().entrySet()) { ErrorMessage message = entity.getError(field.getKey()); copyMessage(field.getValue(), message); if (fieldIsGridCorrespondingLookup(field.getValue(), field.getKey(), entity)) { continue; } if (fieldIsDetachedEntityTree(field.getValue(), field.getKey(), entity)) { EntityTree tree = entity.getTreeField(field.getKey()); if (tree != null) { ((TreeComponentState) field.getValue()).setRootNode(tree.getRoot()); } } field.getValue().setFieldValue(convertFieldToString(entity.getField(field.getKey()), field.getKey())); if (requestUpdateState) { field.getValue().requestComponentUpdateState(); } } } private boolean fieldIsGridCorrespondingLookup(final FieldComponentState field, final String databaseFieldName, final Entity entity) { return (field instanceof LookupComponentState) && (entity.getField(databaseFieldName) instanceof Collection); } private boolean fieldIsDetachedEntityTree(final Object fieldValue, final String databaseFieldName, final Entity entity) { return fieldValue instanceof TreeComponentState && entity.getField(databaseFieldName) instanceof DetachedEntityTreeImpl; } private Object convertFieldToString(final Object value, final String field) { if (value instanceof String) { return value; } if (value == null) { return ""; } if (value instanceof Collection) { return value; } return getDataDefinition().getField(field).getType().toString(value, getLocale()); } @Override public void setFormEnabled(final boolean enabled) { for (Map.Entry<String, FieldComponentState> field : getFieldComponents().entrySet()) { FieldDefinition fieldDefinition = getDataDefinition().getField(field.getKey()); if (!(fieldDefinition.isReadOnly())) { field.getValue().setEnabled(enabled); field.getValue().requestComponentUpdateState(); } } setEnabled(enabled); } private void setPerformBackRequired(final boolean backRequired) { this.performBackRequired = backRequired; } protected final class FormEventPerformer { public void saveAndClear(final String[] args) { save(args); if (isValid()) { clear(args); } } public void save(final String[] args) { Entity databaseEntity = getDatabaseEntity(); if (databaseEntity == null && entityId != null) { throw new IllegalStateException("Entity cannot be found"); } Entity entity = getEntity(); if (entity.isValid()) { entity = getDataDefinition().save(entity); setEntity(entity); } copyGlobalMessages(entity.getGlobalMessages()); if (entity.isValid()) { setFieldValue(entity.getId()); addTranslatedMessage(translateMessage("saveMessage"), MessageType.SUCCESS); } else { if (entity.getGlobalErrors().size() == 0) { addTranslatedMessage(translateMessage("saveFailedMessage"), MessageType.FAILURE); } valid = false; } setFieldsRequiredAndDisables(); } public void copy(final String[] args) { if (entityId == null) { addTranslatedMessage(translateMessage("copyFailedMessage"), MessageType.FAILURE); return; } List<Entity> copiedEntities = getDataDefinition().copy(entityId); if (!copiedEntities.isEmpty() && copiedEntities.get(0).getId() != null) { clear(args); setEntityId(copiedEntities.get(0).getId()); initialize(args); addTranslatedMessage(translateMessage("copyMessage"), MessageType.SUCCESS); } else { addTranslatedMessage(translateMessage("copyFailedMessage"), MessageType.FAILURE); } } public void activate(final String[] args) { if (entityId == null) { addTranslatedMessage(translateMessage("activateFailedMessage"), MessageType.FAILURE); return; } List<Entity> activatedEntities = getDataDefinition().activate(entityId); if (!activatedEntities.isEmpty()) { active = true; addTranslatedMessage(translateMessage("activateMessage"), MessageType.SUCCESS); setEntity(activatedEntities.get(0)); } } public void deactivate(final String[] args) { if (entityId == null) { addTranslatedMessage(translateMessage("deactivateFailedMessage"), MessageType.FAILURE); return; } List<Entity> deactivatedEntities = getDataDefinition().deactivate(entityId); if (!deactivatedEntities.isEmpty()) { active = false; addTranslatedMessage(translateMessage("deactivateMessage"), MessageType.SUCCESS); setEntity(deactivatedEntities.get(0)); } } public void delete(final String[] args) { Entity entity = getDatabaseEntity(); if (entity == null) { throw new IllegalStateException("Entity cannot be found"); } else if (entityId != null) { EntityOpResult result = getDataDefinition().delete(entityId); copyMessages(result.getMessagesHolder().getGlobalErrors()); copyFieldMessages(result.getMessagesHolder()); if (result.isSuccessfull()) { addTranslatedMessage(translateMessage("deleteMessage"), MessageType.SUCCESS); clear(args); setPerformBackRequired(true); } else { setPerformBackRequired(false); } } } public void initialize(final String[] args) { if (contextEntityId != null) { entityId = contextEntityId; } Entity entity = getDatabaseEntity(); if (entity != null) { active = entity.isActive(); copyEntityToFields(entity, true); setFieldValue(entity.getId()); setFieldsRequiredAndDisables(); if (!securityRolesService.canAccess(authorizationRole)) { setFormEnabled(false); } return; } if (entityId != null) { setFormEnabled(false); active = false; valid = false; addTranslatedMessage(translateMessage("entityNotFound"), MessageType.FAILURE); return; } clear(args); if (!securityRolesService.canAccess(authorizationRole)) { setFormEnabled(false); } } public void clear(final String[] args) { active = false; clearFields(); setFieldValue(null); copyDefaultValuesToFields(); setFieldsRequiredAndDisables(); } private Entity getDatabaseEntity() { if (entityId == null) { return null; } return getDataDefinition().get(entityId); } private void copyDefaultValuesToFields() { for (Map.Entry<String, FieldComponentState> field : getFieldComponents().entrySet()) { FieldDefinition fieldDefinition = getDataDefinition().getField(field.getKey()); if (fieldDefinition.getDefaultValue() != null) { field.getValue().setFieldValue(convertFieldToString(fieldDefinition.getDefaultValue(), field.getKey())); field.getValue().requestComponentUpdateState(); } } } private void clearFields() { for (Map.Entry<String, FieldComponentState> field : getFieldComponents().entrySet()) { field.getValue().setFieldValue(null); field.getValue().requestComponentUpdateState(); } } } @Override public FieldComponent findFieldComponentByName(final String name) { return (FieldComponent) findChild(name); } }