blob: 6835f84a0937492d732a2be289609058ba63cb4b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2015 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 v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Lucas Koehler- initial API and implementation
******************************************************************************/
package org.eclipse.emfforms.internal.core.services.controlmapper;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature.Setting;
import org.eclipse.emf.ecp.common.spi.UniqueSetting;
import org.eclipse.emf.ecp.view.spi.model.ModelChangeAddRemoveListener;
import org.eclipse.emf.ecp.view.spi.model.ModelChangeNotification;
import org.eclipse.emf.ecp.view.spi.model.VControl;
import org.eclipse.emf.ecp.view.spi.model.VDomainModelReference;
import org.eclipse.emf.ecp.view.spi.model.VElement;
import org.eclipse.emfforms.spi.core.services.controlmapper.EMFFormsSettingToControlMapper;
import org.eclipse.emfforms.spi.core.services.mappingprovider.EMFFormsMappingProviderManager;
import org.eclipse.emfforms.spi.core.services.view.EMFFormsContextListener;
import org.eclipse.emfforms.spi.core.services.view.EMFFormsViewContext;
/**
* Implementation of {@link EMFFormsSettingToControlMapper}.
*
* @author Lucas Koehler
*
*/
public class SettingToControlMapperImpl implements EMFFormsSettingToControlMapper, EMFFormsContextListener {
/**
* Used to get View model changes.
*
* @author Eugen Neufeld
*
*/
private final class ModelChangeAddRemoveListenerImplementation implements ModelChangeAddRemoveListener {
@Override
public void notifyChange(ModelChangeNotification notification) {
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.model.ModelChangeAddRemoveListener#notifyAdd(org.eclipse.emf.common.notify.Notifier)
*/
@Override
public void notifyAdd(Notifier notifier) {
if (VDomainModelReference.class.isInstance(notifier)
&& !VDomainModelReference.class.isInstance(EObject.class.cast(notifier).eContainer())) {
final VDomainModelReference domainModelReference = VDomainModelReference.class.cast(notifier);
// FIXME remove
SettingToControlExpandHelper.resolveDomainReferences(domainModelReference,
viewModelContext.getDomainModel(),
viewModelContext);
final VControl control = findControl(domainModelReference);
if (control != null) {
vControlAdded(control);
}
}
}
private VControl findControl(VDomainModelReference dmr) {
EObject parent = dmr.eContainer();
while (!VControl.class.isInstance(parent) && parent != null) {
parent = parent.eContainer();
}
return (VControl) parent;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.model.ModelChangeAddRemoveListener#notifyRemove(org.eclipse.emf.common.notify.Notifier)
*/
@Override
public void notifyRemove(Notifier notifier) {
if (VControl.class.isInstance(notifier)) {
vControlRemoved((VControl) notifier);
}
}
}
private final EMFFormsViewContext viewModelContext;
private final ViewModelListener viewModelListener;
private final Map<EObject, Set<UniqueSetting>> eObjectToMappedSettings = new LinkedHashMap<EObject, Set<UniqueSetting>>();
/**
* A mapping between settings and controls.
*/
private final Map<UniqueSetting, Set<VControl>> settingToControlMap = new LinkedHashMap<UniqueSetting, Set<VControl>>();
private final EMFFormsMappingProviderManager mappingManager;
private final Map<VElement, Set<EMFFormsSettingToControlMapper>> childMappers = new LinkedHashMap<VElement, Set<EMFFormsSettingToControlMapper>>();
/**
* Creates a new instance of {@link SettingToControlMapperImpl}.
*
* @param mappingManager The {@link EMFFormsMappingProviderManager}
* @param viewModelContext The {@link EMFFormsViewContext} that created this instance
*/
public SettingToControlMapperImpl(EMFFormsMappingProviderManager mappingManager,
EMFFormsViewContext viewModelContext) {
this.mappingManager = mappingManager;
this.viewModelContext = viewModelContext;
viewModelContext.registerEMFFormsContextListener(this);
viewModelContext.registerViewChangeListener(new ModelChangeAddRemoveListenerImplementation());
viewModelListener = new ViewModelListener(viewModelContext, this);
}
/**
* {@inheritDoc}
*/
@Override
public Set<VControl> getControlsFor(Setting setting) {
return settingToControlMap.get(UniqueSetting.createSetting(setting));
}
/**
* {@inheritDoc}
*/
@Override
public Set<VElement> getControlsFor(UniqueSetting setting) {
final Set<VElement> elements = new LinkedHashSet<VElement>();
final Set<VControl> currentControls = settingToControlMap.get(setting);
if (currentControls != null) {
for (final VElement control : currentControls) {
if (!control.isEffectivelyEnabled() || !control.isEffectivelyVisible()
|| control.isEffectivelyReadonly()) {
continue;
}
elements.add(control);
}
}
for (final VElement parentElement : childMappers.keySet()) {
for (final EMFFormsSettingToControlMapper childMapper : childMappers.get(parentElement)) {
final Set<VElement> controlsFor = childMapper.getControlsFor(setting);
elements.addAll(controlsFor);
if (!controlsFor.isEmpty()) {
elements.add(parentElement);
}
}
}
return elements;
}
/**
* {@inheritDoc}
*/
@Override
public void updateControlMapping(VControl vControl) {
if (vControl == null) {
return;
}
// delete old mapping
final Set<UniqueSetting> keysWithEmptySets = new LinkedHashSet<UniqueSetting>();
for (final UniqueSetting setting : settingToControlMap.keySet()) {
final Set<VControl> controlSet = settingToControlMap.get(setting);
controlSet.remove(vControl);
if (controlSet.isEmpty()) {
keysWithEmptySets.add(setting);
}
}
for (final UniqueSetting setting : keysWithEmptySets) {
settingToControlMap.remove(setting);
handleRemoveForEObjectMapping(setting);
}
// update mapping
final Set<UniqueSetting> map = mappingManager.getAllSettingsFor(vControl.getDomainModelReference(),
viewModelContext.getDomainModel());
for (final UniqueSetting setting : map) {
if (!settingToControlMap.containsKey(setting)) {
settingToControlMap.put(setting, new LinkedHashSet<VControl>());
handleAddForEObjectMapping(setting);
}
settingToControlMap.get(setting).add(vControl);
}
}
private void handleAddForEObjectMapping(UniqueSetting setting) {
if (!eObjectToMappedSettings.containsKey(setting.getEObject())) {
eObjectToMappedSettings.put(setting.getEObject(), new LinkedHashSet<UniqueSetting>());
}
eObjectToMappedSettings.get(setting.getEObject()).add(setting);
}
private void handleRemoveForEObjectMapping(UniqueSetting setting) {
final Set<UniqueSetting> settings = eObjectToMappedSettings.get(setting.getEObject());
settings.remove(setting);
if (settings.isEmpty()) {
eObjectToMappedSettings.remove(setting.getEObject());
}
}
/**
* {@inheritDoc}
*/
@Override
public void vControlRemoved(VControl vControl) {
if (vControl.getDomainModelReference() == null) {
return;
}
final Set<UniqueSetting> map = mappingManager.getAllSettingsFor(vControl.getDomainModelReference(),
viewModelContext.getDomainModel());
for (final UniqueSetting setting : map) {
if (settingToControlMap.containsKey(setting)) {
settingToControlMap.get(setting).remove(vControl);
if (settingToControlMap.get(setting).size() == 0) {
settingToControlMap.remove(setting);
handleRemoveForEObjectMapping(setting);
}
}
}
viewModelListener.removeVControl(vControl);
}
/**
* {@inheritDoc}
*/
@Override
public void vControlAdded(VControl vControl) {
if (vControl.getDomainModelReference() == null) {
return;
}
checkAndUpdateSettingToControlMapping(vControl);
viewModelListener.addVControl(vControl);
}
/**
* {@inheritDoc}
*/
@Override
public void checkAndUpdateSettingToControlMapping(EObject eObject) {
if (VControl.class.isInstance(eObject)) {
final VControl vControl = (VControl) eObject;
if (vControl.getDomainModelReference() == null) {
return;
}
updateControlMapping(vControl);
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emfforms.spi.core.services.view.EMFFormsContextListener#childContextAdded(org.eclipse.emf.ecp.view.spi.model.VElement,
* org.eclipse.emfforms.spi.core.services.view.EMFFormsViewContext)
*/
@Override
public void childContextAdded(VElement parentElement, EMFFormsViewContext childContext) {
final EMFFormsSettingToControlMapper childSettingToControlMapper = childContext
.getService(EMFFormsSettingToControlMapper.class);
if (!childMappers.containsKey(parentElement)) {
childMappers.put(parentElement, new LinkedHashSet<EMFFormsSettingToControlMapper>());
}
childMappers.get(parentElement).add(childSettingToControlMapper);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emfforms.spi.core.services.view.EMFFormsContextListener#childContextDisposed(org.eclipse.emfforms.spi.core.services.view.EMFFormsViewContext)
*/
@Override
public void childContextDisposed(EMFFormsViewContext childContext) {
final EMFFormsSettingToControlMapper childSettingToControlMapper = childContext
.getService(EMFFormsSettingToControlMapper.class);
for (final VElement vElement : childMappers.keySet()) {
childMappers.get(vElement).remove(childSettingToControlMapper);
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emfforms.spi.core.services.view.EMFFormsContextListener#contextInitialised()
*/
@Override
public void contextInitialised() {
// do nothing
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emfforms.spi.core.services.view.EMFFormsContextListener#contextDispose()
*/
@Override
public void contextDispose() {
viewModelContext.unregisterEMFFormsContextListener(this);
viewModelListener.dispose();
settingToControlMap.clear();
childMappers.clear();
}
@Override
public boolean hasControlsFor(EObject eObject) {
if (eObjectToMappedSettings.containsKey(eObject)) {
return true;
}
for (final VElement parentElement : childMappers.keySet()) {
for (final EMFFormsSettingToControlMapper childMapper : childMappers.get(parentElement)) {
if (childMapper.hasControlsFor(eObject)) {
return true;
}
}
}
return false;
}
@Override
public Collection<EObject> getEObjectsWithSettings() {
final Set<EObject> result = new LinkedHashSet<EObject>();
result.addAll(eObjectToMappedSettings.keySet());
for (final VElement parentElement : childMappers.keySet()) {
for (final EMFFormsSettingToControlMapper childMapper : childMappers.get(parentElement)) {
result.addAll(childMapper.getEObjectsWithSettings());
}
}
return result;
}
}