Java tutorial
/* * Copyright (c) 2008-2016 Haulmont. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.haulmont.cuba.web.gui.components; import com.haulmont.bali.util.Preconditions; import com.haulmont.chile.core.datatypes.Datatype; import com.haulmont.chile.core.datatypes.Datatypes; import com.haulmont.chile.core.model.Instance; import com.haulmont.chile.core.model.MetaClass; import com.haulmont.chile.core.model.utils.InstanceUtils; import com.haulmont.cuba.core.entity.Entity; import com.haulmont.cuba.core.entity.SoftDelete; import com.haulmont.cuba.core.global.AppBeans; import com.haulmont.cuba.core.global.MessageTools; import com.haulmont.cuba.core.global.Messages; import com.haulmont.cuba.core.global.View; import com.haulmont.cuba.gui.ComponentsHelper; import com.haulmont.cuba.gui.DialogParams; import com.haulmont.cuba.gui.WindowManager; import com.haulmont.cuba.gui.WindowManager.OpenMode; import com.haulmont.cuba.gui.components.EntityLinkField; import com.haulmont.cuba.gui.components.Frame; import com.haulmont.cuba.gui.components.ListComponent; import com.haulmont.cuba.gui.components.Window; import com.haulmont.cuba.gui.config.WindowConfig; import com.haulmont.cuba.gui.data.DataSupplier; import com.haulmont.cuba.gui.data.Datasource; import com.haulmont.cuba.gui.data.impl.DatasourceImplementation; import com.haulmont.cuba.gui.data.impl.WeakItemChangeListener; import com.haulmont.cuba.gui.data.impl.WeakItemPropertyChangeListener; import com.haulmont.cuba.web.gui.data.ItemWrapper; import com.haulmont.cuba.web.toolkit.ui.CubaButtonField; import com.vaadin.data.Property; import com.vaadin.data.util.converter.Converter; import org.apache.commons.lang.StringUtils; import javax.annotation.Nullable; import java.util.Collections; import java.util.Locale; import java.util.Map; public class WebEntityLinkField extends WebAbstractField<CubaButtonField> implements EntityLinkField { protected static final String EMPTY_VALUE_STYLENAME = "empty-value"; protected EntityLinkClickHandler clickHandler; protected String screen; protected WindowManager.OpenType screenOpenType = WindowManager.OpenType.THIS_TAB; protected DialogParams screenDialogParams; protected ScreenCloseListener screenCloseListener; protected Map<String, Object> screenParams; protected MetaClass metaClass; protected ListComponent owner; protected Datasource.ItemChangeListener itemChangeListener; protected Datasource.ItemPropertyChangeListener itemPropertyChangeListener; public WebEntityLinkField() { component = new CubaButtonField(); component.addClickListener(event -> { if (clickHandler != null) { clickHandler.onClick(WebEntityLinkField.this); } else { openEntityEditor(); } }); component.setInvalidCommitted(true); component.setCaptionFormatter(new Converter() { @Override public Object convertToModel(Object value, Class targetType, Locale locale) throws ConversionException { return null; } @Override public Object convertToPresentation(Object value, Class targetType, Locale locale) throws ConversionException { if (value == null) { return ""; } if (value instanceof Instance) { return ((Instance) value).getInstanceName(); } Datatype datatype = Datatypes.getNN(value.getClass()); if (locale != null) { return datatype.format(value, locale); } return datatype.format(value); } @Override public Class getModelType() { return Object.class; } @Override public Class getPresentationType() { return String.class; } }); attachListener(component); } @Override public MetaClass getMetaClass() { final Datasource ds = getDatasource(); if (ds != null && metaProperty.getRange().isClass()) { return metaProperty.getRange().asClass(); } else { return metaClass; } } @Override public void setMetaClass(MetaClass metaClass) { final Datasource ds = getDatasource(); if (ds != null) { throw new IllegalStateException("Datasource is not null"); } this.metaClass = metaClass; } @Override public ListComponent getOwner() { return owner; } @Override public void setOwner(ListComponent owner) { this.owner = owner; } @Override public void setValue(Object value) { if (value != null) { if (datasource == null && metaClass == null) { throw new IllegalStateException("Datasource or metaclass must be set for field"); } component.removeStyleName(EMPTY_VALUE_STYLENAME); MetaClass fieldMetaClass = getMetaClass(); if (fieldMetaClass != null) { Class fieldClass = fieldMetaClass.getJavaClass(); Class<?> valueClass = value.getClass(); //noinspection unchecked if (!fieldClass.isAssignableFrom(valueClass)) { throw new IllegalArgumentException( String.format("Could not set value with class %s to field with class %s", fieldClass.getCanonicalName(), valueClass.getCanonicalName())); } } } else { component.addStyleName("empty-value"); } super.setValue(value); } @Override public String getStyleName() { return StringUtils.normalizeSpace(super.getStyleName().replace(EMPTY_VALUE_STYLENAME, "")); } @Override public String getScreen() { return screen; } @Override public void setScreen(String screen) { this.screen = screen; } @Override public EntityLinkClickHandler getCustomClickHandler() { return clickHandler; } @Override public void setCustomClickHandler(EntityLinkClickHandler clickHandler) { this.clickHandler = clickHandler; } @Override public WindowManager.OpenType getScreenOpenType() { return screenOpenType; } @Override public void setScreenOpenType(WindowManager.OpenType screenOpenType) { this.screenOpenType = screenOpenType; } @Deprecated @Override public DialogParams getScreenDialogParams() { return screenDialogParams; } @Deprecated @Override public void setScreenDialogParams(DialogParams screenDialogParams) { this.screenDialogParams = screenDialogParams; } @Override public Map<String, Object> getScreenParams() { return screenParams; } @Override public void setScreenParams(Map<String, Object> screenParams) { this.screenParams = screenParams; } @Nullable @Override public ScreenCloseListener getScreenCloseListener() { return screenCloseListener; } @Override public void setScreenCloseListener(@Nullable ScreenCloseListener closeListener) { this.screenCloseListener = closeListener; } @Override public void setDatasource(Datasource datasource, String property) { Preconditions.checkNotNullArgument(datasource, "datasource is null"); if (this.datasource != null) { throw new UnsupportedOperationException( "Changing datasource is not supported by the EntityLinkField component"); } //noinspection unchecked this.datasource = datasource; MetaClass metaClass = datasource.getMetaClass(); resolveMetaPropertyPath(metaClass, property); if (metaProperty.getRange().isClass()) { this.metaClass = metaProperty.getRange().asClass(); } ItemWrapper wrapper = createDatasourceWrapper(datasource, Collections.singleton(metaPropertyPath)); Property itemProperty = wrapper.getItemProperty(metaPropertyPath); component.setPropertyDataSource(itemProperty); itemChangeListener = e -> { Object newValue = InstanceUtils.getValueEx(e.getItem(), metaPropertyPath.getPath()); setValue(newValue); }; //noinspection unchecked datasource.addItemChangeListener(new WeakItemChangeListener(datasource, itemChangeListener)); itemPropertyChangeListener = e -> { if (e.getProperty().equals(metaPropertyPath.toString())) { setValue(e.getValue()); } }; //noinspection unchecked datasource.addItemPropertyChangeListener( new WeakItemPropertyChangeListener(datasource, itemPropertyChangeListener)); if (datasource.getState() == Datasource.State.VALID && datasource.getItem() != null) { if (property.equals(metaPropertyPath.toString())) { Object newValue = InstanceUtils.getValueEx(datasource.getItem(), metaPropertyPath.getPath()); setValue(newValue); } } setRequired(metaProperty.isMandatory()); if (StringUtils.isEmpty(getRequiredMessage())) { MessageTools messageTools = AppBeans.get(MessageTools.NAME); setRequiredMessage(messageTools.getDefaultRequiredMessage(metaClass, property)); } } protected void openEntityEditor() { Object value = getValue(); Entity entity; if (value instanceof Entity) { entity = (Entity) value; } else { entity = datasource.getItem(); } if (entity == null) { return; } WindowManager wm; Window window = ComponentsHelper.getWindow(this); if (window == null) { throw new IllegalStateException("Please specify Frame for EntityLinkField"); } else { wm = window.getWindowManager(); } if (screenOpenType.getOpenMode() == OpenMode.DIALOG && screenDialogParams != null) { wm.getDialogParams().copyFrom(screenDialogParams); } if (entity instanceof SoftDelete && ((SoftDelete) entity).isDeleted()) { Messages messages = AppBeans.get(Messages.NAME); wm.showNotification(messages.getMainMessage("OpenAction.objectIsDeleted"), Frame.NotificationType.HUMANIZED); return; } DataSupplier dataSupplier = window.getDsContext().getDataSupplier(); entity = dataSupplier.reload(entity, View.MINIMAL); String windowAlias = screen; WindowConfig windowConfig = AppBeans.get(WindowConfig.NAME); if (windowAlias == null) { windowAlias = windowConfig.getEditorScreenId(entity.getMetaClass()); } final Window.Editor editor = wm.openEditor(windowConfig.getWindowInfo(windowAlias), entity, screenOpenType, screenParams != null ? screenParams : Collections.<String, Object>emptyMap()); editor.addCloseListener(actionId -> { // move focus to component component.focus(); if (Window.COMMIT_ACTION_ID.equals(actionId)) { Entity item = editor.getItem(); afterCommitOpenedEntity(item); } if (screenCloseListener != null) { screenCloseListener.windowClosed(editor, actionId); } }); } protected void afterCommitOpenedEntity(Entity item) { if (metaProperty.getRange().isClass()) { if (getDatasource() != null) { boolean ownerDsModified = false; boolean nonModifiedInTable = false; if (owner != null && owner.getDatasource() != null) { DatasourceImplementation ownerDs = ((DatasourceImplementation) owner.getDatasource()); nonModifiedInTable = !ownerDs.getItemsToUpdate().contains(getDatasource().getItem()); ownerDsModified = ownerDs.isModified(); } boolean modified = getDatasource().isModified(); setValue(null); setValue(item); ((DatasourceImplementation) getDatasource()).setModified(modified); // restore modified for owner datasource // remove from items to update if it was not modified before setValue if (owner != null && owner.getDatasource() != null) { DatasourceImplementation ownerDs = ((DatasourceImplementation) owner.getDatasource()); if (nonModifiedInTable) { ownerDs.getItemsToUpdate().remove(getDatasource().getItem()); } ownerDs.setModified(ownerDsModified); } } else { setValue(null); setValue(item); } } else if (owner != null && owner.getDatasource() != null) { //noinspection unchecked owner.getDatasource().updateItem(item); // focus owner owner.requestFocus(); } } @Override public int getTabIndex() { return component.getTabIndex(); } @Override public void setTabIndex(int tabIndex) { component.setTabIndex(tabIndex); } }