| /** |
| * Copyright (c) 2011, 2015 - Lunifera GmbH (Gross Enzersdorf, Austria), Loetz GmbH&Co.KG (69115 Heidelberg, Germany) |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Florian Pirchner - Initial implementation |
| */ |
| package org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.internal; |
| |
| import java.util.Locale; |
| |
| import org.eclipse.core.databinding.Binding; |
| import org.eclipse.core.databinding.UpdateValueStrategy; |
| import org.eclipse.core.databinding.observable.IObservable; |
| import org.eclipse.core.databinding.observable.value.IObservableValue; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.notify.impl.AdapterImpl; |
| import org.eclipse.emf.databinding.EMFObservables; |
| import org.eclipse.osbp.ecview.core.common.editpart.IElementEditpart; |
| import org.eclipse.osbp.ecview.core.common.model.core.YEmbeddableBindingEndpoint; |
| import org.eclipse.osbp.ecview.core.common.model.core.YEmbeddableValueEndpoint; |
| import org.eclipse.osbp.ecview.core.common.notification.IReloadRequestService; |
| import org.eclipse.osbp.ecview.core.extension.model.extension.ExtensionModelPackage; |
| import org.eclipse.osbp.ecview.core.extension.model.extension.YSuggestTextField; |
| import org.eclipse.osbp.ecview.core.extension.model.extension.YSuggestTextFieldEvents; |
| import org.eclipse.osbp.ecview.core.ui.core.editparts.extension.ISuggestTextFieldEditpart; |
| import org.eclipse.osbp.runtime.common.state.ISharedStateContext; |
| import org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.common.AbstractFieldWidgetPresenter; |
| import org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.internal.util.Util; |
| import org.eclipse.osbp.runtime.web.vaadin.common.data.BeanServiceLazyLoadingContainer; |
| import org.eclipse.osbp.runtime.web.vaadin.common.data.IBeanSearchServiceFactory; |
| import org.eclipse.osbp.vaadin.addons.suggesttext.SuggestTextField; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.vaadin.data.util.ObjectProperty; |
| import com.vaadin.server.ErrorMessage; |
| import com.vaadin.ui.Component; |
| import com.vaadin.ui.Component.Focusable; |
| import com.vaadin.ui.ComponentContainer; |
| import com.vaadin.ui.Field; |
| |
| // TODO: Auto-generated Javadoc |
| /** |
| * This presenter is responsible to render a text field on the given layout. |
| */ |
| public class SuggestTextFieldPresentation extends AbstractFieldWidgetPresenter<Component> { |
| |
| private static final Logger LOGGER = LoggerFactory.getLogger(SuggestTextFieldPresentation.class); |
| |
| /** The model access. */ |
| private final ModelAccess modelAccess; |
| |
| /** The text. */ |
| private SuggestTextField text; |
| |
| /** The property. */ |
| private ObjectProperty<String> property; |
| |
| /** The adapter. */ |
| private Adapter adapter; |
| |
| /** The value binding. */ |
| private Binding valueBinding; |
| |
| private Binding keyBinding; |
| |
| private boolean updateBinding; |
| |
| /** |
| * Constructor. |
| * |
| * @param editpart |
| * The editpart of that presenter |
| */ |
| public SuggestTextFieldPresentation(IElementEditpart editpart) { |
| super((ISuggestTextFieldEditpart) editpart); |
| this.modelAccess = new ModelAccess((YSuggestTextField) editpart.getModel()); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @SuppressWarnings({ "unchecked", "rawtypes", "serial" }) |
| @Override |
| public Component doCreateWidget(Object parent) { |
| if (text == null) { |
| |
| adapter = new Adapter(); |
| modelAccess.yField.eAdapters().add(adapter); |
| |
| text = new CustomTextField(); |
| text.addStyleName(CSS_CLASS_CONTROL); |
| text.getTextField().setNullRepresentation(""); |
| text.setImmediate(true); |
| text.setLimit(10); |
| text.setAutoHide(modelAccess.yField.isAutoHidePopup()); |
| setupComponent(text, getCastedModel()); |
| |
| associateWidget(text, modelAccess.yField); |
| associateWidget(text.getTextField(), modelAccess.yField); |
| if (modelAccess.isCssIdValid()) { |
| text.setId(modelAccess.getCssID()); |
| } else { |
| text.setId(getEditpart().getId()); |
| } |
| |
| property = new ObjectProperty<String>(null, String.class); |
| text.getTextField().setPropertyDataSource(property); |
| |
| text.addSelectionChangedListener(new SuggestTextField.SelectionChangedListener() { |
| @Override |
| public void selectionChanged(SuggestTextField.SelectionChangedEvent event) { |
| Object itemId = event.getItemId(); |
| internalSetLastSuggestion(itemId); |
| } |
| }); |
| |
| if (modelAccess.yField.getType() != null) { |
| IBeanSearchServiceFactory factory = getViewContext() |
| .getService(IBeanSearchServiceFactory.class.getName()); |
| if (factory != null) { |
| ISharedStateContext sharedState = getViewContext().getService(ISharedStateContext.class.getName()); |
| BeanServiceLazyLoadingContainer<?> datasource = new BeanServiceLazyLoadingContainer( |
| factory.createService(modelAccess.yField.getType()), modelAccess.yField.getType(), |
| sharedState); |
| text.setContainerDataSource(datasource); |
| |
| text.setCaptionPropertyId(modelAccess.yField.getItemCaptionProperty()); |
| text.setFilterPropertyId(modelAccess.yField.getItemFilterProperty()); |
| |
| String uuidProp = modelAccess.yField.getItemUUIDProperty(); |
| if (uuidProp != null && !uuidProp.equals("")) { |
| text.setUniqueIdPropertyId(modelAccess.yField.getItemUUIDProperty()); |
| } |
| } |
| } |
| |
| // creates the binding for the field |
| createBindings(modelAccess.yField, text); |
| |
| if (modelAccess.isCssClassValid()) { |
| text.addStyleName(modelAccess.getCssClass()); |
| } |
| |
| applyCaptions(); |
| |
| initializeField(text.getTextField()); |
| } |
| return text; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.common. |
| * AbstractVaadinWidgetPresenter#doUpdateLocale(java.util.Locale) |
| */ |
| @Override |
| protected void doUpdateLocale(Locale locale) { |
| // no need to set the locale to the ui elements. Is handled by vaadin |
| // internally. |
| |
| // update the captions |
| applyCaptions(); |
| } |
| |
| /** |
| * Applies the labels to the widgets. |
| */ |
| protected void applyCaptions() { |
| Util.applyCaptions(getI18nService(), modelAccess.getLabel(), modelAccess.getLabelI18nKey(), getLocale(), text); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.common. |
| * AbstractFieldWidgetPresenter#doGetField() |
| */ |
| @Override |
| protected Field<?> doGetField() { |
| return text != null ? text.getTextField() : null; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.common. |
| * AbstractVaadinWidgetPresenter |
| * #internalGetObservableEndpoint(org.eclipse.osbp |
| * .ecview.core.common.model.core.YEmbeddableBindingEndpoint) |
| */ |
| @Override |
| protected IObservable internalGetObservableEndpoint(YEmbeddableBindingEndpoint bindableValue) { |
| if (bindableValue == null) { |
| throw new IllegalArgumentException("BindableValue must not be null!"); |
| } |
| |
| if (bindableValue instanceof YEmbeddableValueEndpoint) { |
| return internalGetValueEndpoint(); |
| } |
| throw new IllegalArgumentException("Not a valid input: " + bindableValue); |
| } |
| |
| /** |
| * Returns the observable to observe value. |
| * |
| * @return the i observable value |
| */ |
| protected IObservableValue internalGetValueEndpoint() { |
| // return the observable value for text |
| return EMFObservables.observeValue(castEObject(getModel()), |
| ExtensionModelPackage.Literals.YSUGGEST_TEXT_FIELD__VALUE); |
| } |
| |
| /** |
| * Creates the bindings for the given values. |
| * |
| * @param yField |
| * the y field |
| * @param field |
| * the field |
| */ |
| protected void createBindings(YSuggestTextField yField, SuggestTextField field) { |
| updateValueBinding(field); |
| |
| super.createBindings(yField, field, null); |
| } |
| |
| /** |
| * The value binding takes respect to the |
| * modelAccess.yField.isUseSuggestions(). If suggestions are used, value |
| * changes in the UI MUST NOT be updated to the model. |
| * |
| * @param field |
| * the field |
| */ |
| protected void updateValueBinding(SuggestTextField field) { |
| if (valueBinding != null) { |
| unregisterBinding(valueBinding); |
| } |
| |
| if (keyBinding != null) { |
| unregisterBinding(keyBinding); |
| } |
| |
| if (field == null) { |
| return; |
| } |
| |
| try { |
| updateBinding = true; |
| |
| // suppress suggestions |
| field.setSuggestionEnabled(false); |
| |
| if (modelAccess.yField.isUseSuggestions()) { |
| // in suggest mode do not update from UI to model |
| keyBinding = createBindingsByAccessor(castEObject(getModel()), |
| ExtensionModelPackage.Literals.YSUGGEST_TEXT_FIELD__KEYS, field, "keys", |
| new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER), |
| new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE)); |
| valueBinding = createBindingsValue(castEObject(getModel()), |
| ExtensionModelPackage.Literals.YSUGGEST_TEXT_FIELD__VALUE, field.getTextField(), |
| new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER), |
| new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE)); |
| } else { |
| keyBinding = createBindingsByAccessor(castEObject(getModel()), |
| ExtensionModelPackage.Literals.YSUGGEST_TEXT_FIELD__KEYS, field, "keys", |
| new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE), |
| new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE)); |
| valueBinding = createBindingsValue(castEObject(getModel()), |
| ExtensionModelPackage.Literals.YSUGGEST_TEXT_FIELD__VALUE, field.getTextField(), |
| new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE), |
| new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE)); |
| } |
| |
| field.setSuggestionEnabled(modelAccess.yField.isUseSuggestions()); |
| |
| // create the model binding from model to ECView-model |
| registerBinding(valueBinding); |
| registerBinding(keyBinding); |
| } finally { |
| updateBinding = false; |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.osbp.ecview.core.common.presentation.IWidgetPresentation# |
| * getWidget() |
| */ |
| @Override |
| public Component getWidget() { |
| return text; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.osbp.ecview.core.common.presentation.IWidgetPresentation# |
| * isRendered() |
| */ |
| @Override |
| public boolean isRendered() { |
| return text != null; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void doUnrender() { |
| if (text != null) { |
| |
| modelAccess.yField.eAdapters().remove(adapter); |
| adapter = null; |
| |
| // unbind all active bindings |
| unbind(); |
| |
| Component parent = ((Component) text.getParent()); |
| if (parent != null && parent instanceof ComponentContainer) { |
| ((ComponentContainer) parent).removeComponent(text); |
| } |
| |
| // remove assocations |
| unassociateWidget(text); |
| unassociateWidget(text.getTextField()); |
| |
| text = null; |
| } |
| } |
| |
| /** |
| * Sets the use suggestions. |
| * |
| * @param newBooleanValue |
| * the new use suggestions |
| */ |
| public void setUseSuggestions(boolean newBooleanValue) { |
| updateValueBinding(text); |
| } |
| |
| /** |
| * Executes the given event. |
| * |
| * @param event |
| */ |
| protected void doExecuteEvent(YSuggestTextFieldEvents event) { |
| if (!isRendered()) { |
| return; |
| } |
| |
| if (modelAccess.yField.isAutoHidePopup()) { |
| LOGGER.warn("Using events with autoHidePopup==true, may cause side effects, " |
| + "since a click to the UI outside the popup will close the popup automatically"); |
| } |
| |
| switch (event) { |
| case OPEN_POPUP: |
| text.openPopup(); |
| break; |
| case CLOSE_POPUP: |
| text.closePopup(); |
| break; |
| case NAVIGATE_NEXT: |
| text.navigateToNext(); |
| break; |
| case NAVIGATE_PREV: |
| text.navigateToPrevious(); |
| break; |
| case SELECT: |
| text.selectCurrent(); |
| break; |
| case CLEAR: |
| text.setValue(null); |
| text.closePopup(); |
| internalSetLastSuggestion(null); |
| break; |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| protected void internalDispose() { |
| try { |
| unrender(); |
| } finally { |
| super.internalDispose(); |
| } |
| } |
| |
| protected void internalSetLastSuggestion(Object itemId) { |
| IReloadRequestService service = getViewContext().getService(IReloadRequestService.class.getName()); |
| if (service != null && itemId != null) { |
| service.requestReload(getCastedModel(), itemId); |
| } |
| modelAccess.yField.setLastSuggestion(itemId); |
| if (itemId != null) { |
| modelAccess.yField.setEvent(YSuggestTextFieldEvents.SELECTED); |
| } |
| } |
| |
| /** |
| * A helper class. |
| */ |
| private static class ModelAccess { |
| |
| /** The y field. */ |
| private final YSuggestTextField yField; |
| |
| /** |
| * Instantiates a new model access. |
| * |
| * @param yField |
| * the y field |
| */ |
| public ModelAccess(YSuggestTextField yField) { |
| super(); |
| this.yField = yField; |
| } |
| |
| /** |
| * Gets the css class. |
| * |
| * @return the css class |
| * @see org.eclipse.osbp.ecview.core.ui.core.model.core.YCssAble#getCssClass() |
| */ |
| public String getCssClass() { |
| return yField.getCssClass(); |
| } |
| |
| /** |
| * Returns true, if the css class is not null and not empty. |
| * |
| * @return true, if is css class valid |
| */ |
| public boolean isCssClassValid() { |
| return getCssClass() != null && !getCssClass().equals(""); |
| } |
| |
| /** |
| * Gets the css id. |
| * |
| * @return the css id |
| * @see org.eclipse.osbp.ecview.core.ui.core.model.core.YCssAble#getCssID() |
| */ |
| public String getCssID() { |
| return yField.getCssID(); |
| } |
| |
| /** |
| * Returns true, if the css id is not null and not empty. |
| * |
| * @return true, if is css id valid |
| */ |
| public boolean isCssIdValid() { |
| return getCssID() != null && !getCssID().equals(""); |
| } |
| |
| /** |
| * Returns the label. |
| * |
| * @return the label |
| */ |
| public String getLabel() { |
| return yField.getLabel(); |
| } |
| |
| /** |
| * Returns the label. |
| * |
| * @return the label i18n key |
| */ |
| public String getLabelI18nKey() { |
| return yField.getLabelI18nKey(); |
| } |
| } |
| |
| /** |
| * The Class CustomTextField. |
| */ |
| @SuppressWarnings("serial") |
| private class CustomTextField extends SuggestTextField implements Focusable { |
| |
| private int tabIndex; |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see com.vaadin.ui.AbstractComponent#getErrorMessage() |
| */ |
| @Override |
| public ErrorMessage getErrorMessage() { |
| if (isDisposed()) { |
| // after disposal, Vaadin will call this method once. |
| return null; |
| } |
| |
| ErrorMessage message = super.getErrorMessage(); |
| reportValidationError(message); |
| return message; |
| } |
| |
| @Override |
| public void focus() { |
| if (getTextField() != null) { |
| getTextField().focus(); |
| } |
| } |
| |
| @Override |
| protected TextFieldCustom createTextField() { |
| return new TextFieldCustom() { |
| @Override |
| public ErrorMessage getErrorMessage() { |
| if (isDisposed()) { |
| // after disposal, Vaadin will call this method once. |
| return null; |
| } |
| |
| ErrorMessage message = super.getErrorMessage(); |
| reportValidationError(message); |
| return message; |
| } |
| }; |
| } |
| |
| @Override |
| public void setSuggestionEnabled(boolean suggestionEnabled) { |
| super.setSuggestionEnabled(suggestionEnabled); |
| |
| if (!updateBinding) { |
| modelAccess.yField.setUseSuggestions(suggestionEnabled); |
| } |
| } |
| |
| public int getTabIndex() { |
| return tabIndex; |
| } |
| |
| @Override |
| public void setTabIndex(int tabIndex) { |
| this.tabIndex = tabIndex; |
| } |
| |
| } |
| |
| /** |
| * The Class Adapter. |
| */ |
| private class Adapter extends AdapterImpl { |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.emf.common.notify.impl.AdapterImpl#notifyChanged(org. |
| * eclipse.emf.common.notify.Notification) |
| */ |
| @Override |
| public void notifyChanged(Notification msg) { |
| if (msg.getFeature() == ExtensionModelPackage.Literals.YSUGGEST_TEXT_FIELD__USE_SUGGESTIONS) { |
| setUseSuggestions(msg.getNewBooleanValue()); |
| } else if (msg.getFeature() == ExtensionModelPackage.Literals.YSUGGEST_TEXT_FIELD__AUTO_HIDE_POPUP) { |
| text.setAutoHide(msg.getNewBooleanValue()); |
| } else if (msg.getFeature() == ExtensionModelPackage.Literals.YSUGGEST_TEXT_FIELD__EVENT) { |
| YSuggestTextFieldEvents event = (YSuggestTextFieldEvents) msg.getNewValue(); |
| if (event != null) { |
| doExecuteEvent(event); |
| } |
| } |
| } |
| } |
| } |