Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/infra')
-rw-r--r--plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSModelElementFactory.java13
-rw-r--r--plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSPreferencesModelElementFactory.java8
-rw-r--r--plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSThemesModelElement.java9
-rw-r--r--plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSThemesModelElementFactory.java22
-rw-r--r--plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/AppearanceModelElementFactory.java4
-rw-r--r--plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/CustomStyleModelElementFactory.java12
-rw-r--r--plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/DecoratedModelElementFactory.java24
-rw-r--r--plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/NotationModelElementFactory.java42
-rw-r--r--plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/RulerAndGridModelElement.java11
-rw-r--r--plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/RulersAndGridModelElementFactory.java34
-rw-r--r--plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.properties/src/org/eclipse/papyrus/infra/nattable/properties/modelelement/NatTableFactory.java19
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.tools/META-INF/MANIFEST.MF3
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingInvocationHandler.java174
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservable.java348
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableCollection.java131
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableList.java205
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableSet.java128
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableValue.java140
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/IDelegatingObservable.java53
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/MultipleObservableValue.java14
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/ReferenceCountedObservable.java372
-rw-r--r--plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractValueEditor.java19
22 files changed, 1694 insertions, 91 deletions
diff --git a/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSModelElementFactory.java b/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSModelElementFactory.java
index d71749709c0..b20a7c20261 100644
--- a/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSModelElementFactory.java
+++ b/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSModelElementFactory.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2012 CEA LIST.
+ * Copyright (c) 2012, 2014 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
@@ -8,6 +8,8 @@
*
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 417409
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.css.properties.modelelement;
@@ -16,14 +18,15 @@ import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.infra.gmfdiag.common.helper.NotationHelper;
import org.eclipse.papyrus.infra.gmfdiag.css.properties.Activator;
+import org.eclipse.papyrus.infra.gmfdiag.properties.modelelement.CustomStyleModelElement;
+import org.eclipse.papyrus.infra.gmfdiag.properties.modelelement.CustomStyleModelElementFactory;
import org.eclipse.papyrus.views.properties.contexts.DataContextElement;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElement;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElementFactory;
-public class CSSModelElementFactory implements ModelElementFactory {
+public class CSSModelElementFactory extends CustomStyleModelElementFactory {
- public ModelElement createFromSource(Object sourceElement, DataContextElement context) {
+ @Override
+ protected CustomStyleModelElement doCreateFromSource(Object sourceElement, DataContextElement context) {
View view = NotationHelper.findView(sourceElement);
if(view == null) {
Activator.log.warn("The selected element cannot be resolved to a GMF View");
diff --git a/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSPreferencesModelElementFactory.java b/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSPreferencesModelElementFactory.java
index d335bb1eb20..e7ee6f2327f 100644
--- a/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSPreferencesModelElementFactory.java
+++ b/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSPreferencesModelElementFactory.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2012 CEA LIST.
+ * Copyright (c) 2012, 2014 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
@@ -8,18 +8,20 @@
*
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 417409
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.css.properties.modelelement;
import org.eclipse.papyrus.views.properties.contexts.DataContextElement;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElement;
+import org.eclipse.papyrus.views.properties.modelelement.PreferencesModelElement;
import org.eclipse.papyrus.views.properties.modelelement.PreferencesModelElementFactory;
public class CSSPreferencesModelElementFactory extends PreferencesModelElementFactory {
@Override
- public ModelElement createFromSource(Object sourceElement, DataContextElement context) {
+ protected PreferencesModelElement doCreateFromSource(Object sourceElement, DataContextElement context) {
return new CSSPreferencesModelElement(context);
}
}
diff --git a/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSThemesModelElement.java b/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSThemesModelElement.java
index 6d54d2890d9..5be7b852581 100644
--- a/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSThemesModelElement.java
+++ b/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSThemesModelElement.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2014 CEA LIST.
+ * Copyright (c) 2014 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
@@ -7,7 +7,9 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.net - Initial API and implementation
+ * Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.net - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 417409
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.css.properties.modelelement;
@@ -17,7 +19,6 @@ import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.papyrus.infra.gmfdiag.css.properties.provider.CSSStyleSheetLabelProvider;
import org.eclipse.papyrus.views.properties.modelelement.EMFModelElement;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElement;
/**
@@ -27,7 +28,7 @@ import org.eclipse.papyrus.views.properties.modelelement.ModelElement;
* @author gpascual
*
*/
-public class CSSThemesModelElement extends EMFModelElement implements ModelElement {
+public class CSSThemesModelElement extends EMFModelElement {
/** UI view path for theme style sheets. */
private static final String THEME_STYLESHEETS_PATH = "stylesheets"; //$NON-NLS-1$
diff --git a/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSThemesModelElementFactory.java b/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSThemesModelElementFactory.java
index ade28c59815..f486fb3b640 100644
--- a/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSThemesModelElementFactory.java
+++ b/plugins/infra/gmfdiag/css/org.eclipse.papyrus.infra.gmfdiag.css.properties/src/org/eclipse/papyrus/infra/gmfdiag/css/properties/modelelement/CSSThemesModelElementFactory.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2014 CEA LIST.
+ * Copyright (c) 2014 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
@@ -7,7 +7,9 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.net - Initial API and implementation
+ * Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.net - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 417409
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.css.properties.modelelement;
@@ -17,8 +19,7 @@ import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.views.properties.Activator;
import org.eclipse.papyrus.views.properties.contexts.DataContextElement;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElement;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElementFactory;
+import org.eclipse.papyrus.views.properties.modelelement.AbstractEMFModelElementFactory;
/**
@@ -28,7 +29,7 @@ import org.eclipse.papyrus.views.properties.modelelement.ModelElementFactory;
* @author gpascual
*
*/
-public class CSSThemesModelElementFactory implements ModelElementFactory {
+public class CSSThemesModelElementFactory extends AbstractEMFModelElementFactory<CSSThemesModelElement> {
/**
@@ -39,15 +40,8 @@ public class CSSThemesModelElementFactory implements ModelElementFactory {
super();
}
- /**
- * @see org.eclipse.papyrus.views.properties.modelelement.ModelElementFactory#createFromSource(java.lang.Object,
- * org.eclipse.papyrus.views.properties.contexts.DataContextElement)
- *
- * @param sourceElement
- * @param context
- * @return
- */
- public ModelElement createFromSource(Object sourceElement, DataContextElement context) {
+ @Override
+ protected CSSThemesModelElement doCreateFromSource(Object sourceElement, DataContextElement context) {
EObject source = EMFHelper.getEObject(sourceElement);
if(source == null) {
diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/AppearanceModelElementFactory.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/AppearanceModelElementFactory.java
index 11f5520683c..de8b9efcdd8 100644
--- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/AppearanceModelElementFactory.java
+++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/AppearanceModelElementFactory.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2012 CEA LIST.
+ * Copyright (c) 2012, 2014 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
@@ -8,6 +8,8 @@
*
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 417409
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.properties.modelelement;
diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/CustomStyleModelElementFactory.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/CustomStyleModelElementFactory.java
index 87769b7b6d4..a2c8553afea 100644
--- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/CustomStyleModelElementFactory.java
+++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/CustomStyleModelElementFactory.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2012 CEA LIST.
+ * Copyright (c) 2012, 2014 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
@@ -8,6 +8,8 @@
*
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 417409
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.properties.modelelement;
@@ -17,13 +19,13 @@ import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.infra.gmfdiag.common.helper.NotationHelper;
import org.eclipse.papyrus.infra.gmfdiag.properties.Activator;
import org.eclipse.papyrus.views.properties.contexts.DataContextElement;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElement;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElementFactory;
+import org.eclipse.papyrus.views.properties.modelelement.AbstractEMFModelElementFactory;
-public class CustomStyleModelElementFactory implements ModelElementFactory {
+public class CustomStyleModelElementFactory extends AbstractEMFModelElementFactory<CustomStyleModelElement> {
- public ModelElement createFromSource(Object sourceElement, DataContextElement context) {
+ @Override
+ protected CustomStyleModelElement doCreateFromSource(Object sourceElement, DataContextElement context) {
View view = NotationHelper.findView(sourceElement);
if(view != null) {
diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/DecoratedModelElementFactory.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/DecoratedModelElementFactory.java
index e549d8f8dd4..3b7b2cc602b 100644
--- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/DecoratedModelElementFactory.java
+++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/DecoratedModelElementFactory.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2014 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
@@ -8,25 +8,28 @@
*
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 417409
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.properties.modelelement;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.infra.gmfdiag.common.helper.NotationHelper;
import org.eclipse.papyrus.infra.gmfdiag.common.providers.ShapeDecorator;
import org.eclipse.papyrus.infra.gmfdiag.properties.Activator;
import org.eclipse.papyrus.views.properties.contexts.DataContextElement;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElement;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElementFactory;
+import org.eclipse.papyrus.views.properties.modelelement.AbstractModelElementFactory;
/**
* A factory for handling the GMF decorated elements
*/
-public class DecoratedModelElementFactory implements ModelElementFactory {
+public class DecoratedModelElementFactory extends AbstractModelElementFactory<DecoratedModelElement> {
- public ModelElement createFromSource(Object sourceElement, DataContextElement context) {
+ @Override
+ protected DecoratedModelElement doCreateFromSource(Object sourceElement, DataContextElement context) {
View view = NotationHelper.findView(sourceElement);
if(view != null) {
@@ -34,11 +37,20 @@ public class DecoratedModelElementFactory implements ModelElementFactory {
if(ShapeDecorator.isDecorable(view)) {
return new DecoratedModelElement(view, domain);
}
-
+
}
Activator.log.warn("The selected element cannot be resolved to a Decorated element");
return null;
}
+ @Override
+ protected void updateModelElement(DecoratedModelElement modelElement, Object newSourceElement) {
+ View view = NotationHelper.findView(newSourceElement);
+ if((view == null) || !ShapeDecorator.isDecorable(view)) {
+ throw new IllegalArgumentException("Cannot resolve decorable View selection: " + newSourceElement);
+ }
+ modelElement.source = view;
+ modelElement.domain = EMFHelper.resolveEditingDomain(view);
+ }
}
diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/NotationModelElementFactory.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/NotationModelElementFactory.java
index 6a0889ccf7d..a0895d13c2d 100644
--- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/NotationModelElementFactory.java
+++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/NotationModelElementFactory.java
@@ -9,6 +9,7 @@
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
* Christian W. Damus (CEA) - bug 323802
+ * Christian W. Damus (CEA) - bug 417409
*
*****************************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.properties.modelelement;
@@ -21,17 +22,18 @@ import org.eclipse.papyrus.infra.gmfdiag.common.helper.NotationHelper;
import org.eclipse.papyrus.infra.gmfdiag.properties.Activator;
import org.eclipse.papyrus.infra.gmfdiag.properties.databinding.ObservableGradientData;
import org.eclipse.papyrus.views.properties.contexts.DataContextElement;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElement;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElementFactory;
+import org.eclipse.papyrus.views.properties.modelelement.AbstractEMFModelElementFactory;
+import org.eclipse.papyrus.views.properties.modelelement.AbstractModelElement;
+import org.eclipse.papyrus.views.properties.modelelement.AbstractModelElementFactory;
/**
* A factory for handling the GMF Notation elements
*
* @author Camille Letavernier
*/
-public class NotationModelElementFactory implements ModelElementFactory {
-
- public ModelElement createFromSource(Object sourceElement, DataContextElement context) {
+public class NotationModelElementFactory extends AbstractModelElementFactory<AbstractModelElement> {
+ @Override
+ protected AbstractModelElement doCreateFromSource(Object sourceElement, DataContextElement context) {
if (sourceElement instanceof ObservableGradientData) {
ObservableGradientData gradientData = (ObservableGradientData)sourceElement;
@@ -50,4 +52,34 @@ public class NotationModelElementFactory implements ModelElementFactory {
return null;
}
+ @Override
+ protected void updateModelElement(AbstractModelElement modelElement, Object newSourceElement) {
+ if(modelElement instanceof GMFModelElement) {
+ updateModelElement((GMFModelElement)modelElement, newSourceElement);
+ } else if(modelElement instanceof GradientDataModelElement) {
+ updateModelElement((GradientDataModelElement)modelElement, newSourceElement);
+ }
+ }
+
+ void updateModelElement(GradientDataModelElement modelElement, Object newSourceElement) {
+ if(newSourceElement instanceof ObservableGradientData) {
+ ObservableGradientData ogd = (ObservableGradientData)newSourceElement;
+ modelElement.sourceElement = ogd;
+ modelElement.owner = ogd.getOwner();
+ } else if(newSourceElement instanceof GradientData) {
+ modelElement.sourceElement = (GradientData)newSourceElement;
+ modelElement.owner = null;
+ } else {
+ throw new IllegalArgumentException("Cannot resolve GradientData selection: " + newSourceElement);
+ }
+ }
+
+ void updateModelElement(GMFModelElement modelElement, Object newSourceElement) {
+ View view = NotationHelper.findView(newSourceElement);
+ if(view == null) {
+ throw new IllegalArgumentException("Cannot resolve View selection: " + newSourceElement);
+ }
+
+ AbstractEMFModelElementFactory.updateEMFModelElement(modelElement, view);
+ }
}
diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/RulerAndGridModelElement.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/RulerAndGridModelElement.java
index 87f0f8cfd2b..cae3f549ea8 100644
--- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/RulerAndGridModelElement.java
+++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/RulerAndGridModelElement.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2014 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
@@ -7,8 +7,9 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- *
- * CEA LIST - Initial API and implementation
+ *
+ * CEA LIST - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 417409
*
*****************************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.properties.modelelement;
@@ -47,12 +48,12 @@ public class RulerAndGridModelElement extends AbstractModelElement {
/**
* the diagram for which we are editing preferences
*/
- private Diagram diagram;
+ protected Diagram diagram;
/**
* the edited preference store
*/
- private IPreferenceStore store;
+ protected IPreferenceStore store;
/**
*
diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/RulersAndGridModelElementFactory.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/RulersAndGridModelElementFactory.java
index 0709999a89e..8b7e6e1abfe 100644
--- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/RulersAndGridModelElementFactory.java
+++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.properties/src/org/eclipse/papyrus/infra/gmfdiag/properties/modelelement/RulersAndGridModelElementFactory.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2014 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
@@ -7,8 +7,9 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- *
- * CEA LIST - Initial API and implementation
+ *
+ * CEA LIST - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 417409
*
*****************************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.properties.modelelement;
@@ -23,26 +24,17 @@ import org.eclipse.papyrus.infra.gmfdiag.common.helper.NotationHelper;
import org.eclipse.papyrus.infra.gmfdiag.common.utils.DiagramEditPartsUtil;
import org.eclipse.papyrus.infra.gmfdiag.properties.Activator;
import org.eclipse.papyrus.views.properties.contexts.DataContextElement;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElement;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElementFactory;
+import org.eclipse.papyrus.views.properties.modelelement.AbstractModelElementFactory;
/**
*
* @author vl222926
* The factory used to edit Rulers and Grid properties
*/
-public class RulersAndGridModelElementFactory implements ModelElementFactory {
+public class RulersAndGridModelElementFactory extends AbstractModelElementFactory<RulerAndGridModelElement> {
- /**
- *
- * @see org.eclipse.papyrus.views.properties.modelelement.ModelElementFactory#createFromSource(java.lang.Object,
- * org.eclipse.papyrus.views.properties.contexts.DataContextElement)
- *
- * @param sourceElement
- * @param context
- * @return
- */
- public ModelElement createFromSource(Object sourceElement, DataContextElement context) {
+ @Override
+ protected RulerAndGridModelElement doCreateFromSource(Object sourceElement, DataContextElement context) {
if(sourceElement instanceof EditPart) {
final IPreferenceStore preferenceStore = DiagramEditPartsUtil.getDiagramWorkspacePreferenceStore((EditPart)sourceElement);
View view = NotationHelper.findView(DiagramEditPartsUtil.getDiagramEditPart((EditPart)sourceElement));
@@ -56,6 +48,14 @@ public class RulersAndGridModelElementFactory implements ModelElementFactory {
return null;
}
-
+ @Override
+ protected void updateModelElement(RulerAndGridModelElement modelElement, Object newSourceElement) {
+ if(!(newSourceElement instanceof EditPart)) {
+ throw new IllegalArgumentException("Cannot resolve EditPart selection: " + newSourceElement);
+ }
+ EditPart editPart = (EditPart)newSourceElement;
+ modelElement.store = DiagramEditPartsUtil.getDiagramWorkspacePreferenceStore(editPart);
+ modelElement.diagram = (Diagram)NotationHelper.findView(DiagramEditPartsUtil.getDiagramEditPart(editPart));
+ }
}
diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.properties/src/org/eclipse/papyrus/infra/nattable/properties/modelelement/NatTableFactory.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.properties/src/org/eclipse/papyrus/infra/nattable/properties/modelelement/NatTableFactory.java
index 11b51492418..0c7e6645c70 100644
--- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.properties/src/org/eclipse/papyrus/infra/nattable/properties/modelelement/NatTableFactory.java
+++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.properties/src/org/eclipse/papyrus/infra/nattable/properties/modelelement/NatTableFactory.java
@@ -1,7 +1,6 @@
/*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2014 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
@@ -9,6 +8,7 @@
*
* Contributors:
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 417409
*
*****************************************************************************/
package org.eclipse.papyrus.infra.nattable.properties.modelelement;
@@ -20,23 +20,14 @@ import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.infra.nattable.model.nattable.Table;
import org.eclipse.papyrus.infra.nattable.properties.Activator;
import org.eclipse.papyrus.views.properties.contexts.DataContextElement;
+import org.eclipse.papyrus.views.properties.modelelement.EMFModelElement;
import org.eclipse.papyrus.views.properties.modelelement.EMFModelElementFactory;
-import org.eclipse.papyrus.views.properties.modelelement.ModelElement;
public class NatTableFactory extends EMFModelElementFactory {
- /**
- *
- * @see org.eclipse.papyrus.views.properties.modelelement.EMFModelElementFactory#createFromSource(java.lang.Object,
- * org.eclipse.papyrus.views.properties.contexts.DataContextElement)
- *
- * @param sourceElement
- * @param context
- * @return
- */
@Override
- public ModelElement createFromSource(final Object sourceElement, final DataContextElement context) {
+ protected EMFModelElement doCreateFromSource(Object sourceElement, DataContextElement context) {
EObject source = EMFHelper.getEObject(sourceElement);
if(source == null) {
Activator.log.warn("Unable to resolve the selected element to an EObject"); //$NON-NLS-1$
@@ -46,7 +37,7 @@ public class NatTableFactory extends EMFModelElementFactory {
EditingDomain domain = AdapterFactoryEditingDomain.getEditingDomainFor(source);
return new NatTableModelElement((Table)source, domain);
} else {
- return super.createFromSource(sourceElement, context);
+ return super.doCreateFromSource(sourceElement, context);
}
}
}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.tools/META-INF/MANIFEST.MF b/plugins/infra/org.eclipse.papyrus.infra.tools/META-INF/MANIFEST.MF
index 69b756e3f75..b2b0b9839a1 100644
--- a/plugins/infra/org.eclipse.papyrus.infra.tools/META-INF/MANIFEST.MF
+++ b/plugins/infra/org.eclipse.papyrus.infra.tools/META-INF/MANIFEST.MF
@@ -13,7 +13,8 @@ Require-Bundle: org.eclipse.ui,
org.eclipse.emf.ecore;bundle-version="2.9.0",
org.eclipse.emf.ecore.xmi;bundle-version="2.9.0",
org.eclipse.emf.edit;bundle-version="2.9.0",
- org.eclipse.core.expressions;bundle-version="3.4.500"
+ org.eclipse.core.expressions;bundle-version="3.4.500",
+ com.google.guava;bundle-version="11.0.0"
Bundle-Vendor: %Bundle-Vendor
Bundle-ActivationPolicy: lazy
Bundle-Version: 1.0.0.qualifier
diff --git a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingInvocationHandler.java b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingInvocationHandler.java
new file mode 100644
index 00000000000..6dd91f9e37b
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingInvocationHandler.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.tools.databinding;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.databinding.observable.IObservable;
+
+
+/**
+ * An invocation handler for dynamic proxies that wrap {@link DelegatingObservable}s to implement other interfaces of those delegators' delegates,
+ * such as the papyrus {@code ICommitListener} interface from the Widgets API.
+ */
+class DelegatingInvocationHandler implements InvocationHandler {
+
+ private final IDelegatingObservable delegator;
+
+ private final Class<? extends IObservable> delegatedInterface;
+
+ private DelegatingInvocationHandler(IDelegatingObservable delegator, Class<? extends IObservable> delegatedInterface) {
+ super();
+
+ this.delegator = delegator;
+ this.delegatedInterface = delegatedInterface;
+ }
+
+ public static <T extends IObservable> T wrap(IDelegatingObservable delegator, Class<T> delegatedInterface) {
+ T result;
+
+ List<Class<?>> mixins = null;
+
+ IObservable delegate = delegator.getDelegate();
+
+ for(Class<?> next : allInterfaces(delegate.getClass())) {
+ // Already have the core observable interfaces covered
+ if(!next.isAssignableFrom(delegatedInterface)) {
+ if(mixins == null) {
+ mixins = new ArrayList<Class<?>>(1);
+ }
+ mixins.add(next);
+ }
+ }
+
+ if(mixins == null) {
+ result = delegatedInterface.cast(delegator);
+ } else {
+ // This class loader is sure to be able to see all of the interfaces implemented by the delegate.
+ // But the question is, can it see the IDelegatingObservable interface?
+ ClassLoader loader = delegator.getDelegate().getClass().getClassLoader();
+ try {
+ if(loader.loadClass(IDelegatingObservable.class.getName()) != IDelegatingObservable.class) {
+ // This loader can't see the same class. Use my loader, instead
+ loader = DelegatingInvocationHandler.class.getClassLoader();
+ }
+ } catch (Exception e) {
+ // This loader can't see the class. Use my loader, instead
+ loader = DelegatingInvocationHandler.class.getClassLoader();
+ }
+
+ result = wrap(delegator, delegatedInterface, loader, mixins.toArray(new Class<?>[mixins.size()]));
+ }
+
+ return result;
+ }
+
+ static Set<Class<?>> allInterfaces(Class<?> clazz) {
+ Set<Class<?>> result = new HashSet<Class<?>>();
+ collectAllInterfaces(clazz, result);
+ return result;
+ }
+
+ private static void collectAllInterfaces(Class<?> clazz, Collection<Class<?>> result) {
+ Class<?>[] interfaces = clazz.getInterfaces();
+ for(int i = 0; i < interfaces.length; i++) {
+ // Don't need to collect super-interfaces because they are inherited
+ result.add(interfaces[i]);
+ }
+
+ // Climb the type hierarchy to get interfaces of superclasses (which may be unrelated to direct interfaces)
+ Class<?> zuper = clazz.getSuperclass();
+ if(zuper != null) {
+ collectAllInterfaces(zuper, result);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T extends IObservable> T wrap(IDelegatingObservable delegator, Class<T> delegatedInterface, ClassLoader loader, Class<?>... mixins) {
+ T result;
+
+ if((loader == null) || (mixins.length == 0)) {
+ // Nothing to wrap
+ result = delegatedInterface.cast(delegator);
+ } else {
+ List<Class<?>> interfaces = new ArrayList<Class<?>>(mixins.length + 2);
+ interfaces.add(delegatedInterface);
+ interfaces.add(IDelegatingObservable.class);
+ interfaces.addAll(Arrays.asList(mixins));
+ InvocationHandler handler = new DelegatingInvocationHandler(delegator, delegatedInterface);
+
+ result = delegatedInterface.cast(Proxy.newProxyInstance(loader, interfaces.toArray(new Class<?>[interfaces.size()]), handler));
+ ((DelegatingObservable<T>)delegator).setRealObservable(result);
+ }
+
+ return result;
+ }
+
+ /**
+ * The interesting case of wrapping an observable that is already one of our delegating dynamic proxies.
+ *
+ * @param proxy
+ * a dynamic proxy implementing the {@link IDelegatingObservable} interface
+ *
+ * @return another dynamic proxy of the same class, which delegates to the supplied {@code proxy}
+ *
+ * @throws Exception
+ * on failure to create a new dynamic proxy of the same kind as the delegate {@code proxy}
+ */
+ @SuppressWarnings("unchecked")
+ static <T extends IObservable> T wrapDynamicProxy(T proxy) throws Exception {
+ final DelegatingInvocationHandler proxyHandler = (DelegatingInvocationHandler)Proxy.getInvocationHandler(proxy);
+
+ // Create a new delegator of the appropriate class
+ DelegatingObservable<T> proxyDelegator = (DelegatingObservable<T>)proxyHandler.delegator;
+ DelegatingObservable<T> delegator = proxyDelegator.getClass().getDeclaredConstructor(proxyHandler.delegatedInterface).newInstance(proxy);
+
+ // Create an invocation handler for the same delegated interface as the wrapped proxy
+ DelegatingInvocationHandler handler = new DelegatingInvocationHandler(delegator, proxyHandler.delegatedInterface);
+
+ // And create a new delegating proxy of the same class
+ return (T)proxy.getClass().getDeclaredConstructor(InvocationHandler.class).newInstance(handler);
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ Object result = null;
+
+ Class<?> owner = method.getDeclaringClass();
+
+ try {
+ if((owner == delegatedInterface) || (owner == IDelegatingObservable.class) || (owner == ReferenceCountedObservable.class) || (owner == Object.class) || owner.isAssignableFrom(delegatedInterface)) {
+ // Refer this to our delegate
+ result = method.invoke(delegator, args);
+ } else {
+ // Refer this to the delegator's delegate
+ result = method.invoke(delegator.getDelegate(), args);
+ }
+ } catch (InvocationTargetException e) {
+ // Don't just re-throw this because chances are it's triggered by a run-time exception (doesn't need to
+ // be declared) or by a declared exception. The ITE type is not usually declared in API signatures
+ // (in fact, it really should only be declared by the Method::invoke(...) API!)
+ throw e.getTargetException();
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservable.java b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservable.java
new file mode 100644
index 00000000000..55393927999
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservable.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.tools.databinding;
+
+import java.lang.reflect.Proxy;
+
+import org.eclipse.core.databinding.observable.ChangeEvent;
+import org.eclipse.core.databinding.observable.DisposeEvent;
+import org.eclipse.core.databinding.observable.IChangeListener;
+import org.eclipse.core.databinding.observable.IDisposeListener;
+import org.eclipse.core.databinding.observable.IObservable;
+import org.eclipse.core.databinding.observable.IObserving;
+import org.eclipse.core.databinding.observable.IStaleListener;
+import org.eclipse.core.databinding.observable.ObservableEvent;
+import org.eclipse.core.databinding.observable.ObservableTracker;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.StaleEvent;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.core.databinding.observable.set.IObservableSet;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+
+
+/**
+ * Abstract implementation of the {@link IDelegatingObservable} protocol with factory methods for creation of delegators.
+ *
+ * @see #wrap(IObservable)
+ * @see #create(Realm, Class)
+ * @see #create(Realm, Class, ClassLoader, Class...)
+ */
+public abstract class DelegatingObservable<T extends IObservable> extends ReferenceCountedObservable.Abstract implements IDelegatingObservable {
+
+ private final Class<T> delegateType;
+
+ private T delegate;
+
+ @SuppressWarnings("unchecked")
+ private T realObservable = (T)this;
+
+ private IChangeListener forwardingChangeListener;
+
+ private IStaleListener forwardingStaleListener;
+
+ private IDisposeListener delegateDisposeListener;
+
+ DelegatingObservable(T delegate, Class<T> delegateType) {
+ super(delegate.getRealm());
+
+ this.delegateType = delegateType;
+
+ setDelegate(delegate);
+ }
+
+ DelegatingObservable(Realm realm, Class<T> delegateType) {
+ super(realm);
+
+ this.delegateType = delegateType;
+ }
+
+ /**
+ * Wraps an {@code observable} in a delegator, returning an {@link IDelegatingObservable} of the appropriate kind.
+ *
+ * @param observable
+ * an observable to wrap in a delegator
+ * @return the delegator, which will be an instance of the {@link IDelegatingObservable} interface
+ *
+ * @throws IllegalArgumentException
+ * if the {@code observable} is of a kind for which no delegator is currently implemented
+ */
+ public static IObservable wrap(IObservable observable) {
+ IObservable result;
+
+ if(Proxy.isProxyClass(observable.getClass()) && (Proxy.getInvocationHandler(observable) instanceof DelegatingInvocationHandler)) {
+ // Already have a delegator and it's a dynamic proxy. Just create another like it
+ try {
+ result = DelegatingInvocationHandler.wrapDynamicProxy(observable);
+ } catch (Exception e) {
+ // Seems unlikely as I must have created the observable in the first place
+ throw new IllegalArgumentException("observable is an invalid implementation of IDelegatingObservable", e); //$NON-NLS-1$
+ }
+ } else if(observable instanceof IObservableList) {
+ result = DelegatingObservableList.wrap((IObservableList)observable);
+ } else if(observable instanceof IObservableSet) {
+ result = DelegatingObservableSet.wrap((IObservableSet)observable);
+ } else if(observable instanceof IObservableValue) {
+ result = DelegatingObservableValue.wrap((IObservableValue)observable);
+ } else {
+ throw new IllegalArgumentException("no delegating wrapper implementation available for observable"); //$NON-NLS-1$
+ }
+
+ return result;
+ }
+
+ /**
+ * Creates a new empty delegator suitable for observables of the specified type without any other mix-in interfaces such as {@link IObserving}.
+ * Observable types must be specified by their abstract interface, and currently the following types are supported:
+ * <ul>
+ * <li>{@link IObservableValue}</li>
+ * <li>{@link IObservableList}</li>
+ * <li>{@link IObservableSet}</li>
+ * </ul>
+ *
+ * @param observableType
+ * the kind of observable that will be the new delegator's delegate
+ * @return the delegator, which will be an instance of the {@link IDelegatingObservable} interface
+ *
+ * @throws IllegalArgumentException
+ * if the {@code observable} is of a kind for which no delegator is currently implemented
+ *
+ * @see #create(Realm, Class, ClassLoader, Class...)
+ */
+ public static <T extends IObservable> T create(Realm realm, Class<T> observableType) {
+ return create(realm, observableType, null); // Class loader not needed without any mix-ins
+ }
+
+ /**
+ * Creates a new empty delegator suitable for observables of the specified type with optional mix-in interfaces such as {@link IObserving},
+ * which is implemented by detail observables in a master/detail relationship. Observable types must be specified
+ * by their abstract interface, and currently the following types are supported:
+ * <ul>
+ * <li>{@link IObservableValue}</li>
+ * <li>{@link IObservableList}</li>
+ * <li>{@link IObservableSet}</li>
+ * </ul>
+ *
+ * @param observableType
+ * the kind of observable that will be the new delegator's delegate
+ * @param loader
+ * a class loader that can see all of the {@code mixins}, if any
+ * @param mixins
+ * optional mix-in interfaces that the resulting observable should refer to its delegate. These must all have
+ * {@linkplain #registerMixinHandler handlers already registered}
+ * @return the delegator, which will be an instance of the {@link IDelegatingObservable} interface
+ *
+ * @throws IllegalArgumentException
+ * if the {@code observable} is of a kind for which no delegator is currently implemented
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends IObservable> T create(Realm realm, Class<T> observableType, ClassLoader loader, Class<?>... mixins) {
+ if(observableType == IObservableList.class) {
+ return (T)DelegatingObservableList.create(realm, loader, mixins);
+ } else if(observableType == IObservableSet.class) {
+ return (T)DelegatingObservableSet.create(realm, loader, mixins);
+ } else if(observableType == IObservableValue.class) {
+ return (T)DelegatingObservableValue.create(realm, loader, mixins);
+ } else {
+ throw new IllegalArgumentException("observableType"); //$NON-NLS-1$
+ }
+ }
+
+ public final void setDelegate(final IObservable delegate) {
+ if(isDisposed()) {
+ throw new IllegalStateException("disposed"); //$NON-NLS-1$
+ }
+
+ final T oldDelegate = this.delegate;
+
+ if(delegate != oldDelegate) {
+ final T newDelegate = (delegate == null) ? null : delegateType.cast(delegate);
+
+ if(oldDelegate != null) {
+ unhookDelegate(oldDelegate);
+
+ // Release it only after this iteration of the event loop so that UI refreshes can still access it for now
+ // in case its retain count will go to zero and it will be disposed
+ ReferenceCountedObservable.Util.autorelease(oldDelegate);
+ }
+
+ this.delegate = newDelegate;
+
+ if(newDelegate != null) {
+ ReferenceCountedObservable.Util.retain(newDelegate);
+ hookDelegate(newDelegate);
+ }
+
+ delegateChanged(oldDelegate, newDelegate);
+ }
+ }
+
+ final void clearDelegate() {
+ // Can do this even if disposed
+
+ if(delegate != null) {
+ unhookDelegate(delegate);
+
+ delegate = null;
+
+ // Let listeners know that we've changed. We cannot fire an accurate value change event
+ // because we can no longer access the old delegate's value, as it is now disposed
+ fireChange();
+ }
+ }
+
+ public final T getDelegate() {
+ return delegate;
+ }
+
+ /**
+ * Notifies of a change from one delegate to another. Subclasses overriding this must call {@code super}.
+ *
+ * @param oldDelegate
+ * the previous delegate, or {@code null} if there was none
+ * @param newDelegate
+ * the new delegate, or {@code null} if now I have none
+ */
+ protected void delegateChanged(T oldDelegate, T newDelegate) {
+ fireChange();
+ }
+
+ protected void hookDelegate(T delegate) {
+ delegate.addChangeListener(getForwardingChangeListener());
+ delegate.addStaleListener(getForwardingStaleListener());
+
+ // Don't forward dispose events because the delegate has its own lifecycle. However, when our delegate
+ // is disposed, we forget about it
+ delegate.addDisposeListener(getDelegateDisposeListener());
+ }
+
+ protected void unhookDelegate(T delegate) {
+ delegate.removeChangeListener(getForwardingChangeListener());
+ delegate.removeStaleListener(getForwardingStaleListener());
+ delegate.removeDisposeListener(getDelegateDisposeListener());
+ }
+
+ public boolean isStale() {
+ getterCalled();
+
+ return (delegate != null) && delegate.isStale();
+ }
+
+ protected void getterCalled() {
+ ObservableTracker.getterCalled(getRealObservable());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return (obj == this) || ((delegate == null) ? false : delegate.equals(obj));
+ }
+
+ @Override
+ public int hashCode() {
+ return (delegate == null) ? 0 : delegate.hashCode();
+ }
+
+ /**
+ * Sets the real observable (which may be a dynamic proxy) to report as the source of events and the target of getter calls in the
+ * {@link ObservableTracker}.
+ *
+ * @param realObservable
+ * my event source
+ */
+ final void setRealObservable(T realObservable) {
+ this.realObservable = realObservable;
+ }
+
+ /**
+ * Gets the source to report for events (which may be a dynamic proxy).
+ *
+ * @return my event source
+ */
+ final T getRealObservable() {
+ return realObservable;
+ }
+
+ @Override
+ protected final void fireChange() {
+ fireEvent(new ChangeEvent(getRealObservable()));
+ }
+
+ @Override
+ protected final void fireStale() {
+ fireEvent(new StaleEvent(getRealObservable()));
+ }
+
+ public void dispose() {
+ if(!isDisposed()) {
+ if(delegate != null) {
+ unhookDelegate(delegate);
+
+ // Release it only after this iteration of the event loop so that UI refreshes can still access it for now
+ // in case its retain count will go to zero and it will be disposed
+ ReferenceCountedObservable.Util.autorelease(delegate);
+ delegate = null;
+ }
+ super.dispose();
+ }
+ }
+
+ @Override
+ protected void fireEvent(ObservableEvent event) {
+ // ensure the correct source for events fired by the superclass
+ if((event instanceof DisposeEvent) && (event.getSource() != getRealObservable())) {
+ event = new DisposeEvent(getRealObservable());
+ }
+
+ super.fireEvent(event);
+ }
+
+ private IChangeListener getForwardingChangeListener() {
+ if(forwardingChangeListener == null) {
+ forwardingChangeListener = new IChangeListener() {
+
+ public void handleChange(ChangeEvent event) {
+ DelegatingObservable.this.fireChange();
+ }
+ };
+ }
+
+ return forwardingChangeListener;
+ }
+
+ private IStaleListener getForwardingStaleListener() {
+ if(forwardingStaleListener == null) {
+ forwardingStaleListener = new IStaleListener() {
+
+ public void handleStale(StaleEvent staleEvent) {
+ DelegatingObservable.this.fireStale();
+ }
+ };
+ }
+
+ return forwardingStaleListener;
+ }
+
+ private IDisposeListener getDelegateDisposeListener() {
+ if(delegateDisposeListener == null) {
+ delegateDisposeListener = new IDisposeListener() {
+
+ public void handleDispose(DisposeEvent event) {
+ if(event.getObservable() == getDelegate()) {
+ clearDelegate();
+ }
+ }
+ };
+ }
+
+ return delegateDisposeListener;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableCollection.java b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableCollection.java
new file mode 100644
index 00000000000..f4597404f19
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableCollection.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.tools.databinding;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+
+import org.eclipse.core.databinding.observable.IObservableCollection;
+import org.eclipse.core.databinding.observable.Realm;
+
+
+/**
+ * This is the DelegatingObservableCollection type. Enjoy.
+ */
+public abstract class DelegatingObservableCollection<T extends IObservableCollection> extends DelegatingObservable<T> implements IObservableCollection {
+
+ private static final Object[] EMPTY_ARRAY = {};
+
+ DelegatingObservableCollection(T delegate, Class<T> delegateType) {
+ super(delegate, delegateType);
+ }
+
+ DelegatingObservableCollection(Realm realm, Class<T> delegateType) {
+ super(realm, delegateType);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ getterCalled();
+
+ return super.equals(obj);
+ }
+
+ @Override
+ public int hashCode() {
+ getterCalled();
+
+ return super.hashCode();
+ }
+
+ public int size() {
+ getterCalled();
+
+ return (getDelegate() == null) ? 0 : getDelegate().size();
+ }
+
+ public boolean isEmpty() {
+ getterCalled();
+
+ return (getDelegate() == null) ? true : getDelegate().isEmpty();
+ }
+
+ public boolean contains(Object o) {
+ getterCalled();
+
+ return (getDelegate() == null) ? false : getDelegate().contains(o);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public Iterator iterator() {
+ getterCalled();
+
+ return (getDelegate() == null) ? Collections.EMPTY_LIST.iterator() : getDelegate().iterator();
+ }
+
+ public Object[] toArray() {
+ getterCalled();
+
+ return (getDelegate() == null) ? EMPTY_ARRAY : getDelegate().toArray();
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object[] toArray(Object[] a) {
+ getterCalled();
+
+ return (getDelegate() == null) ? Collections.EMPTY_LIST.toArray(a) : getDelegate().toArray(a);
+ }
+
+ @SuppressWarnings("unchecked")
+ public boolean add(Object e) {
+ return (getDelegate() == null) ? false : getDelegate().add(e);
+ }
+
+ public boolean remove(Object o) {
+ return (getDelegate() == null) ? false : getDelegate().remove(o);
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public boolean containsAll(Collection c) {
+ getterCalled();
+
+ return (getDelegate() == null) ? false : getDelegate().containsAll(c);
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public boolean addAll(Collection c) {
+ return (getDelegate() == null) ? false : getDelegate().addAll(c);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public boolean removeAll(Collection c) {
+ return (getDelegate() == null) ? false : getDelegate().removeAll(c);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public boolean retainAll(Collection c) {
+ return (getDelegate() == null) ? false : getDelegate().retainAll(c);
+ }
+
+ public void clear() {
+ if(getDelegate() != null) {
+ getDelegate().clear();
+ }
+ }
+
+ public Object getElementType() {
+ return (getDelegate() == null) ? null : getDelegate().getElementType();
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableList.java b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableList.java
new file mode 100644
index 00000000000..2c7e7807aaa
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableList.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.tools.databinding;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.eclipse.core.databinding.observable.Diffs;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.IListChangeListener;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.core.databinding.observable.list.ListChangeEvent;
+import org.eclipse.core.databinding.observable.list.ListDiff;
+
+
+/**
+ * This is the DelegatingObservableList type. Enjoy.
+ */
+public class DelegatingObservableList extends DelegatingObservableCollection<IObservableList> implements IObservableList {
+
+ private static final Object LIST_EVENT_TYPE = new Object();
+
+ private IListChangeListener forwardingListChangeListener;
+
+ DelegatingObservableList(IObservableList delegate) {
+ super(delegate, IObservableList.class);
+ }
+
+ DelegatingObservableList(Realm realm) {
+ super(realm, IObservableList.class);
+ }
+
+ public static IObservableList wrap(IObservableList observable) {
+ IObservableList result;
+
+ if(observable instanceof IDelegatingObservable) {
+ // Already have a delegator. Just create another like it
+ try {
+ result = (IObservableList)observable.getClass().getDeclaredConstructor(IObservableList.class).newInstance(observable);
+ } catch (Exception e) {
+ // Seems unlikely as I must have created the observable in the first place
+ throw new IllegalArgumentException("observable is an invalid implementation of IDelegatingObservable", e); //$NON-NLS-1$
+ }
+ } else {
+ result = DelegatingInvocationHandler.wrap(new DelegatingObservableList(observable), IObservableList.class);
+ }
+
+ return result;
+ }
+
+ public static IObservableList create(Realm realm, ClassLoader loader, Class<?>... mixins) {
+ return DelegatingInvocationHandler.wrap(new DelegatingObservableList(realm), IObservableList.class, loader, mixins);
+ }
+
+ public void addListChangeListener(IListChangeListener listener) {
+ addListener(LIST_EVENT_TYPE, listener);
+ }
+
+ public void removeListChangeListener(IListChangeListener listener) {
+ removeListener(LIST_EVENT_TYPE, listener);
+ }
+
+ @Override
+ protected void hookDelegate(IObservableList delegate) {
+ super.hookDelegate(delegate);
+ delegate.addListChangeListener(getForwardingListChangeListener());
+ }
+
+ @Override
+ protected void unhookDelegate(IObservableList delegate) {
+ delegate.removeListChangeListener(getForwardingListChangeListener());
+ super.unhookDelegate(delegate);
+ }
+
+ @Override
+ protected void delegateChanged(IObservableList oldDelegate, IObservableList newDelegate) {
+ super.delegateChanged(oldDelegate, newDelegate);
+
+ List<?> oldList = ((oldDelegate == null) || oldDelegate.isDisposed()) ? Collections.EMPTY_LIST : oldDelegate;
+ List<?> newList = (newDelegate == null) ? Collections.EMPTY_LIST : newDelegate;
+
+ fireEvent(new MyListChangeEvent(Diffs.computeListDiff(oldList, newList)));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void add(int index, Object element) {
+ if(getDelegate() == null) {
+ throw new IndexOutOfBoundsException();
+ }
+ getDelegate().add(index, element);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public boolean addAll(int index, Collection c) {
+ if(getDelegate() == null) {
+ throw new IndexOutOfBoundsException();
+ }
+ return getDelegate().addAll(index, c);
+ }
+
+ public Object get(int index) {
+ getterCalled();
+
+ if(getDelegate() == null) {
+ throw new IndexOutOfBoundsException();
+ }
+ return getDelegate().get(index);
+ }
+
+ public Object set(int index, Object element) {
+ if(getDelegate() == null) {
+ throw new IndexOutOfBoundsException();
+ }
+ return getDelegate().set(index, element);
+ }
+
+ public Object move(int oldIndex, int newIndex) {
+ if(getDelegate() == null) {
+ throw new IndexOutOfBoundsException();
+ }
+ return getDelegate().move(oldIndex, newIndex);
+ }
+
+ public Object remove(int index) {
+ return (getDelegate() == null) ? Collections.EMPTY_LIST.remove(index) : getDelegate().remove(index);
+ }
+
+ public int indexOf(Object o) {
+ getterCalled();
+
+ return (getDelegate() == null) ? -1 : getDelegate().indexOf(o);
+ }
+
+ public int lastIndexOf(Object o) {
+ getterCalled();
+
+ return (getDelegate() == null) ? -1 : getDelegate().lastIndexOf(o);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public ListIterator listIterator() {
+ getterCalled();
+
+ return (getDelegate() == null) ? Collections.EMPTY_LIST.listIterator() : getDelegate().listIterator();
+ }
+
+ @SuppressWarnings("rawtypes")
+ public ListIterator listIterator(int index) {
+ getterCalled();
+
+ return (getDelegate() == null) ? Collections.EMPTY_LIST.listIterator(index) : getDelegate().listIterator(index);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public List subList(int fromIndex, int toIndex) {
+ getterCalled();
+
+ return (getDelegate() == null) ? Collections.EMPTY_LIST.subList(fromIndex, toIndex) : getDelegate().subList(fromIndex, toIndex);
+ }
+
+ private IListChangeListener getForwardingListChangeListener() {
+ if(forwardingListChangeListener == null) {
+ forwardingListChangeListener = new IListChangeListener() {
+
+ public void handleListChange(ListChangeEvent event) {
+ ListChangeEvent myEvent = new MyListChangeEvent(event.diff);
+ fireEvent(myEvent);
+ }
+ };
+ }
+
+ return forwardingListChangeListener;
+ }
+
+ //
+ // Nested types
+ //
+
+ class MyListChangeEvent extends ListChangeEvent {
+
+ private static final long serialVersionUID = 1L;
+
+ MyListChangeEvent(ListDiff diff) {
+ super(getRealObservable(), diff);
+ }
+
+ @Override
+ protected Object getListenerType() {
+ // We implement our own listener type because the type from the core framework is not accessible
+ return LIST_EVENT_TYPE;
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableSet.java b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableSet.java
new file mode 100644
index 00000000000..4111577f027
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableSet.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.tools.databinding;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.eclipse.core.databinding.observable.Diffs;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.set.IObservableSet;
+import org.eclipse.core.databinding.observable.set.ISetChangeListener;
+import org.eclipse.core.databinding.observable.set.SetChangeEvent;
+import org.eclipse.core.databinding.observable.set.SetDiff;
+
+
+/**
+ * This is the DelegatingObservableSet type. Enjoy.
+ */
+public class DelegatingObservableSet extends DelegatingObservableCollection<IObservableSet> implements IObservableSet {
+
+ private static final Object SET_EVENT_TYPE = new Object();
+
+ private ISetChangeListener forwardingSetChangeListener;
+
+ DelegatingObservableSet(IObservableSet delegate) {
+ super(delegate, IObservableSet.class);
+ }
+
+ DelegatingObservableSet(Realm realm) {
+ super(realm, IObservableSet.class);
+ }
+
+ public static IObservableSet wrap(IObservableSet observable) {
+ IObservableSet result;
+
+ if(observable instanceof IDelegatingObservable) {
+ // Already have a delegator. Just create another like it
+ try {
+ result = (IObservableSet)observable.getClass().getDeclaredConstructor(IObservableSet.class).newInstance(observable);
+ } catch (Exception e) {
+ // Seems unlikely as I must have created the observable in the first place
+ throw new IllegalArgumentException("observable is an invalid implementation of IDelegatingObservable", e); //$NON-NLS-1$
+ }
+ } else {
+ result = DelegatingInvocationHandler.wrap(new DelegatingObservableSet(observable), IObservableSet.class);
+ }
+
+ return result;
+ }
+
+ public static IObservableSet create(Realm realm, ClassLoader loader, Class<?>... mixins) {
+ return DelegatingInvocationHandler.wrap(new DelegatingObservableSet(realm), IObservableSet.class, loader, mixins);
+ }
+
+ public void addSetChangeListener(ISetChangeListener listener) {
+ addListener(SET_EVENT_TYPE, listener);
+ }
+
+ public void removeSetChangeListener(ISetChangeListener listener) {
+ removeListener(SET_EVENT_TYPE, listener);
+ }
+
+ @Override
+ protected void hookDelegate(IObservableSet delegate) {
+ super.hookDelegate(delegate);
+ delegate.addSetChangeListener(getForwardingSetChangeListener());
+ }
+
+ @Override
+ protected void unhookDelegate(IObservableSet delegate) {
+ delegate.removeSetChangeListener(getForwardingSetChangeListener());
+ super.unhookDelegate(delegate);
+ }
+
+ @Override
+ protected void delegateChanged(IObservableSet oldDelegate, IObservableSet newDelegate) {
+ super.delegateChanged(oldDelegate, newDelegate);
+
+ Set<?> oldSet = ((oldDelegate == null) || oldDelegate.isDisposed()) ? Collections.EMPTY_SET : oldDelegate;
+ Set<?> newSet = (newDelegate == null) ? Collections.EMPTY_SET : newDelegate;
+
+ fireEvent(new MySetChangeEvent(Diffs.computeSetDiff(oldSet, newSet)));
+ }
+
+ private ISetChangeListener getForwardingSetChangeListener() {
+ if(forwardingSetChangeListener == null) {
+ forwardingSetChangeListener = new ISetChangeListener() {
+
+ public void handleSetChange(SetChangeEvent event) {
+ SetChangeEvent myEvent = new MySetChangeEvent(event.diff);
+ fireEvent(myEvent);
+ }
+ };
+ }
+
+ return forwardingSetChangeListener;
+ }
+
+ //
+ // Nested types
+ //
+
+ class MySetChangeEvent extends SetChangeEvent {
+
+ private static final long serialVersionUID = 1L;
+
+ MySetChangeEvent(SetDiff diff) {
+ super(getRealObservable(), diff);
+ }
+
+ @Override
+ protected Object getListenerType() {
+ // We implement our own listener type because the type from the core framework is not accessible
+ return SET_EVENT_TYPE;
+ }
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableValue.java b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableValue.java
new file mode 100644
index 00000000000..6c75786a1aa
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/DelegatingObservableValue.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.tools.databinding;
+
+import org.eclipse.core.databinding.observable.Diffs;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.observable.value.IValueChangeListener;
+import org.eclipse.core.databinding.observable.value.ValueChangeEvent;
+import org.eclipse.core.databinding.observable.value.ValueDiff;
+
+
+/**
+ * This is the DelegatingObservableValue type. Enjoy.
+ */
+public class DelegatingObservableValue extends DelegatingObservable<IObservableValue> implements IObservableValue {
+
+ private static final Object VALUE_EVENT_TYPE = new Object();
+
+ private IValueChangeListener forwardingValueChangeListener;
+
+ DelegatingObservableValue(IObservableValue delegate) {
+ super(delegate, IObservableValue.class);
+ }
+
+ DelegatingObservableValue(Realm realm) {
+ super(realm, IObservableValue.class);
+ }
+
+ public static IObservableValue wrap(IObservableValue observable) {
+ IObservableValue result;
+
+ if(observable instanceof IDelegatingObservable) {
+ // Already have a delegator. Just create another like it
+ try {
+ result = (IObservableValue)observable.getClass().getDeclaredConstructor(IObservableValue.class).newInstance(observable);
+ } catch (Exception e) {
+ // Seems unlikely as I must have created the observable in the first place
+ throw new IllegalArgumentException("observable is an invalid implementation of IDelegatingObservable", e); //$NON-NLS-1$
+ }
+ } else {
+ result = DelegatingInvocationHandler.wrap(new DelegatingObservableValue(observable), IObservableValue.class);
+ }
+
+ return result;
+ }
+
+ public static IObservableValue create(Realm realm, ClassLoader loader, Class<?>... mixins) {
+ return DelegatingInvocationHandler.wrap(new DelegatingObservableValue(realm), IObservableValue.class, loader, mixins);
+ }
+
+ public void addValueChangeListener(IValueChangeListener listener) {
+ addListener(VALUE_EVENT_TYPE, listener);
+ }
+
+ public void removeValueChangeListener(IValueChangeListener listener) {
+ removeListener(VALUE_EVENT_TYPE, listener);
+ }
+
+ @Override
+ protected void hookDelegate(IObservableValue delegate) {
+ super.hookDelegate(delegate);
+ delegate.addValueChangeListener(getForwardingValueChangeListener());
+ }
+
+ @Override
+ protected void unhookDelegate(IObservableValue delegate) {
+ delegate.removeValueChangeListener(getForwardingValueChangeListener());
+ super.unhookDelegate(delegate);
+ }
+
+ @Override
+ protected void delegateChanged(IObservableValue oldDelegate, IObservableValue newDelegate) {
+ super.delegateChanged(oldDelegate, newDelegate);
+
+ Object oldValue = ((oldDelegate == null) || oldDelegate.isDisposed()) ? null : oldDelegate.getValue();
+ Object newValue = (newDelegate == null) ? null : newDelegate.getValue();
+
+ fireEvent(new MyValueChangeEvent(Diffs.createValueDiff(oldValue, newValue)));
+ }
+
+ public Object getValueType() {
+ return (getDelegate() == null) ? Void.class : getDelegate().getValueType();
+ }
+
+ public Object getValue() {
+ getterCalled();
+
+ return (getDelegate() == null) ? null : getDelegate().getValue();
+ }
+
+ public void setValue(Object value) {
+ if(getDelegate() != null) {
+ getDelegate().setValue(value);
+ }
+ }
+
+ private IValueChangeListener getForwardingValueChangeListener() {
+ if(forwardingValueChangeListener == null) {
+ forwardingValueChangeListener = new IValueChangeListener() {
+
+ public void handleValueChange(ValueChangeEvent event) {
+ ValueChangeEvent myEvent = new MyValueChangeEvent(event.diff);
+ fireEvent(myEvent);
+ }
+ };
+ }
+
+ return forwardingValueChangeListener;
+ }
+
+ //
+ // Nested types
+ //
+
+ class MyValueChangeEvent extends ValueChangeEvent {
+
+ private static final long serialVersionUID = 1L;
+
+ MyValueChangeEvent(ValueDiff diff) {
+ super(getRealObservable(), diff);
+ }
+
+ @Override
+ protected Object getListenerType() {
+ // We implement our own listener type because the type from the core framework is not accessible
+ return VALUE_EVENT_TYPE;
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/IDelegatingObservable.java b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/IDelegatingObservable.java
new file mode 100644
index 00000000000..2fa0e07bc86
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/IDelegatingObservable.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.tools.databinding;
+
+import org.eclipse.core.databinding.observable.IObservable;
+
+
+
+/**
+ * <p>
+ * An {@linkplain IObservable observable} that delegates its function (including notification of state changes) to a wrapped instance. The delegate
+ * may be {@linkplain #setDelegate(IObservable) replaced} at any time. Thus, the lifecycle of a delegator is independent of its delegate and
+ * {@link #dispose() disposing} a delegator only disposes it, not its delegate if it has one at the time.
+ * </p>
+ * <p>
+ * Delegating observables may be created via factory methods provided by the {@link DelegatingObservable} class.
+ * </p>
+ *
+ * @see DelegatingObservable
+ */
+public interface IDelegatingObservable extends IObservable, ReferenceCountedObservable {
+
+ /**
+ * Assigns me a new delegate, or at least forgets my delegate if {@code null}.
+ *
+ * @param delegate
+ * my delegate (may be {@code null})
+ */
+ void setDelegate(IObservable delegate);
+
+ /**
+ * Obtains my current delegate, if any.
+ *
+ * @return my delegate, or {@code null} if I have none
+ */
+ IObservable getDelegate();
+
+ /**
+ * Disposes of me and my own resources only. In particular, if I have a {@linkplain #getDelegate() delegate}, it is <em>not</em> disposed, but
+ * must be disposed independently.
+ */
+ void dispose();
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/MultipleObservableValue.java b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/MultipleObservableValue.java
index bd8dadf1e11..a326d80dab1 100644
--- a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/MultipleObservableValue.java
+++ b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/MultipleObservableValue.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 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
@@ -8,6 +8,8 @@
*
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 417409
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.tools.databinding;
@@ -18,7 +20,6 @@ import java.util.List;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.IObservable;
-import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.ValueDiff;
@@ -32,7 +33,7 @@ import org.eclipse.core.databinding.observable.value.ValueDiff;
* All sub-elements will be edited at the same time, with the same value.
*/
//TODO : Add listeners on sub-observables, and remove them on dispose
-public class MultipleObservableValue extends AbstractObservableValue implements AggregatedObservable, IChangeListener {
+public class MultipleObservableValue extends ReferenceCountedObservable.Value implements AggregatedObservable, IChangeListener {
/**
*
@@ -98,6 +99,7 @@ public class MultipleObservableValue extends AbstractObservableValue implements
public AggregatedObservable aggregate(IObservable observable) {
if(observable instanceof IObservableValue) {
+ ReferenceCountedObservable.Util.retain(observable);
observableValues.add((IObservableValue)observable);
observable.addChangeListener(this);
return this;
@@ -128,8 +130,12 @@ public class MultipleObservableValue extends AbstractObservableValue implements
super.dispose();
for(IObservableValue observable : observableValues) {
observable.removeChangeListener(this);
- observable.dispose();
+
+ // I don't own my observables, so I just release them
+ ReferenceCountedObservable.Util.release(observable);
}
+
+ observableValues.clear();
}
/**
diff --git a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/ReferenceCountedObservable.java b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/ReferenceCountedObservable.java
new file mode 100644
index 00000000000..41a9ebf5ee9
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/databinding/ReferenceCountedObservable.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.tools.databinding;
+
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.core.databinding.observable.AbstractObservable;
+import org.eclipse.core.databinding.observable.DisposeEvent;
+import org.eclipse.core.databinding.observable.IDisposeListener;
+import org.eclipse.core.databinding.observable.IObservable;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.MapMaker;
+
+
+
+/**
+ * A mix-in interface for {@link IObservable}s that support reference counting as a means to automatically dispose of them while ensuring that
+ * they may be freely shared without any client finding itself interacting with a disposed observable.
+ */
+public interface ReferenceCountedObservable extends IObservable {
+
+ /**
+ * Retains me for use by the caller, which should be sure to {@linkplain #release() release me} when I am no longer needed.
+ * As long as I have been retained by at least one client, I shall not {@linkplain IObservable#dispose() dispose} myself.
+ *
+ * @see #release()
+ */
+ void retain();
+
+ /**
+ * Releases me, indicating that I am no longer being used by the caller. When my {@linkplain #retain() retain count} reaches zero,
+ * I automatically {@linkplain IObservable#dispose() dispose} myself, because no client needs me.
+ *
+ * @see #retain()
+ * @see #autorelease()
+ * @see IObservable#dispose()
+ */
+ void release();
+
+ /**
+ * Automatically releases me some time after the current iteration of the UI event loop. This is useful when it is
+ * expected that the UI will still need to be able to access the observable for refreshes while processing the
+ * current event.
+ *
+ * @see #release()
+ */
+ void autorelease();
+
+ /**
+ * A composable assistant to implement the {@link ReferenceCountedObservable} protocol by delegating of its API.
+ */
+ class Support {
+
+ private final IObservable observable;
+
+ private final AtomicInteger refCount = new AtomicInteger();
+
+ /**
+ * Creates a new instance to support reference counting on behalf of an {@code observable}.
+ *
+ * @param observable
+ * the observable for which to provide reference counting
+ */
+ public Support(IObservable observable) {
+ this.observable = observable;
+ }
+
+ public void retain() {
+ refCount.incrementAndGet();
+ }
+
+ public void release() {
+ if((refCount.decrementAndGet() <= 0) && !observable.isDisposed()) {
+ observable.dispose();
+ }
+ }
+
+ public void autorelease() {
+ AutoReleasePool.get(observable.getRealm()).add(observable);
+ }
+ }
+
+ /**
+ * A convenient superclass for reference-counted observables that don't need any other more specific superclass.
+ */
+ abstract class Abstract extends AbstractObservable implements ReferenceCountedObservable {
+
+ private final Support refCount = new Support(this);
+
+ public Abstract(Realm realm) {
+ super(realm);
+ }
+
+ public void retain() {
+ refCount.retain();
+ }
+
+ public void release() {
+ refCount.release();
+ }
+
+ public void autorelease() {
+ refCount.autorelease();
+ }
+ }
+
+ /**
+ * A convenient superclass for reference-counted observable values that don't need any other more specific superclass.
+ */
+ abstract class Value extends AbstractObservableValue implements ReferenceCountedObservable {
+
+ private final Support refCount = new Support(this);
+
+ public Value() {
+ super();
+ }
+
+ public Value(Realm realm) {
+ super(realm);
+ }
+
+ public void retain() {
+ refCount.retain();
+ }
+
+ public void release() {
+ refCount.release();
+ }
+
+ public void autorelease() {
+ refCount.autorelease();
+ }
+ }
+
+ /**
+ * A pool of {@link IObservable}s to be released automatically after the completion of the current iteration
+ * of the UI event loop (or whatever determines the asynchronous execution of tasks in a given {@link Realm}).
+ */
+ final class AutoReleasePool {
+
+ private static final ConcurrentMap<Realm, AutoReleasePool> pools = new MapMaker().concurrencyLevel(1).makeMap();
+
+ private final Realm realm;
+
+ private Collection<IObservable> pool = Lists.newArrayList();
+
+ private AutoReleasePool(Realm realm) {
+ this.realm = realm;
+
+ realm.asyncExec(new ReleaseRunnable());
+ }
+
+ public static AutoReleasePool get(Realm realm) {
+ AutoReleasePool result = pools.get(realm);
+ if(result == null) {
+ result = new AutoReleasePool(realm);
+
+ // Double-check
+ AutoReleasePool oops = pools.putIfAbsent(realm, result);
+ if(oops != null) {
+ result = oops;
+ }
+ }
+
+ return result;
+ }
+
+ public synchronized void add(IObservable observable) {
+ if(pool == null) {
+ pool = Lists.newArrayList();
+ }
+
+ pool.add(observable);
+ }
+
+ public void release() {
+ pools.remove(realm);
+
+ for(;;) {
+ Iterable<IObservable> toDrain;
+
+ synchronized(this) {
+ toDrain = pool;
+ pool = null;
+ }
+
+ if(toDrain != null) {
+ // Drain this pool
+ for(IObservable next : toDrain) {
+ Util.release(next);
+ }
+ } else {
+ // Done. No more pools to drain
+ break;
+ }
+ }
+ }
+
+ private final class ReleaseRunnable implements Runnable {
+
+ public void run() {
+ release();
+ }
+ }
+ }
+
+ /**
+ * Utility APIs for working with reference-counted observables. In particular, this provides external reference-counting
+ * for observables that don't implement it internally via the {@link ReferenceCountedObservable} protocol.
+ */
+ final class Util {
+
+ // Use the Guava weak map because that uses object identity for comparisons, which is critical
+ // to avoid using equals() which will often fail on an assertion violation for accessing a
+ // getter of a disposed observable
+ private static final Map<IObservable, WeakRefCount> adapters = new MapMaker().concurrencyLevel(1).weakKeys().makeMap();
+
+ private Util() {
+ super();
+ }
+
+ /**
+ * Provides a unified interface to retaining observables, delegating to the {@link ReferenceCountedObservable} protocol
+ * for observables that implement it, otherwise providing an external reference-count (which is GC-safe).
+ *
+ * @param observable
+ * an observable to retain
+ *
+ * @return the same {@code observable} (useful for call chaining)
+ *
+ * @see ReferenceCountedObservable#retain()
+ */
+ public static <T extends IObservable> T retain(T observable) {
+ if(observable instanceof ReferenceCountedObservable) {
+ ((ReferenceCountedObservable)observable).retain();
+ } else if(!observable.isDisposed()) { // Don't bother counting if already disposed
+ WeakRefCount adapter = adapt(observable, true);
+ adapter.retain();
+ }
+
+ return observable;
+ }
+
+ /**
+ * Provides a unified interface to releasing observables, delegating to the {@link ReferenceCountedObservable} protocol
+ * for observables that implement it, otherwise providing an external reference-count (which is GC-safe). Note that
+ * for externally reference-counted observables, they are automatically disposed as usual when the retain count drops
+ * to zero, just as though they implemented reference counting internally.
+ *
+ * @param observable
+ * an observable to release. If its retain count is zero as a result (whether intrinsic or extrinsic), it will be disposed
+ *
+ * @return the same {@code observable} (useful for call chaining)
+ *
+ * @see ReferenceCountedObservable#release()
+ */
+ public static <T extends IObservable> T release(T observable) {
+ if(observable instanceof ReferenceCountedObservable) {
+ ((ReferenceCountedObservable)observable).release();
+ } else if(!observable.isDisposed()) { // Don't bother counting if already disposed
+ WeakRefCount adapter = adapt(observable, false);
+
+ // There won't be an adapter if there was no prior retain (of course) or if it was already disposed
+ if(adapter != null) {
+ adapter.release();
+ }
+ }
+
+ return observable;
+ }
+
+ /**
+ * Provides a unified interface to auto-releasing observables, delegating to the {@link ReferenceCountedObservable} protocol
+ * for observables that implement it, otherwise providing an external reference-count (which is GC-safe). Note that
+ * for externally reference-counted observables, they are automatically disposed as usual when the retain count drops
+ * to zero, just as though they implemented reference counting internally.
+ *
+ * @param observable
+ * an observable to release. If its retain count is zero as a result (whether intrinsic or extrinsic), it will be disposed
+ *
+ * @return the same {@code observable} (useful for call chaining)
+ *
+ * @see ReferenceCountedObservable#autorelease()
+ */
+ public static <T extends IObservable> T autorelease(T observable) {
+ if(observable instanceof ReferenceCountedObservable) {
+ ((ReferenceCountedObservable)observable).autorelease();
+ } else if(!observable.isDisposed()) { // Don't bother counting if already disposed
+ WeakRefCount adapter = adapt(observable, false);
+
+ // There won't be an adapter if there was no prior retain (of course) or if it was already disposed
+ if(adapter != null) {
+ adapter.autorelease();
+ }
+ }
+
+ return observable;
+ }
+
+ private static WeakRefCount adapt(IObservable observable, boolean create) {
+ WeakRefCount result = adapters.get(observable);
+
+ if((result == null) && create) {
+ result = new WeakRefCount(observable);
+ adapters.put(observable, result);
+ }
+
+ return result;
+ }
+
+ private static final class WeakRefCount extends WeakReference<IObservable> implements IDisposeListener {
+
+ private final AtomicInteger refCount = new AtomicInteger();
+
+ WeakRefCount(IObservable observable) {
+ super(observable);
+
+ observable.addDisposeListener(this);
+ }
+
+ public void retain() {
+ refCount.incrementAndGet();
+ }
+
+ public void release() {
+ if(refCount.decrementAndGet() <= 0) {
+ IObservable observable = get();
+
+ if(observable != null) {
+ if(!observable.isDisposed()) {
+ observable.dispose();
+ }
+
+ clear();
+ }
+ }
+ }
+
+ public void autorelease() {
+ IObservable observable = get();
+
+ // If it's null, then it's already disposed, so auto-release is meaningless
+ if(observable != null) {
+ AutoReleasePool.get(observable.getRealm()).add(observable);
+ }
+ }
+
+ public void handleDispose(DisposeEvent event) {
+ if(event.getObservable() == get()) {
+ clear();
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractValueEditor.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractValueEditor.java
index f99ed5ba9a9..f7249f3146c 100644
--- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractValueEditor.java
+++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractValueEditor.java
@@ -11,6 +11,7 @@
* Thibault Le Ouay t.leouay@sherpa-eng.com - Add binding implementation
* Christian W. Damus (CEA) - bug 402525
* Mickaƫl ADAM (ALL4TEC) mickael.adam@all4tec.net - bug 435415
+ * Christian W. Damus (CEA) - bug 417409
*
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.editors;
@@ -217,13 +218,19 @@ public abstract class AbstractValueEditor extends AbstractEditor {
@Override
public void handleValueChange(ValueChangeEvent event) {
- //Check if the widget is disposed before isReadOnly() to avoid NPE
- if(!AbstractValueEditor.this.isDisposed() && !isReadOnly()) { //Bug 434787 : Shouldn't not execute the timer thread if the widget is disposed
- IStatus status = (IStatus)binding.getValidationStatus().getValue(); //Bug 435415 : Update the status only if the widget isn't disposed
- updateStatus(status);
- changeColorField();
+ // Don't handle validation changes if we don't have a validator, because then it could only be green and it isn't useful.
+ // Also, if we're showing in a dialog, then our widget may have been disposed already if we're validating a change applied
+ // by hitting the OK button
+ if((modelValidator) != null) {
+ //Check if the widget is disposed before isReadOnly() to avoid NPE
+ if(!AbstractValueEditor.this.isDisposed() && !isReadOnly()) { //Bug 434787 : Shouldn't not execute the timer thread if the widget is disposed
+ IStatus status = (IStatus)binding.getValidationStatus().getValue(); //Bug 435415 : Update the status only if the widget isn't disposed
+ updateStatus(status);
+ changeColorField();
+ }
}
}
+
});
}
@@ -248,11 +255,9 @@ public abstract class AbstractValueEditor extends AbstractEditor {
* @param modelValidator
*/
public void setModelValidator(IValidator targetToModelValidator) {
- if(targetToModelValidator != null) {
this.modelValidator = targetToModelValidator;
targetToModelStrategy.setBeforeSetValidator(targetToModelValidator);
modelToTargetStrategy.setAfterGetValidator(targetToModelValidator);
- }
}
/**

Back to the top