| /******************************************************************************* |
| * Copyright (c) 2016 BestSolution.at 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: |
| * Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.fx.emf.databinding.internal; |
| |
| import java.lang.ref.WeakReference; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.eclipse.emf.common.command.Command; |
| import org.eclipse.emf.common.notify.Adapter; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.notify.Notifier; |
| import org.eclipse.emf.common.notify.impl.AdapterImpl; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.edit.command.SetCommand; |
| import org.eclipse.emf.edit.domain.EditingDomain; |
| import org.eclipse.fx.emf.databinding.EFXObject; |
| import org.eclipse.fx.emf.databinding.EProperty; |
| import org.eclipse.jdt.annotation.NonNull; |
| |
| import javafx.beans.property.BooleanProperty; |
| import javafx.beans.property.DoubleProperty; |
| import javafx.beans.property.FloatProperty; |
| import javafx.beans.property.IntegerProperty; |
| import javafx.beans.property.LongProperty; |
| import javafx.beans.property.ObjectProperty; |
| import javafx.beans.property.Property; |
| import javafx.beans.property.SimpleBooleanProperty; |
| import javafx.beans.property.SimpleDoubleProperty; |
| import javafx.beans.property.SimpleFloatProperty; |
| import javafx.beans.property.SimpleIntegerProperty; |
| import javafx.beans.property.SimpleLongProperty; |
| import javafx.beans.property.SimpleObjectProperty; |
| import javafx.beans.property.SimpleStringProperty; |
| import javafx.beans.property.StringProperty; |
| |
| |
| @SuppressWarnings("javadoc") |
| public class AdaptedEObject<@NonNull O extends EObject> implements EFXObject<O> { |
| final Map<EStructuralFeature, Property<?>> map = new HashMap<>(); |
| final O eo; |
| private final EditingDomain ed; |
| private Adapter adapter; |
| |
| public AdaptedEObject(EditingDomain ed, O eo) { |
| this.eo = eo; |
| this.ed = ed; |
| this.adapter = new MyInnerAdapter(this); |
| this.eo.eAdapters().add(this.adapter); |
| } |
| |
| static class MyInnerAdapter extends AdapterImpl { |
| private WeakReference<AdaptedEObject<?>> eo; |
| |
| public MyInnerAdapter(AdaptedEObject<?> eo) { |
| this.eo = new WeakReference<AdaptedEObject<?>>(eo); |
| } |
| |
| @Override |
| public void notifyChanged(Notification msg) { |
| super.notifyChanged(msg); |
| AdaptedEObject<?> eo = this.eo.get(); |
| if( eo == null ) { |
| if( msg.getEventType() != Notification.REMOVING_ADAPTER ) { |
| ((EObject)msg.getNotifier()).eAdapters().remove(this); |
| } |
| } else { |
| Property<Object> property = (Property<Object>) eo.map.get(msg.getFeature()); |
| if( property != null && ! property.isBound() ) { |
| //TODO could avoid boxing |
| property.setValue(msg.getNewValue()); |
| } |
| } |
| } |
| |
| @Override |
| public void setTarget(Notifier newTarget) { |
| super.setTarget(newTarget); |
| } |
| } |
| |
| @Override |
| public BooleanProperty getBooleanProperty(EStructuralFeature feature) { |
| if( feature.isMany() ) { |
| throw new IllegalArgumentException("Feature is multi valued"); //$NON-NLS-1$ |
| } |
| if(feature.getEType().getInstanceClass() == boolean.class) { |
| return (BooleanProperty) this.map.computeIfAbsent(feature, f -> new BooleanPropertyImpl<>(this, f, this.ed)); |
| } else { |
| throw new IllegalAccessError("The feature type is not boolean.class"); //$NON-NLS-1$ |
| } |
| } |
| |
| @Override |
| public DoubleProperty getDoubleProperty(EStructuralFeature feature) { |
| if( feature.isMany() ) { |
| throw new IllegalArgumentException("Feature is multi valued"); //$NON-NLS-1$ |
| } |
| if(feature.getEType().getInstanceClass() == double.class) { |
| return (DoubleProperty) this.map.computeIfAbsent(feature, f -> new DoublePropertyImpl<>(this, f, this.ed)); |
| } else { |
| throw new IllegalAccessError("The feature type is not double.class"); //$NON-NLS-1$ |
| } |
| } |
| |
| @Override |
| public FloatProperty getFloatProperty(EStructuralFeature feature) { |
| if( feature.isMany() ) { |
| throw new IllegalArgumentException("Feature is multi valued"); //$NON-NLS-1$ |
| } |
| if(feature.getEType().getInstanceClass() == float.class) { |
| return (FloatProperty) this.map.computeIfAbsent(feature, f -> new FloatPropertyImpl<>(this, f, this.ed)); |
| } else { |
| throw new IllegalAccessError("The feature type is not float.class"); //$NON-NLS-1$ |
| } |
| } |
| |
| @Override |
| public IntegerProperty getIntegerProperty(EStructuralFeature feature) { |
| if( feature.isMany() ) { |
| throw new IllegalArgumentException("Feature is multi valued"); //$NON-NLS-1$ |
| } |
| if(feature.getEType().getInstanceClass() == int.class) { |
| return (IntegerProperty) this.map.computeIfAbsent(feature, f -> new IntegerPropertyImpl<>(this, f, this.ed)); |
| } else { |
| throw new IllegalAccessError("The feature type is not float.class"); //$NON-NLS-1$ |
| } |
| } |
| |
| @Override |
| public LongProperty getLongProperty(EStructuralFeature feature) { |
| if( feature.isMany() ) { |
| throw new IllegalArgumentException("Feature is multi valued"); //$NON-NLS-1$ |
| } |
| if(feature.getEType().getInstanceClass() == long.class) { |
| return (LongProperty) this.map.computeIfAbsent(feature, f -> new LongPropertyImpl<>(this, f, this.ed)); |
| } else { |
| throw new IllegalAccessError("The feature type is not float.class"); //$NON-NLS-1$ |
| } |
| } |
| |
| @Override |
| public <T> ObjectProperty<T> getObjectProperty(Class<T> type, EStructuralFeature feature) { |
| if( feature.isMany() ) { |
| throw new IllegalArgumentException("Feature is multi valued"); //$NON-NLS-1$ |
| } |
| |
| if( feature instanceof EReference ) { |
| return (ObjectProperty<T>) map.computeIfAbsent(feature, f -> new ObjectPropertyImpl<>(this, f, ed)); |
| } else { |
| Class<?> t = feature.getEType().getInstanceClass(); |
| if( t == String.class |
| || t == int.class |
| || t == long.class |
| || t == double.class |
| || t == float.class |
| || t == boolean.class) { |
| throw new IllegalArgumentException("Feature holds a primitive value"); |
| } else { |
| return new ObjectPropertyImpl<>(this, feature, this.ed); |
| } |
| } |
| } |
| |
| @Override |
| public StringProperty getStringProperty(EStructuralFeature feature) { |
| if( feature.isMany() ) { |
| throw new IllegalArgumentException("Feature is multi valued"); //$NON-NLS-1$ |
| } |
| if(feature.getEType().getInstanceClass() == String.class) { |
| return (StringProperty) this.map.computeIfAbsent(feature, f -> new StringPropertyImpl<>(this, f, this.ed)); |
| } else { |
| throw new IllegalAccessError("The feature type is not String.class"); //$NON-NLS-1$ |
| } |
| } |
| |
| static class ObjectPropertyImpl<@NonNull O extends EObject, V> extends SimpleObjectProperty<V> implements EProperty<O, V> { |
| private final AdaptedEObject<O> adapter; |
| private final EStructuralFeature f; |
| private final EditingDomain ed; |
| |
| public ObjectPropertyImpl(AdaptedEObject<O> adapter, EStructuralFeature f, EditingDomain ed) { |
| this.adapter = adapter; |
| this.f = f; |
| this.ed = ed; |
| set(((V) this.adapter.eo.eGet(this.f))); |
| } |
| |
| @Override |
| public O getBean() { |
| return this.adapter.eo; |
| } |
| |
| @Override |
| public EStructuralFeature getFeature() { |
| return this.f; |
| } |
| |
| @Override |
| public String getName() { |
| return this.f.getName(); |
| } |
| |
| @Override |
| public void unbind() { |
| super.unbind(); |
| set(((V) this.adapter.eo.eGet(this.f))); |
| } |
| |
| @Override |
| protected void invalidated() { |
| super.invalidated(); |
| |
| V value = get(); |
| if( this.adapter.eo.eGet(this.f) != value ) { |
| if( this.ed == null ) { |
| this.adapter.eo.eSet(this.f, value); |
| } else { |
| Command command = SetCommand.create(this.ed, this.adapter.eo, this.f, value); |
| if( command.canExecute() ) { |
| this.ed.getCommandStack().execute(command); |
| } |
| } |
| } |
| } |
| } |
| |
| static class BooleanPropertyImpl<@NonNull O extends EObject> extends SimpleBooleanProperty implements EProperty<O, Boolean> { |
| private final AdaptedEObject<O> adapter; |
| private final EStructuralFeature f; |
| private final EditingDomain ed; |
| |
| public BooleanPropertyImpl(AdaptedEObject<O> adapter, EStructuralFeature f, EditingDomain ed) { |
| this.adapter = adapter; |
| this.f = f; |
| this.ed = ed; |
| set(((Boolean) this.adapter.eo.eGet(this.f)).booleanValue()); |
| } |
| |
| @Override |
| public O getBean() { |
| return this.adapter.eo; |
| } |
| |
| @Override |
| public EStructuralFeature getFeature() { |
| return this.f; |
| } |
| |
| @Override |
| public String getName() { |
| return this.f.getName(); |
| } |
| |
| @Override |
| public void unbind() { |
| super.unbind(); |
| set(((Boolean) this.adapter.eo.eGet(this.f)).booleanValue()); |
| } |
| |
| @Override |
| protected void invalidated() { |
| super.invalidated(); |
| |
| boolean value = get(); |
| if( ((Boolean) this.adapter.eo.eGet(this.f)).booleanValue() != value ) { |
| if( this.ed == null ) { |
| this.adapter.eo.eSet(this.f, Boolean.valueOf(value)); |
| } else { |
| Command command = SetCommand.create(this.ed, this.adapter.eo, this.f, Boolean.valueOf(value)); |
| if( command.canExecute() ) { |
| this.ed.getCommandStack().execute(command); |
| } |
| } |
| } |
| } |
| } |
| |
| static class FloatPropertyImpl<@NonNull O extends EObject> extends SimpleFloatProperty implements EProperty<O, Number> { |
| private final AdaptedEObject<O> adapter; |
| private final EStructuralFeature f; |
| private final EditingDomain ed; |
| |
| public FloatPropertyImpl(AdaptedEObject<O> adapter, EStructuralFeature f, EditingDomain ed) { |
| this.adapter = adapter; |
| this.f = f; |
| this.ed = ed; |
| set(((Float) this.adapter.eo.eGet(this.f)).floatValue()); |
| } |
| |
| @Override |
| public O getBean() { |
| return this.adapter.eo; |
| } |
| |
| @Override |
| public EStructuralFeature getFeature() { |
| return this.f; |
| } |
| |
| @Override |
| public String getName() { |
| return this.f.getName(); |
| } |
| |
| @Override |
| public void unbind() { |
| super.unbind(); |
| set(((Float) this.adapter.eo.eGet(this.f)).floatValue()); |
| } |
| |
| @Override |
| protected void invalidated() { |
| super.invalidated(); |
| |
| float value = get(); |
| if( ((Float) this.adapter.eo.eGet(this.f)).floatValue() != value ) { |
| if( this.ed == null ) { |
| this.adapter.eo.eSet(this.f, Float.valueOf(value)); |
| } else { |
| Command command = SetCommand.create(this.ed, this.adapter.eo, this.f, Float.valueOf(value)); |
| if( command.canExecute() ) { |
| this.ed.getCommandStack().execute(command); |
| } |
| } |
| } |
| } |
| } |
| |
| static class LongPropertyImpl<@NonNull O extends EObject> extends SimpleLongProperty implements EProperty<O, Number> { |
| private final AdaptedEObject<O> adapter; |
| private final EStructuralFeature f; |
| private final EditingDomain ed; |
| |
| public LongPropertyImpl(AdaptedEObject<O> adapter, EStructuralFeature f, EditingDomain ed) { |
| this.adapter = adapter; |
| this.f = f; |
| this.ed = ed; |
| set(((Long) this.adapter.eo.eGet(this.f)).longValue()); |
| } |
| |
| @Override |
| public O getBean() { |
| return this.adapter.eo; |
| } |
| |
| @Override |
| public EStructuralFeature getFeature() { |
| return this.f; |
| } |
| |
| @Override |
| public String getName() { |
| return this.f.getName(); |
| } |
| |
| @Override |
| public void unbind() { |
| super.unbind(); |
| set(((Long) this.adapter.eo.eGet(this.f)).longValue()); |
| } |
| |
| @Override |
| protected void invalidated() { |
| super.invalidated(); |
| |
| long value = get(); |
| if( ((Long) this.adapter.eo.eGet(this.f)).longValue() != value ) { |
| if( this.ed == null ) { |
| this.adapter.eo.eSet(this.f, Long.valueOf(value)); |
| } else { |
| Command command = SetCommand.create(this.ed, this.adapter.eo, this.f, Long.valueOf(value)); |
| if( command.canExecute() ) { |
| this.ed.getCommandStack().execute(command); |
| } |
| } |
| } |
| } |
| } |
| |
| static class IntegerPropertyImpl<@NonNull O extends EObject> extends SimpleIntegerProperty implements EProperty<O, Number> { |
| private final AdaptedEObject<O> adapter; |
| private final EStructuralFeature f; |
| private final EditingDomain ed; |
| |
| public IntegerPropertyImpl(AdaptedEObject<O> adapter, EStructuralFeature f, EditingDomain ed) { |
| this.adapter = adapter; |
| this.f = f; |
| this.ed = ed; |
| set(((Integer) this.adapter.eo.eGet(this.f)).intValue()); |
| } |
| |
| @Override |
| public O getBean() { |
| return this.adapter.eo; |
| } |
| |
| @Override |
| public EStructuralFeature getFeature() { |
| return this.f; |
| } |
| |
| @Override |
| public String getName() { |
| return this.f.getName(); |
| } |
| |
| @Override |
| public void unbind() { |
| super.unbind(); |
| set(((Integer) this.adapter.eo.eGet(this.f)).intValue()); |
| } |
| |
| @Override |
| protected void invalidated() { |
| super.invalidated(); |
| |
| int value = get(); |
| if( ((Integer) this.adapter.eo.eGet(this.f)).intValue() != value ) { |
| if( this.ed == null ) { |
| this.adapter.eo.eSet(this.f, Integer.valueOf(value)); |
| } else { |
| Command command = SetCommand.create(this.ed, this.adapter.eo, this.f, Integer.valueOf(value)); |
| if( command.canExecute() ) { |
| this.ed.getCommandStack().execute(command); |
| } |
| } |
| } |
| } |
| } |
| |
| static class DoublePropertyImpl<@NonNull O extends EObject> extends SimpleDoubleProperty implements EProperty<O, Number> { |
| private final AdaptedEObject<O> adapter; |
| private final EStructuralFeature f; |
| private final EditingDomain ed; |
| |
| public DoublePropertyImpl(AdaptedEObject<O> adapter, EStructuralFeature f, EditingDomain ed) { |
| this.adapter = adapter; |
| this.f = f; |
| this.ed = ed; |
| set(((Double) this.adapter.eo.eGet(this.f)).doubleValue()); |
| } |
| |
| @Override |
| public O getBean() { |
| return this.adapter.eo; |
| } |
| |
| @Override |
| public EStructuralFeature getFeature() { |
| return this.f; |
| } |
| |
| @Override |
| public String getName() { |
| return this.f.getName(); |
| } |
| |
| @Override |
| public void unbind() { |
| super.unbind(); |
| set(((Double) this.adapter.eo.eGet(this.f)).doubleValue()); |
| } |
| |
| @Override |
| protected void invalidated() { |
| super.invalidated(); |
| |
| double value = get(); |
| if( ((Double) this.adapter.eo.eGet(this.f)).doubleValue() != value ) { |
| if( this.ed == null ) { |
| this.adapter.eo.eSet(this.f, Double.valueOf(value)); |
| } else { |
| Command command = SetCommand.create(this.ed, this.adapter.eo, this.f, Double.valueOf(value)); |
| if( command.canExecute() ) { |
| this.ed.getCommandStack().execute(command); |
| } |
| } |
| } |
| } |
| } |
| |
| static class StringPropertyImpl<@NonNull O extends EObject> extends SimpleStringProperty implements EProperty<O, String> { |
| private final AdaptedEObject<O> adapter; |
| private final EStructuralFeature f; |
| private final EditingDomain ed; |
| |
| public StringPropertyImpl(AdaptedEObject<O> adapter, EStructuralFeature f, EditingDomain ed) { |
| this.adapter = adapter; |
| this.f = f; |
| this.ed = ed; |
| set((String) adapter.eo.eGet(f)); |
| } |
| |
| @Override |
| public O getBean() { |
| return this.adapter.eo; |
| } |
| |
| @Override |
| public EStructuralFeature getFeature() { |
| return this.f; |
| } |
| |
| @Override |
| public String getName() { |
| return this.f.getName(); |
| } |
| |
| @Override |
| public void unbind() { |
| super.unbind(); |
| set((String) this.adapter.eo.eGet(this.f)); |
| } |
| |
| @Override |
| protected void invalidated() { |
| super.invalidated(); |
| |
| String value = get(); |
| if( this.adapter.eo.eGet(this.f) != value ) { |
| if( this.ed == null ) { |
| this.adapter.eo.eSet(this.f, value); |
| } else { |
| Command command = SetCommand.create(this.ed, this.adapter.eo, this.f, value); |
| if( command.canExecute() ) { |
| this.ed.getCommandStack().execute(command); |
| } |
| } |
| } |
| } |
| } |
| } |