/**
* This file is protected by Copyright.
* Please refer to the COPYRIGHT file distributed with this source distribution.
*
* This file is part of REDHAWK IDE.
*
* 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.
*
*/
/**
* Copyright (c) 2009, 2010 Anyware Technologies 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:
* Anyware Technologies - initial API and implementation
* Sebastien Moran <smoran@sierrawireless.com> - bug 292926
*
* $Id: ValidatingEContentAdapter.java,v 1.14 2010/02/10 10:54:50 bcabe Exp $
*/
package gov.redhawk.internal.ui.editor.validation;
import gov.redhawk.ui.RedhawkUiActivator;
import gov.redhawk.ui.editor.FormOutlinePage;
import gov.redhawk.ui.editor.SCAFormEditor;
import gov.redhawk.ui.validation.ValidatingService;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable;
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.Notifier;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.DiagnosticChain;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecore.util.EContentAdapter;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.provider.IItemLabelProvider;
import org.eclipse.emf.transaction.NotificationFilter;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.ui.forms.IMessageManager;
import org.eclipse.ui.forms.editor.IFormPage;
import org.eclipse.ui.progress.WorkbenchJob;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
public class ValidatingEContentAdapter extends EContentAdapter {
private final SCAFormEditor formEditor;
private final DataBindingContext dataBindingContext;
private final Diagnostician diagnostician;
private final ValidatingService validatingService = new ValidatingService34();
private final Notifier root;
// Ensure that the update is performed within the UI Thread. See Bug
// #292926
private final WorkbenchJob updateManagerJob = new WorkbenchJob("Update Message Manager") {
{
setPriority(Job.INTERACTIVE);
setUser(false);
setSystem(true);
}
/**
* {@inheritDoc}
*/
@Override
public boolean shouldRun() {
return super.shouldRun() && !ValidatingEContentAdapter.this.formEditor.isDisposed();
}
@Override
public IStatus runInUIThread(final IProgressMonitor monitor) {
final IFormPage activePageInstance = ValidatingEContentAdapter.this.formEditor.getActivePageInstance();
if (activePageInstance == null || activePageInstance.getManagedForm() == null) {
return Status.OK_STATUS;
}
final IMessageManager messageManager = activePageInstance.getManagedForm().getMessageManager();
if (!ValidatingEContentAdapter.this.formEditor.isDisposed()) {
messageManager.update();
//Force a viewer refresh so all labels get updated properly
if (ValidatingEContentAdapter.this.formEditor.getViewer() != null) {
ValidatingEContentAdapter.this.formEditor.getViewer().refresh();
}
IContentOutlinePage outline = ValidatingEContentAdapter.this.formEditor.getFormOutline();
if (outline != null && outline instanceof FormOutlinePage) {
((FormOutlinePage) outline).refresh();
}
}
return Status.OK_STATUS;
}
};
public ValidatingEContentAdapter(final SCAFormEditor formEditor, final Notifier root) {
this.formEditor = formEditor;
this.dataBindingContext = formEditor.getDataBindingContext();
this.root = root;
// Subclass the default Diagnostician to customize the String
// representation of each validated EObject
this.diagnostician = new Diagnostician() {
@Override
public String getObjectLabel(final EObject eObject) {
if (!eObject.eIsProxy()) {
final IItemLabelProvider itemLabelProvider = (IItemLabelProvider) ValidatingEContentAdapter.this.formEditor.getAdapterFactory().adapt(
eObject, IItemLabelProvider.class);
if (itemLabelProvider != null) {
return itemLabelProvider.getText(eObject);
}
}
return super.getObjectLabel(eObject);
}
@Override
protected boolean doValidateContents(final EObject eObject, final DiagnosticChain diagnostics, final Map<Object, Object> context) {
final Resource eContainerResource = eObject.eResource();
final List<EObject> eContents = eObject.eContents();
if (!eContents.isEmpty()) {
boolean result = true;
for (final Iterator<EObject> i = eContents.iterator(); i.hasNext() && (result || diagnostics != null);) {
final EObject child = i.next();
// in case of cross resource containment,
// avoid to validate a child which are not in the
// container resource
final Resource eChildResource = child.eResource();
if (eContainerResource != null && eChildResource == eContainerResource) {
result &= validate(child, diagnostics, context);
}
}
return result;
}
return true;
}
};
}
@Override
public void notifyChanged(final Notification notification) {
super.notifyChanged(notification);
if (!NotificationFilter.READ.matches(notification)) {
validate();
}
}
public void validate() {
final IFormPage activePageInstance = this.formEditor.getActivePageInstance();
if (activePageInstance == null || activePageInstance.getManagedForm() == null) {
return;
}
final IMessageManager messageManager = activePageInstance.getManagedForm().getMessageManager();
messageManager.removeAllMessages();
messageManager.setAutoUpdate(false);
final BasicDiagnostic diagnostics = new BasicDiagnostic();
if (this.root instanceof ResourceSet) {
validateResourceSet((ResourceSet) this.root, messageManager, diagnostics);
} else if (this.root instanceof Resource) {
validateResource((Resource) this.root, messageManager, diagnostics);
} else if (this.root instanceof EObject) {
validatorEObject((EObject) this.root, messageManager, diagnostics);
}
for (final Diagnostic diagnostic : diagnostics.getChildren()) {
getValidatorService().analyzeDiagnostic(this.dataBindingContext, diagnostic, messageManager);
}
this.updateManagerJob.schedule();
}
/**
* @param root2
*/
private void validatorEObject(final EObject obj, final IMessageManager messageManager, final DiagnosticChain diagnostic) {
validate(obj, diagnostic);
}
/**
* @param root2
*/
private void validateResource(final Resource resource, final IMessageManager messageManager, final DiagnosticChain diagnostic) {
if (this.formEditor.isPersisted(resource)) {
for (final EObject obj : resource.getContents()) {
if (obj != null) {
validatorEObject(obj, messageManager, diagnostic);
}
}
}
}
/**
* @param root2
* @param messageManager
*/
private void validateResourceSet(final ResourceSet resourceSet, final IMessageManager messageManager, final DiagnosticChain diagnosticChain) {
List<Resource> resources = new ArrayList<Resource>(resourceSet.getResources());
for (final Object o : resources) {
final Resource resource = (Resource) o;
validateResource(resource, messageManager, diagnosticChain);
}
}
public void validate(final EObject obj, final DiagnosticChain diagnostic) {
EditingDomain editingDomain = formEditor.getEditingDomain();
if (editingDomain instanceof TransactionalEditingDomain) {
TransactionalEditingDomain ted = (TransactionalEditingDomain) editingDomain;
try {
ted.runExclusive(new Runnable() {
@Override
public void run() {
SafeRunnable.run(new ISafeRunnable() {
@Override
public void run() throws Exception {
diagnostician.validate(obj, diagnostic);
}
@Override
public void handleException(Throwable exception) {
diagnostic.add(BasicDiagnostic.toDiagnostic(new Status(Status.ERROR, RedhawkUiActivator.getPluginId(), "FATAL Diagnostic exception on: " + obj, exception)));
}
});
}
});
} catch (InterruptedException e) {
// PASS
}
} else {
SafeRunnable.run(new ISafeRunnable() {
@Override
public void run() throws Exception {
diagnostician.validate(obj, diagnostic);
}
@Override
public void handleException(Throwable exception) {
diagnostic.add(BasicDiagnostic.toDiagnostic(new Status(Status.ERROR, RedhawkUiActivator.getPluginId(), "FATAL Diagnostic exception on: " + obj, exception)));
}
});
}
}
private ValidatingService getValidatorService() {
return this.validatingService;
}
}