| /******************************************************************************* |
| * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH and others. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Eugen Neufeld - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.emfforms.internal.core.services.label; |
| |
| import java.text.MessageFormat; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.WeakHashMap; |
| |
| import org.eclipse.core.databinding.observable.value.IObservableValue; |
| import org.eclipse.core.databinding.observable.value.WritableValue; |
| import org.eclipse.core.databinding.property.value.IValueProperty; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecp.common.spi.asserts.Assert; |
| import org.eclipse.emf.ecp.view.spi.model.VDomainModelReference; |
| import org.eclipse.emfforms.spi.common.BundleResolver; |
| import org.eclipse.emfforms.spi.common.BundleResolver.NoBundleFoundException; |
| import org.eclipse.emfforms.spi.common.BundleResolverFactory; |
| import org.eclipse.emfforms.spi.common.locale.EMFFormsLocaleChangeListener; |
| import org.eclipse.emfforms.spi.common.locale.EMFFormsLocaleProvider; |
| import org.eclipse.emfforms.spi.common.report.ReportService; |
| import org.eclipse.emfforms.spi.core.services.databinding.DatabindingFailedException; |
| import org.eclipse.emfforms.spi.core.services.databinding.DatabindingFailedReport; |
| import org.eclipse.emfforms.spi.core.services.databinding.EMFFormsDatabinding; |
| import org.eclipse.emfforms.spi.core.services.databinding.emf.EMFFormsDatabindingEMF; |
| import org.eclipse.emfforms.spi.core.services.label.EMFFormsLabelProvider; |
| import org.eclipse.emfforms.spi.core.services.label.NoLabelFoundException; |
| import org.eclipse.emfforms.spi.localization.EMFFormsLocalizationService; |
| import org.osgi.framework.Bundle; |
| |
| /** |
| * Implementation of {@link EMFFormsLabelProvider}. It provides a label service that delivers the display name and |
| * description for a domain model reference and optionally an EObject. |
| * |
| * @author Eugen Neufeld |
| * |
| */ |
| public class EMFFormsLabelProviderImpl implements EMFFormsLabelProvider, EMFFormsLocaleChangeListener { |
| |
| /** |
| * Key for the map of description observables. |
| * |
| * @author Eugen Neufeld |
| */ |
| private static class DescriptionKey { |
| private final String eClassName; |
| private final String featureName; |
| private final Bundle bundle; |
| |
| DescriptionKey(String eClassName, String featureName, Bundle bundle) { |
| super(); |
| this.eClassName = eClassName; |
| this.featureName = featureName; |
| this.bundle = bundle; |
| } |
| |
| Bundle getBundle() { |
| return bundle; |
| } |
| |
| String geteClassName() { |
| return eClassName; |
| } |
| |
| String getFeatureName() { |
| return featureName; |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + (bundle == null ? 0 : bundle.hashCode()); |
| result = prime * result + (eClassName == null ? 0 : eClassName.hashCode()); |
| result = prime * result + (featureName == null ? 0 : featureName.hashCode()); |
| return result; |
| } |
| |
| // BEGIN COMPLEX CODE |
| // path complexity check does not take returns into account |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj == null) { |
| return false; |
| } |
| if (!(obj instanceof DescriptionKey)) { |
| return false; |
| } |
| final DescriptionKey other = (DescriptionKey) obj; |
| if (bundle == null) { |
| if (other.bundle != null) { |
| return false; |
| } |
| } else if (!bundle.equals(other.bundle)) { |
| return false; |
| } |
| if (eClassName == null) { |
| if (other.eClassName != null) { |
| return false; |
| } |
| } else if (!eClassName.equals(other.eClassName)) { |
| return false; |
| } |
| if (featureName == null) { |
| if (other.featureName != null) { |
| return false; |
| } |
| } else if (!featureName.equals(other.featureName)) { |
| return false; |
| } |
| return true; |
| } |
| // END COMPLEX CODE |
| } |
| |
| private static final String DISPLAY_NAME = "_UI_%1$s_%2$s_feature"; //$NON-NLS-1$ |
| private static final String DESCRIPTION = "_UI_%1$s_%2$s_description"; //$NON-NLS-1$ |
| private static final String DESCRIPTION_COMPOSITE = "_UI_PropertyDescriptor_description"; //$NON-NLS-1$ |
| private static final String TYPE = "_UI_%1$s_type"; //$NON-NLS-1$ |
| |
| private EMFFormsDatabindingEMF emfFormsDatabinding; |
| private EMFFormsLocalizationService localizationService; |
| private ReportService reportService; |
| private BundleResolver bundleResolver = BundleResolverFactory.createBundleResolver(); |
| |
| private final Map<WritableValue, BundleKeyWrapper> displayKeyObservableMap = new WeakHashMap<WritableValue, BundleKeyWrapper>(); |
| private final Map<WritableValue, DescriptionKey> descriptionKeyObservableMap = new WeakHashMap<WritableValue, DescriptionKey>(); |
| private EMFFormsLocaleProvider localeProvider; |
| private EMFFormsLabelProviderDefaultImpl labelProviderDefault; |
| |
| /** |
| * Sets the {@link ReportService} service. |
| * |
| * @param reportService The ReportService service. |
| */ |
| protected void setReportService(ReportService reportService) { |
| this.reportService = reportService; |
| } |
| |
| /** |
| * Sets the {@link EMFFormsDatabinding} service. |
| * |
| * @param emfFormsDatabinding The databinding service. |
| */ |
| protected void setEMFFormsDatabinding(EMFFormsDatabindingEMF emfFormsDatabinding) { |
| this.emfFormsDatabinding = emfFormsDatabinding; |
| } |
| |
| /** |
| * Sets the {@link EMFFormsLocalizationService}. |
| * |
| * @param localizationService The {@link EMFFormsLocalizationService} |
| */ |
| protected void setEMFFormsLocalizationService(EMFFormsLocalizationService localizationService) { |
| this.localizationService = localizationService; |
| } |
| |
| /** |
| * Sets the {@link EMFFormsLocaleProvider}. |
| * |
| * @param localeProvider The {@link EMFFormsLocaleProvider} |
| */ |
| protected void setEMFFormsLocaleProvider(EMFFormsLocaleProvider localeProvider) { |
| this.localeProvider = localeProvider; |
| this.localeProvider.addEMFFormsLocaleChangeListener(this); |
| } |
| |
| /** |
| * Sets the {@link BundleResolver}. |
| * |
| * @param bundleResolver The {@link BundleResolver} |
| */ |
| protected void setBundleResolver(BundleResolver bundleResolver) { |
| this.bundleResolver = bundleResolver; |
| } |
| |
| /** |
| * Sets the default {@link EMFFormsLabelProviderDefaultImpl}. |
| * |
| * @param labelProviderDefault the labelProviderDefault to set |
| */ |
| protected void setLabelProviderDefault(EMFFormsLabelProviderDefaultImpl labelProviderDefault) { |
| this.labelProviderDefault = labelProviderDefault; |
| } |
| |
| private BundleKeyResultWrapper getDisplayBundleKeyResultWrapper(EStructuralFeature structuralFeature) |
| throws NoBundleFoundException { |
| final EClass eContainingClass = structuralFeature.getEContainingClass(); |
| final Bundle bundle = bundleResolver.getEditBundle(eContainingClass); |
| final String key = String.format(DISPLAY_NAME, eContainingClass.getName(), |
| structuralFeature.getName()); |
| final String displayName = getDisplayName(bundle, key); |
| return new BundleKeyResultWrapper(new BundleKeyWrapper(key, bundle), displayName); |
| } |
| |
| /** |
| * Returns the display name of the {@link EStructuralFeature}. |
| * |
| * @param structuralFeature The {@link EStructuralFeature} |
| * @return The localized feature name |
| */ |
| public String getDisplayName(EStructuralFeature structuralFeature) { |
| try { |
| return getDisplayBundleKeyResultWrapper(structuralFeature).getResult(); |
| } catch (final NoBundleFoundException ex) { |
| return (String) labelProviderDefault.getDisplayName(structuralFeature).getValue(); |
| } |
| } |
| |
| @Deprecated |
| @Override |
| public IObservableValue getDisplayName(VDomainModelReference domainModelReference) throws NoLabelFoundException { |
| Assert.create(domainModelReference).notNull(); |
| |
| IValueProperty valueProperty; |
| try { |
| valueProperty = emfFormsDatabinding.getValueProperty(domainModelReference, (EObject) null); |
| } catch (final DatabindingFailedException ex) { |
| reportService.report(new DatabindingFailedReport(ex)); |
| throw new NoLabelFoundException(ex); |
| } |
| final EStructuralFeature structuralFeature = (EStructuralFeature) valueProperty.getValueType(); |
| BundleKeyResultWrapper bundleKeyResultWrapper; |
| try { |
| bundleKeyResultWrapper = getDisplayBundleKeyResultWrapper(structuralFeature); |
| } catch (final NoBundleFoundException ex) { |
| return labelProviderDefault.getDisplayName(domainModelReference); |
| } |
| |
| final WritableValue value = getObservableValue(bundleKeyResultWrapper.getResult()); |
| displayKeyObservableMap.put(value, bundleKeyResultWrapper.getBundleKeyWrapper()); |
| return value; |
| } |
| |
| @Override |
| public IObservableValue getDisplayName(VDomainModelReference domainModelReference, EClass rootEClass) |
| throws NoLabelFoundException { |
| Assert.create(domainModelReference).notNull(); |
| Assert.create(rootEClass).notNull(); |
| |
| IValueProperty valueProperty; |
| try { |
| valueProperty = emfFormsDatabinding.getValueProperty(domainModelReference, rootEClass); |
| } catch (final DatabindingFailedException ex) { |
| reportService.report(new DatabindingFailedReport(ex)); |
| throw new NoLabelFoundException(ex); |
| } |
| final EStructuralFeature structuralFeature = (EStructuralFeature) valueProperty.getValueType(); |
| |
| BundleKeyResultWrapper displayBundleKeyResultWrapper; |
| try { |
| displayBundleKeyResultWrapper = getDisplayBundleKeyResultWrapper(structuralFeature); |
| } catch (final NoBundleFoundException ex) { |
| return labelProviderDefault.getDisplayName(domainModelReference, rootEClass); |
| } |
| |
| final WritableValue displayObserveValue = getObservableValue(displayBundleKeyResultWrapper.getResult()); |
| displayKeyObservableMap.put(displayObserveValue, displayBundleKeyResultWrapper.getBundleKeyWrapper()); |
| return displayObserveValue; |
| } |
| |
| @Override |
| public IObservableValue getDisplayName(VDomainModelReference domainModelReference, EObject rootObject) |
| throws NoLabelFoundException { |
| Assert.create(domainModelReference).notNull(); |
| Assert.create(rootObject).notNull(); |
| |
| return getDisplayName(domainModelReference, rootObject.eClass()); |
| } |
| |
| @Deprecated |
| @Override |
| public IObservableValue getDescription(VDomainModelReference domainModelReference) throws NoLabelFoundException { |
| Assert.create(domainModelReference).notNull(); |
| |
| IValueProperty valueProperty; |
| try { |
| valueProperty = emfFormsDatabinding.getValueProperty(domainModelReference, (EObject) null); |
| } catch (final DatabindingFailedException ex) { |
| reportService.report(new DatabindingFailedReport(ex)); |
| throw new NoLabelFoundException(ex); |
| } |
| final EStructuralFeature structuralFeature = (EStructuralFeature) valueProperty.getValueType(); |
| final EClass eContainingClass = structuralFeature.getEContainingClass(); |
| Bundle bundle; |
| try { |
| bundle = bundleResolver.getEditBundle(eContainingClass); |
| } catch (final NoBundleFoundException ex) { |
| return labelProviderDefault.getDescription(domainModelReference); |
| } |
| final WritableValue writableValue = getObservableValue(getDescription(eContainingClass |
| .getName(), |
| structuralFeature.getName(), bundle)); |
| descriptionKeyObservableMap.put(writableValue, new DescriptionKey(eContainingClass.getName(), |
| structuralFeature.getName(), bundle)); |
| return writableValue; |
| } |
| |
| @Override |
| public IObservableValue getDescription(VDomainModelReference domainModelReference, EClass rootEClass) |
| throws NoLabelFoundException { |
| Assert.create(domainModelReference).notNull(); |
| Assert.create(rootEClass).notNull(); |
| |
| IValueProperty valueProperty; |
| try { |
| valueProperty = emfFormsDatabinding.getValueProperty(domainModelReference, rootEClass); |
| } catch (final DatabindingFailedException ex) { |
| reportService.report(new DatabindingFailedReport(ex)); |
| throw new NoLabelFoundException(ex); |
| } |
| final EStructuralFeature structuralFeature = (EStructuralFeature) valueProperty.getValueType(); |
| Bundle bundle; |
| try { |
| bundle = bundleResolver.getEditBundle(structuralFeature.getEContainingClass()); |
| } catch (final NoBundleFoundException ex) { |
| return labelProviderDefault.getDescription(domainModelReference, rootEClass); |
| } |
| return createDescriptionObservableValue(structuralFeature, bundle); |
| } |
| |
| @Override |
| public IObservableValue getDescription(VDomainModelReference domainModelReference, EObject rootObject) |
| throws NoLabelFoundException { |
| Assert.create(domainModelReference).notNull(); |
| Assert.create(rootObject).notNull(); |
| |
| IValueProperty valueProperty; |
| try { |
| valueProperty = emfFormsDatabinding.getValueProperty(domainModelReference, rootObject); |
| } catch (final DatabindingFailedException ex) { |
| reportService.report(new DatabindingFailedReport(ex)); |
| throw new NoLabelFoundException(ex); |
| } |
| final EStructuralFeature structuralFeature = (EStructuralFeature) valueProperty.getValueType(); |
| Bundle bundle; |
| try { |
| bundle = bundleResolver.getEditBundle(structuralFeature.getEContainingClass()); |
| } catch (final NoBundleFoundException ex) { |
| return labelProviderDefault.getDescription(domainModelReference, rootObject); |
| } |
| return createDescriptionObservableValue(structuralFeature, bundle); |
| } |
| |
| private IObservableValue createDescriptionObservableValue(final EStructuralFeature structuralFeature, |
| Bundle bundle) { |
| final WritableValue writableValue = getObservableValue(getDescription(structuralFeature.getEContainingClass() |
| .getName(), structuralFeature.getName(), bundle)); |
| descriptionKeyObservableMap.put(writableValue, |
| new DescriptionKey(structuralFeature.getEContainingClass().getName(), |
| structuralFeature.getName(), bundle)); |
| return writableValue; |
| } |
| |
| private WritableValue getObservableValue(String value) { |
| return new WritableValue(value, String.class); |
| } |
| |
| private String getDisplayName(Bundle bundle, String key) { |
| return localizationService.getString(bundle, key); |
| } |
| |
| private String getDescription(String eClassName, String featureName, Bundle bundle) { |
| final String keyDefault = String.format(DESCRIPTION, eClassName, featureName); |
| if (localizationService.hasKey(bundle, keyDefault)) { |
| return localizationService.getString(bundle, |
| keyDefault); |
| } |
| final String descriptionWithSubstitution = localizationService.getString(bundle, |
| DESCRIPTION_COMPOSITE); |
| final String key = String.format(DISPLAY_NAME, eClassName, featureName); |
| final String featureSubstitution = getDisplayName(bundle, key); |
| final String eObjectSubstitution = localizationService.getString(bundle, |
| String.format(TYPE, eClassName)); |
| return MessageFormat.format(descriptionWithSubstitution, featureSubstitution, eObjectSubstitution); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emfforms.spi.common.locale.EMFFormsLocaleChangeListener#notifyLocaleChange() |
| */ |
| @Override |
| public void notifyLocaleChange() { |
| for (final Entry<WritableValue, BundleKeyWrapper> entry : displayKeyObservableMap.entrySet()) { |
| final WritableValue writableValue = entry.getKey(); |
| if (writableValue.isDisposed()) { |
| continue; |
| } |
| final BundleKeyWrapper displayNameKey = entry.getValue(); |
| writableValue.setValue(getDisplayName(displayNameKey.getBundle(), displayNameKey.getKey())); |
| } |
| for (final Entry<WritableValue, DescriptionKey> entry : descriptionKeyObservableMap.entrySet()) { |
| final WritableValue writableValue = entry.getKey(); |
| if (writableValue.isDisposed()) { |
| continue; |
| } |
| final DescriptionKey descriptionKey = entry.getValue(); |
| writableValue.setValue(getDescription(descriptionKey.geteClassName(), descriptionKey.getFeatureName(), |
| descriptionKey.getBundle())); |
| } |
| } |
| } |