| /******************************************************************************* |
| * Copyright (c) 2015 Obeo |
| * 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: |
| * Obeo - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.emf.ecoretools.design.service; |
| |
| import java.util.Collection; |
| import java.util.Set; |
| |
| import org.eclipse.emf.common.command.Command; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.util.Diagnostic; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.EcorePackage; |
| import org.eclipse.emf.ecore.util.Diagnostician; |
| import org.eclipse.emf.transaction.NotificationFilter; |
| import org.eclipse.emf.transaction.RecordingCommand; |
| import org.eclipse.emf.transaction.TransactionalEditingDomain; |
| import org.eclipse.sirius.business.api.session.ModelChangeTrigger; |
| import org.eclipse.sirius.ext.base.Option; |
| import org.eclipse.sirius.ext.base.Options; |
| |
| import com.google.common.collect.Sets; |
| |
| public class LiveValidationTrigger implements ModelChangeTrigger { |
| |
| public static final NotificationFilter IS_ECORE_CHANGE = new NotificationFilter.Custom() { |
| |
| public boolean matches(Notification notification) { |
| return (!notification.isTouch() && notification.getFeature() instanceof EStructuralFeature && ((EStructuralFeature) notification.getFeature()).getEContainingClass().getEPackage() == EcorePackage.eINSTANCE); |
| } |
| }; |
| |
| private TransactionalEditingDomain domain; |
| |
| /** |
| * We need to be triggered before the refresh mechanism takes place so that |
| * the diagnostic attachements are up-to date when computing colors. |
| */ |
| public static final int PRIORITY = 0; |
| |
| public LiveValidationTrigger(TransactionalEditingDomain domain) { |
| this.domain = domain; |
| } |
| |
| public Option<Command> localChangesAboutToCommit(Collection<Notification> notifications) { |
| final Set<EObject> changedEcoreObjects = Sets.newLinkedHashSet(); |
| for (Notification notif : notifications) { |
| Object obj = notif.getNotifier(); |
| if (obj instanceof EObject && ((EObject) obj).eClass() != null && ((EObject) obj).eClass().getEPackage() == EcorePackage.eINSTANCE) { |
| changedEcoreObjects.add((EObject) obj); |
| } |
| } |
| if (changedEcoreObjects.size() > 0) { |
| |
| Command revalidateEObjects = new RecordingCommand(domain) { |
| |
| @Override |
| protected void doExecute() { |
| Set<EObject> containers = Sets.newLinkedHashSet(); |
| for (EObject eObj : changedEcoreObjects) { |
| revalidate(eObj); |
| EObject container = eObj.eContainer(); |
| if (container != null) { |
| containers.add(container); |
| } |
| } |
| /* |
| * When an Ecore object changes it is likely the container |
| * might have a new validation error (or an error might be |
| * gone) even if it has suffered no change itself. Example : |
| * two EStructural features having the same name and |
| * contained in the same EClass will trigger an error on |
| * such EClass. This state should be updated when one of the |
| * EStructuralFeature got renamed. |
| */ |
| for (EObject container : containers) { |
| revalidate(container); |
| } |
| } |
| |
| protected void revalidate(EObject eObj) { |
| DiagnosticAttachment diag = DiagnosticAttachment.getAttachment(eObj); |
| /* |
| * If the EObject had a validation marker, then we need to |
| * update its state, otherwise nobody cared about its |
| * validation status, no need to pre-compute it. |
| */ |
| if (diag != null) { |
| try { |
| /* |
| * anything could happen within the validate. We |
| * make sure we won't fail the whole post-process in |
| * this case. |
| */ |
| Diagnostic diagnostic = Diagnostician.INSTANCE.validate(eObj); |
| /* |
| * We attach the result of the validation on the |
| * EObject through the eAdapters list. It might be |
| * consumed by some modelers to change colors or |
| * update tooltips. |
| */ |
| diag.setDiagnostic(diagnostic); |
| } catch (Throwable e) { |
| /* |
| * Anything which happens here might not be a |
| * concern. |
| */ |
| } |
| } |
| } |
| }; |
| |
| return Options.newSome(revalidateEObjects); |
| } |
| |
| return Options.newNone(); |
| } |
| |
| public int priority() { |
| return PRIORITY; |
| } |
| |
| } |