blob: 0ac68d13390018b55463c8e19efe93027e0fe9a4 [file] [log] [blame]
/*******************************************************************************
* 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()));
}
}
}