blob: 6493f2346fa3dda4d4effdc789c1673a9e6ffca8 [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2013 CEA LIST 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:
* E.D.Willink (CEA LIST) - initial API and implementation
* Obeo - Fix refreshing and Manage Enabled Nodes Validation
*
* </copyright>
*/
package org.eclipse.ocl.examples.emf.validation.validity.ui.view;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.BasicMonitor;
import org.eclipse.emf.common.util.Monitor;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.examples.emf.validation.validity.AbstractNode;
import org.eclipse.ocl.examples.emf.validation.validity.ConstrainingNode;
import org.eclipse.ocl.examples.emf.validation.validity.LeafConstrainingNode;
import org.eclipse.ocl.examples.emf.validation.validity.Result;
import org.eclipse.ocl.examples.emf.validation.validity.ResultConstrainingNode;
import org.eclipse.ocl.examples.emf.validation.validity.ResultSet;
import org.eclipse.ocl.examples.emf.validation.validity.ResultValidatableNode;
import org.eclipse.ocl.examples.emf.validation.validity.RootNode;
import org.eclipse.ocl.examples.emf.validation.validity.Severity;
import org.eclipse.ocl.examples.emf.validation.validity.ValidatableNode;
import org.eclipse.ocl.examples.emf.validation.validity.ValidityPackage;
import org.eclipse.ocl.examples.emf.validation.validity.locator.ConstraintLocator;
import org.eclipse.ocl.examples.emf.validation.validity.manager.ValidityManager;
import org.eclipse.ocl.examples.emf.validation.validity.manager.ValidityModel;
public class IDEValidityManager extends ValidityManager
{
public static final int FAST_REFRESH_DELAY = 250; // 250 ms delay to aggregate refresh new changes
public static final int SLOW_REFRESH_DELAY = 2500; // 2500 ms delay to aggregate refresh changes when busy
private static final @NonNull List<Job> validityJobs = new ArrayList<Job>();
public static void stopValidation() {
while (!validityJobs.isEmpty()) {
ArrayList<Job> jobs;
synchronized (validityJobs) {
jobs = new ArrayList<Job>(validityJobs);
}
for (Job job : jobs) {
job.cancel();
}
}
}
protected class IDEValidityModel extends ValidityModel
{
public IDEValidityModel(@NonNull IDEValidityManager validityManager, @NonNull Collection<Resource> newResources) {
super(validityManager, newResources);
}
@Override
protected @Nullable Result createResult(@Nullable IProgressMonitor monitor) {
if ((monitor != null) && monitor.isCanceled()) {
return null;
}
Result result = super.createResult(monitor);
if (result == null) {
return null;
}
result.eAdapters().add(resultAdapter);
return result;
}
}
private class ValidityViewJob extends Job
{
protected final @NonNull ValidityView validityView;
private ValidityViewJob(@NonNull ValidityView validityView) {
super("Validity View Validation");
this.validityView = validityView;
}
@Override
protected IStatus run(final /*@NonNull*/ IProgressMonitor monitor) {
assert monitor != null;
try {
final ResultSet resultSet = createResultSet(monitor);
if (resultSet == null) {
return Status.CANCEL_STATUS;
}
List<Result> results = installResultSet(resultSet, monitor);
if (results == null) {
return Status.CANCEL_STATUS;
}
try {
monitor.beginTask("Constraint Validation", results.size());
Monitor emfMonitor = monitor != null ? BasicMonitor.toMonitor(monitor) : null;
int i = 0;
for (Result result : results) {
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
boolean refreshLabels = (i % 100) == 0;
try {
ValidatableNode validatable = result.getValidatableNode();
if (refreshLabels) {
monitor.setTaskName(i + "/" + results.size() + ": " + validatable.toString());
}
ValidatableNode validatableParent = validatable.getParent();
LeafConstrainingNode constraint = result.getLeafConstrainingNode();
if (constraint !=null){
List<ConstrainingNode> constrainingAncestors = getConstrainingNodeAncestors(constraint);
boolean isConstrainingNodeEnabled = true;
for (ConstrainingNode constrainingAncestor: constrainingAncestors){
if (!constrainingAncestor.isEnabled()){
isConstrainingNodeEnabled = false;
break;
}
}
boolean isEnabledForValidation = false;
if (isConstrainingNodeEnabled) {
if (validatable instanceof ResultValidatableNode) {
if (validatableParent != null && validatableParent.isEnabled()) {
isEnabledForValidation = true;
}
} else {
isEnabledForValidation = true;
}
}
if (isEnabledForValidation){
ConstraintLocator constraintLocator = constraint.getConstraintLocator();
constraintLocator.validate(result, IDEValidityManager.this, emfMonitor);
} else {
result.setSeverity(Severity.UNKNOWN);
}
} else {
result.setSeverity(Severity.UNKNOWN);
}
}
catch (Exception e) {
result.setException(e);
result.setSeverity(Severity.FATAL);
}
finally {
if (refreshLabels) {
monitor.worked(100);
}
i++;
}
}
return Status.OK_STATUS;
}
finally {
validityView.redraw();
monitor.done();
}
}
finally {
synchronized (validityJobs) {
validityJobs.remove(this);
}
}
}
private @NonNull List<ConstrainingNode> getConstrainingNodeAncestors(@NonNull ConstrainingNode constraining) {
ConstrainingNode ancestor = constraining.getParent();
List<ConstrainingNode> ancestors = new ArrayList<ConstrainingNode>();
while (ancestor != null) {
ancestors.add(ancestor);
ancestor = ancestor.getParent();
}
return ancestors;
}
}
public class AbstractNodeAdapter extends AdapterImpl
{
@Override
public void notifyChanged(Notification notification) {
Object target = notification.getNotifier();
if (target instanceof AbstractNode) {
int event = notification.getEventType();
Object feature = notification.getFeature();
if (event == Notification.SET) {
if (feature == ValidityPackage.Literals.ABSTRACT_NODE__ENABLED) {
refreshJob.add((AbstractNode) target);
}
else if (feature == ValidityPackage.Literals.ABSTRACT_NODE__GRAYED) {
refreshJob.add((AbstractNode) target);
}
else if (feature == ValidityPackage.Literals.ABSTRACT_NODE__WORST_RESULT) {
refreshJob.add((AbstractNode) target);
}
else if (feature == ValidityPackage.Literals.ABSTRACT_NODE__LABEL) {
refreshJob.add((AbstractNode) target);
}
}
}
}
}
public class ResultAdapter extends AdapterImpl
{
@Override
public void notifyChanged(Notification notification) {
Object target = notification.getNotifier();
if (target instanceof Result) {
Result result = (Result)target;
int event = notification.getEventType();
Object feature = notification.getFeature();
if (event == Notification.SET) {
if (feature == ValidityPackage.Literals.RESULT__SEVERITY) {
ResultConstrainingNode resultConstrainingNode = result.getResultConstrainingNode();
if (resultConstrainingNode != null) {
refreshJob.add(resultConstrainingNode);
ConstrainingNode parent = resultConstrainingNode.getParent();
if (parent != null) {
refreshJob.add(parent);
}
}
ResultValidatableNode resultValidatableNode = result.getResultValidatableNode();
if (resultValidatableNode != null) {
refreshJob.add(resultValidatableNode);
ValidatableNode parent = resultValidatableNode.getParent();
if (parent != null) {
refreshJob.add(parent);
}
}
}
}
}
}
}
private final @NonNull AbstractNodeAdapter nodeAdapter = new AbstractNodeAdapter();
private final @NonNull ResultAdapter resultAdapter = new ResultAdapter();
private final @NonNull ValidityViewRefreshJob refreshJob;
public IDEValidityManager(@NonNull ValidityViewRefreshJob refreshJob) {
this.refreshJob = refreshJob;
// CREATE_CONSTRAINING.setState(true);
// CREATE_RESULT.setState(true);
// CREATE_VALIDATABLE.setState(true);
}
@Override
protected @NonNull ValidityModel createModel(@NonNull Collection<Resource> newResources) {
ValidityModel contents = new IDEValidityModel(this, newResources);
RootNode rootNode = contents.getRootNode();
installAdapters(rootNode.getConstrainingNodes());
installAdapters(rootNode.getValidatableNodes());
return contents;
}
private void installAdapters(@NonNull List<? extends AbstractNode> nodes) {
for (AbstractNode node : nodes) {
node.eAdapters().add(nodeAdapter);
installAdapters(node.getChildren());
}
}
public void runValidation(@NonNull ValidityView validityView) {
Job validationJob = new ValidityViewJob(validityView);
synchronized (validityJobs) {
validityJobs.add(validationJob);
}
validationJob.schedule();
}
public void redraw() {
refreshJob.add(null);
}
}