blob: 4316a8b8a57fd6c8fff38bc8059a57e739835123 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2014 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:
* Eugen Neufeld - initial API and implementation
******************************************************************************/
package org.eclipse.emf.ecp.view.treemasterdetail.internal.validation;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecp.view.model.common.edit.provider.CustomReflectiveItemProviderAdapterFactory;
import org.eclipse.emf.ecp.view.spi.context.GlobalViewModelService;
import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
import org.eclipse.emf.ecp.view.spi.model.ModelChangeListener;
import org.eclipse.emf.ecp.view.spi.model.ModelChangeNotification;
import org.eclipse.emf.ecp.view.spi.model.VView;
import org.eclipse.emf.ecp.view.spi.provider.ViewProviderHelper;
import org.eclipse.emf.ecp.view.treemasterdetail.model.VTreeMasterDetail;
import org.eclipse.emf.ecp.view.treemasterdetail.ui.swt.internal.RootObject;
import org.eclipse.emf.ecp.view.treemasterdetail.ui.swt.internal.TreeMasterDetailSelectionManipulatorHelper;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
/**
* The TreeMasterDatailValidationInitiator searches for {@link VTreeMasterDetail} VElements and registers the necessary
* ViewModelContexts.
*
* @author Eugen Neufeld
*
*/
@SuppressWarnings("restriction")
public class TreeMasterDetailValidationInitiator implements
GlobalViewModelService {
/**
* A Mapping for TreeMasterDetails.
*
* @author Eugen Neufeld
*
*/
private static class TreeContextMapping {
private VTreeMasterDetail control;
private ViewModelContext context;
/**
* {@inheritDoc}
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (context == null ? 0 : context.hashCode());
result = prime * result + (control == null ? 0 : control.hashCode());
return result;
}
/**
* {@inheritDoc}
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final TreeContextMapping other = (TreeContextMapping) obj;
if (context == null) {
if (other.context != null) {
return false;
}
} else if (!context.equals(other.context)) {
return false;
}
if (control == null) {
if (other.control != null) {
return false;
}
} else if (!control.equals(other.control)) {
return false;
}
return true;
}
}
private final Map<TreeContextMapping, Set<Object>> mapping = new LinkedHashMap<TreeContextMapping, Set<Object>>();
/**
* The detail key passed to the view model context.
*/
public static final String DETAIL_KEY = "detail"; //$NON-NLS-1$
/**
* Context key for the root.
*/
public static final String ROOT_KEY = "root"; //$NON-NLS-1$
private ComposedAdapterFactory adapterFactory;
private AdapterFactoryContentProvider adapterFactoryContentProvider;
/**
* Constructor of the Initiator.
*/
public TreeMasterDetailValidationInitiator() {
adapterFactory = new ComposedAdapterFactory(new AdapterFactory[] {
new CustomReflectiveItemProviderAdapterFactory(),
new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE) });
adapterFactoryContentProvider = new AdapterFactoryContentProvider(
adapterFactory) {
@Override
public Object[] getElements(Object object) {
return new Object[] { ((RootObject) object).getRoot() };
}
};
}
@Override
public void instantiate(ViewModelContext context) {
context.registerDomainChangeListener(new ModelChangeListener() {
@Override
public void notifyChange(ModelChangeNotification notification) {
if (notification.getRawNotification().isTouch() || mapping.isEmpty()) {
return;
}
for (final TreeContextMapping treeContextEntry : mapping.keySet()) {
if (!mapping.get(treeContextEntry).contains(notification.getNotifier())) {
return;
}
final Set<Object> children = getAllChildren(manipulateSelection(notification.getNotifier()),
adapterFactoryContentProvider);
if (mapping.get(treeContextEntry).containsAll(children)) {
return;
}
children.removeAll(mapping.get(treeContextEntry));
for (final Object child : children) {
final EObject addedObject = (EObject) manipulateSelection(child);
mapping.get(treeContextEntry).add(addedObject);
final Map<String, Object> context = new LinkedHashMap<String, Object>();
context.put(DETAIL_KEY, true);
context.put(ROOT_KEY, true);
treeContextEntry.context.getChildContext(addedObject,
treeContextEntry.control, ViewProviderHelper.getView(addedObject, context));
}
}
}
});
checkForTreeMasterDetail(context);
}
private void checkForTreeMasterDetail(ViewModelContext context) {
final EObject viewRoot = context.getViewModel();
final TreeIterator<EObject> eAllContents = viewRoot.eAllContents();
while (eAllContents.hasNext()) {
final EObject eObject = eAllContents.next();
if (VTreeMasterDetail.class.isInstance(eObject)) {
final VTreeMasterDetail treeMasterDetail = VTreeMasterDetail.class.cast(eObject);
registerRootChildContext(treeMasterDetail, context);
registerChildrenChildContext(treeMasterDetail, context, adapterFactoryContentProvider);
}
}
}
private void registerChildrenChildContext(VTreeMasterDetail treeMasterDetail, ViewModelContext viewModelContext,
final AdapterFactoryContentProvider adapterFactoryContentProvider) {
final Set<Object> children = getAllChildren(viewModelContext.getDomainModel(),
adapterFactoryContentProvider);
for (final Object object : children) {
final Map<String, Object> context = new LinkedHashMap<String, Object>();
context.put(DETAIL_KEY, true);
final EObject manipulateSelection = (EObject) manipulateSelection(object);
final TreeContextMapping entry = new TreeContextMapping();
entry.context = viewModelContext;
entry.control = treeMasterDetail;
if (!mapping.containsKey(entry)) {
mapping.put(entry, new LinkedHashSet<Object>());
}
mapping.get(entry).add(manipulateSelection);
final VView view = ViewProviderHelper.getView(manipulateSelection, context);
viewModelContext.getChildContext(manipulateSelection, treeMasterDetail, view);
}
}
private void registerRootChildContext(VTreeMasterDetail treeMasterDetail, ViewModelContext viewModelContext) {
final Map<String, Object> context = new LinkedHashMap<String, Object>();
context.put(DETAIL_KEY, true);
context.put(ROOT_KEY, true);
final Object manipulateSelection = manipulateSelection(viewModelContext.getDomainModel());
final TreeContextMapping entry = new TreeContextMapping();
entry.context = viewModelContext;
entry.control = treeMasterDetail;
if (!mapping.containsKey(entry)) {
mapping.put(entry, new LinkedHashSet<Object>());
}
mapping.get(entry).add(manipulateSelection);
VView view = treeMasterDetail.getDetailView();
if (view == null || view.getChildren().isEmpty()) {
view = ViewProviderHelper.getView((EObject) manipulateSelection, context);
}
viewModelContext.getChildContext((EObject) manipulateSelection, treeMasterDetail, view);
}
private Set<Object> getAllChildren(Object parent, AdapterFactoryContentProvider adapterFactoryContentProvider) {
final Set<Object> allChildren = new LinkedHashSet<Object>();
final Object[] children = adapterFactoryContentProvider.getChildren(parent);
for (final Object object : children) {
final Object manipulatedSelection = manipulateSelection(object);
if (!EObject.class.isInstance(manipulatedSelection)) {
continue;
}
allChildren.add(manipulatedSelection);
allChildren.addAll(getAllChildren(object, adapterFactoryContentProvider));
}
return allChildren;
}
private Object manipulateSelection(Object object) {
return TreeMasterDetailSelectionManipulatorHelper.manipulateSelection(object);
}
@Override
public void dispose() {
adapterFactoryContentProvider.dispose();
adapterFactory.dispose();
}
@Override
public int getPriority() {
return 2;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.context.GlobalViewModelService#childViewModelContextAdded(org.eclipse.emf.ecp.view.spi.context.ViewModelContext)
*/
@Override
public void childViewModelContextAdded(ViewModelContext childContext) {
checkForTreeMasterDetail(childContext);
}
}