495670: initial implementation of Detail widgets validation
Change-Id: I2c5b16abe6f93c1d92d7f336fa54eecd0689352a
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=495670
Signed-off-by: Francesco Guidieri <francesco.guidieri@gmail.com>
diff --git a/plugins/org.eclipse.emf.parsley.common/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.parsley.common/META-INF/MANIFEST.MF
index c2686aa..d83aeea 100644
--- a/plugins/org.eclipse.emf.parsley.common/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.parsley.common/META-INF/MANIFEST.MF
@@ -26,6 +26,7 @@
org.eclipse.emf.parsley.edit.ui.dnd,
org.eclipse.emf.parsley.edit.ui.provider,
org.eclipse.emf.parsley.handlers,
+ org.eclipse.emf.parsley.internal.databinding;x-internal:=true,
org.eclipse.emf.parsley.internal.edit.ui.dnd,
org.eclipse.emf.parsley.listeners,
org.eclipse.emf.parsley.menus,
@@ -53,6 +54,7 @@
org.eclipse.jface.action,
org.eclipse.jface.bindings,
org.eclipse.jface.bindings.keys,
+ org.eclipse.jface.databinding.fieldassist,
org.eclipse.jface.databinding.swt,
org.eclipse.jface.databinding.viewers,
org.eclipse.jface.dialogs,
diff --git a/plugins/org.eclipse.emf.parsley.common/src/org/eclipse/emf/parsley/composite/AbstractControlFactory.java b/plugins/org.eclipse.emf.parsley.common/src/org/eclipse/emf/parsley/composite/AbstractControlFactory.java
index 40ce302..e8caeb8 100644
--- a/plugins/org.eclipse.emf.parsley.common/src/org/eclipse/emf/parsley/composite/AbstractControlFactory.java
+++ b/plugins/org.eclipse.emf.parsley.common/src/org/eclipse/emf/parsley/composite/AbstractControlFactory.java
@@ -24,20 +24,24 @@
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.edit.command.SetCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.parsley.EmfParsleyActivator;
import org.eclipse.emf.parsley.EmfParsleyConstants;
import org.eclipse.emf.parsley.edit.IEditingStrategy;
import org.eclipse.emf.parsley.edit.TextUndoRedo;
+import org.eclipse.emf.parsley.internal.databinding.EmfValidationTargetToModelUpdateValueStrategy;
import org.eclipse.emf.parsley.runtime.util.PolymorphicDispatcherExtensions;
import org.eclipse.emf.parsley.ui.provider.ComboViewerLabelProvider;
import org.eclipse.emf.parsley.ui.provider.FeatureLabelCaptionProvider;
import org.eclipse.emf.parsley.util.DatabindingUtil;
import org.eclipse.emf.parsley.util.FeatureHelper;
+import org.eclipse.emf.parsley.validation.DiagnosticUtil;
import org.eclipse.emf.parsley.widgets.IWidgetFactory;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
+import org.eclipse.jface.databinding.fieldassist.ControlDecorationSupport;
import org.eclipse.jface.databinding.viewers.ViewersObservables;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.ControlDecoration;
@@ -95,6 +99,12 @@
@Inject
private ProposalCreator proposalCreator;
+ @Inject
+ private Diagnostician diagnostician;
+
+ @Inject
+ private DiagnosticUtil diagnosticUtil;
+
private EObject owner;
private Resource resource;
private EditingDomain domain;
@@ -332,12 +342,16 @@
.getObservableValue();
if (controlObservable != null) {
- edbc.bindValue(controlObservable, featureObservable, null, null);
+ EmfValidationTargetToModelUpdateValueStrategy targetToModelUpdateValueStrategy =
+ new EmfValidationTargetToModelUpdateValueStrategy(owner,feature,diagnostician, diagnosticUtil);
+
+ Binding bindValue = edbc.bindValue(controlObservable, featureObservable, targetToModelUpdateValueStrategy, null);
+ ControlDecorationSupport.create(bindValue, SWT.TOP | SWT.LEFT);
}
return retVal;
}
-
+
protected ControlObservablePair createControlAndObservableValue(
EStructuralFeature feature, boolean withPolymorphicDispatch) {
if (withPolymorphicDispatch) {
@@ -471,7 +485,9 @@
// set default layout data if not already set by a custom
// polymorphic implementation or from the DSL
if (c.getLayoutData()==null) {
- c.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ GridData deafultLayout = new GridData(GridData.FILL_HORIZONTAL);
+ deafultLayout.horizontalIndent=10;
+ c.setLayoutData(deafultLayout);
}
}
}
diff --git a/plugins/org.eclipse.emf.parsley.common/src/org/eclipse/emf/parsley/internal/databinding/EmfValidationTargetToModelUpdateValueStrategy.java b/plugins/org.eclipse.emf.parsley.common/src/org/eclipse/emf/parsley/internal/databinding/EmfValidationTargetToModelUpdateValueStrategy.java
new file mode 100644
index 0000000..83c4216
--- /dev/null
+++ b/plugins/org.eclipse.emf.parsley.common/src/org/eclipse/emf/parsley/internal/databinding/EmfValidationTargetToModelUpdateValueStrategy.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2016 RCP Vision (http://www.rcp-vision.com) 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:
+ * Francesco Guidieri - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.parsley.internal.databinding;
+
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.List;
+
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.validation.ValidationStatus;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.util.Diagnostician;
+import org.eclipse.emf.parsley.validation.DiagnosticUtil;
+
+import com.google.common.base.Predicate;
+
+/**
+ * @author Francesco Guidieri - initial API and implementation
+ *
+ */
+public class EmfValidationTargetToModelUpdateValueStrategy extends UpdateValueStrategy {
+
+ private EStructuralFeature feature;
+ private Diagnostician diagnostician;
+ private DiagnosticUtil diagnosticUtil;
+ private EObject owner;
+ private boolean firstValidateBeforeSet = true;
+
+ public EmfValidationTargetToModelUpdateValueStrategy(EObject owner, EStructuralFeature feature,
+ Diagnostician diagnostician, DiagnosticUtil diagnosticUtil) {
+ this.owner = owner;
+ this.feature = feature;
+ this.diagnostician = diagnostician;
+ this.diagnosticUtil = diagnosticUtil;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ protected IStatus doSet(IObservableValue observableValue, Object value) {
+ IStatus afterSetStatus = super.doSet(observableValue, (!"".equals(value) ? value : null));
+ if (afterSetStatus.isOK()) {
+ return validationStatus(feature);
+ }
+ return afterSetStatus;
+ };
+
+ @Override
+ public IStatus validateBeforeSet(Object value) {
+ if (firstValidateBeforeSet) {
+ IStatus validationStatus = validationStatus(feature);
+ firstValidateBeforeSet = false;
+ if (!validationStatus.isOK()) {
+ return validationStatus;
+ }
+ return super.validateBeforeSet(value);
+ }
+ return Status.OK_STATUS;
+ }
+
+ private IStatus validationStatus(final EStructuralFeature feature) {
+ Diagnostic diagnostic = diagnostician.validate(owner);
+ List<Diagnostic> diagnostics = diagnosticUtil.flatten(diagnostic);
+ Iterable<Diagnostic> filtered = filter(diagnostics, new Predicate<Diagnostic>() {
+ @Override
+ public boolean apply(Diagnostic d) {
+ return filter(filter(d.getData(), EStructuralFeature.class), new Predicate<EStructuralFeature>() {
+ @Override
+ public boolean apply(EStructuralFeature input) {
+ return input.equals(feature);
+ }
+ }).iterator().hasNext();
+ }
+ });
+ for (Diagnostic d : filtered) {
+ int severity = d.getSeverity();
+ if (severity == Diagnostic.ERROR) {
+ return ValidationStatus.error(d.getMessage());
+ }
+ }
+ return ValidationStatus.ok();
+ }
+}