/*******************************************************************************
* Copyright (c) 2008-2011 Chair for Applied Software Engineering,
* Technische Universitaet Muenchen.
* 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:
* Maximilian Koegel - initial API and implementation
******************************************************************************/
package org.eclipse.emf.emfstore.internal.client.model.changeTracking.notification.filter;
import java.util.List;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.emfstore.client.handler.ESNotificationFilter;
import org.eclipse.emf.emfstore.common.model.ESObjectContainer;
import org.eclipse.emf.emfstore.common.model.util.ESNotificationInfo;
import org.eclipse.emf.emfstore.internal.common.model.impl.IdEObjectCollectionImpl;
import org.eclipse.emf.emfstore.internal.common.model.util.ModelUtil;
/**
* Filter to ignore Reference Notifications to Elements outside of the project.
*
* @author koegel
*/
public class IgnoreOutsideProjectReferencesFilter implements ESNotificationFilter {
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.client.handler.ESNotificationFilter#check(org.eclipse.emf.emfstore.common.model.util.ESNotificationInfo,
* org.eclipse.emf.emfstore.common.model.ESObjectContainer)
*/
@SuppressWarnings("rawtypes")
public boolean check(ESNotificationInfo notificationInfo, ESObjectContainer<?> container) {
// if notification is from an element disconnected from the project?s containment tree we will not try to filter
// since we cannot derive the project then
if (container == null) {
return false;
}
// only filter reference notifications
if (!notificationInfo.isReferenceNotification()) {
return false;
}
// do not filter notifications on containment or container references
final EReference reference = (EReference) notificationInfo.getFeature();
if (reference.isContainer() || reference.isContainment()) {
return false;
}
// we have a cross-reference feature notification
if (notificationInfo.getEventType() == Notification.MOVE) {
return ModelUtil.getProject(notificationInfo.getNewModelElementValue()) == null;
}
// notification is about adding elements => check added elements
if (notificationInfo.getNewValue() != null && notificationInfo.getNewValue() instanceof List) {
return checkNewValueList(notificationInfo, container);
// notification is about removing elements => check removed elements
} else if (notificationInfo.getOldValue() != null && notificationInfo.getOldValue() instanceof List) {
if (!notificationInfo.wasSet() && ((List) notificationInfo.getOldValue()).size() == 0) {
// do not filter remove notifications on empty list when unset before
return false;
}
return checkOldValueList(notificationInfo, container);
} else {
if (!notificationInfo.wasSet()
&& notificationInfo.getNewValue() == notificationInfo.getStructuralFeature().getDefaultValue()) {
// do not filter notification when unset before and new value is null
return false;
}
// check single reference notification
return checkSingleReference(notificationInfo, container);
}
}
private boolean checkSingleReference(ESNotificationInfo notificationInfo, ESObjectContainer<?> container) {
if (notificationInfo.getEventType() == Notification.UNSET) {
// do NOT filter unset notifications although old and new value are not in project
return false;
}
// if new value is in project then do NOT filter
if (notificationInfo.getOldValue() != null && !notificationInfo.isMoveEvent()
&& isOrWasInProject(container, notificationInfo.getOldModelElementValue())) {
return false;
}
// if old value is in project then do NOT filter
if (notificationInfo.getNewValue() != null
&& isOrWasInProject(container, notificationInfo.getNewModelElementValue())) {
return false;
}
// neither old nor new value are in project => filter
return true;
}
@SuppressWarnings("unchecked")
private boolean checkOldValueList(ESNotificationInfo notificationInfo, ESObjectContainer<?> container) {
for (final EObject referencedElement : (List<EObject>) notificationInfo.getOldValue()) {
if (isOrWasInProject(container, referencedElement)) {
return false;
}
}
// all referenced elements are NOT in the project
return true;
}
@SuppressWarnings("unchecked")
private boolean checkNewValueList(ESNotificationInfo notificationInfo, ESObjectContainer<?> container) {
for (final EObject referencedElement : (List<EObject>) notificationInfo.getNewValue()) {
if (isOrWasInProject(container, referencedElement)) {
return false;
}
}
// all referenced elements are NOT in the project
return true;
}
private boolean isOrWasInProject(ESObjectContainer<?> container, EObject referencedElement) {
if (ModelUtil.isSingleton(referencedElement)) {
return true;
}
final boolean b = container.contains(referencedElement)
|| ((IdEObjectCollectionImpl) container).getDeletedModelElementId(referencedElement) != null;
return b;
}
}