/***************************************************************************** * Copyright (c) 2010 CEA LIST. * * 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: * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation *****************************************************************************/ package org.eclipse.papyrus.uml.tools.databinding; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import org.eclipse.core.databinding.observable.ChangeEvent; import org.eclipse.core.databinding.observable.Diffs; import org.eclipse.core.databinding.observable.IChangeListener; import org.eclipse.core.databinding.observable.IObservable; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.value.AbstractObservableValue; import org.eclipse.emf.common.command.Command; import org.eclipse.emf.common.command.CompoundCommand; import org.eclipse.emf.common.command.UnexecutableCommand; import org.eclipse.emf.databinding.EMFProperties; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.gmf.runtime.common.core.command.ICommand; import org.eclipse.gmf.runtime.emf.type.core.requests.SetRequest; import org.eclipse.papyrus.commands.wrappers.GMFtoEMFCommandWrapper; import org.eclipse.papyrus.infra.services.edit.service.ElementEditServiceUtils; import org.eclipse.papyrus.infra.services.edit.service.IElementEditService; import org.eclipse.papyrus.infra.tools.databinding.AggregatedObservable; import org.eclipse.uml2.uml.Association; import org.eclipse.uml2.uml.Classifier; import org.eclipse.uml2.uml.Property; import org.eclipse.uml2.uml.UMLPackage; /** * An ObservableValue for manipulating the UML Navigable property. * The navigable property is a virtual property, represented as a Boolean. * * @author Camille Letavernier */ public class NavigationObservableValue extends AbstractObservableValue implements IChangeListener, CommandBasedObservableValue, AggregatedObservable { private Property memberEnd; private EditingDomain domain; private final IObservableList ownerObservableList; private boolean currentValue; /** * Constructor. * * @param source * The EObject (Property) which the navigability is being edited * @param domain * The Editing Domain on which the commands will be executed */ public NavigationObservableValue(EObject source, EditingDomain domain) { memberEnd = (Property)source; this.domain = domain; ownerObservableList = EMFProperties.list(UMLPackage.eINSTANCE.getAssociation_OwnedEnd()).observe(memberEnd.getAssociation()); ownerObservableList.addChangeListener(this); } public void handleChange(ChangeEvent event) { fireValueChange(Diffs.createValueDiff(currentValue, doGetValue())); } public Object getValueType() { return Boolean.class; } @Override protected Boolean doGetValue() { return memberEnd.isNavigable(); } @Override protected void doSetValue(Object value) { Command command = getCommand(value); domain.getCommandStack().execute(command); } @Override public synchronized void dispose() { super.dispose(); ownerObservableList.removeChangeListener(this); ownerObservableList.dispose(); } public Command getCommand(Object value) { if(value instanceof Boolean) { boolean isNavigable = (Boolean)value; if(memberEnd.isNavigable() == isNavigable) { return UnexecutableCommand.INSTANCE; } Association association = memberEnd.getAssociation(); List<Property> navigableEnds = new ArrayList<Property>(); navigableEnds.addAll(association.getNavigableOwnedEnds()); List<SetRequest> setRequests = new LinkedList<SetRequest>(); if(isNavigable) { navigableEnds.add(memberEnd); } else { if(memberEnd.getOwningAssociation() == null && memberEnd.getOwner() instanceof Classifier) { List<Property> ownedEnds = new LinkedList<Property>(); ownedEnds.addAll(association.getOwnedEnds()); ownedEnds.add(memberEnd); setRequests.add(new SetRequest(association, UMLPackage.eINSTANCE.getAssociation_OwnedEnd(), ownedEnds)); } if(navigableEnds.contains(memberEnd)) { navigableEnds.remove(memberEnd); } } EStructuralFeature navigableFeature = UMLPackage.eINSTANCE.getAssociation_NavigableOwnedEnd(); setRequests.add(new SetRequest(association, navigableFeature, navigableEnds)); CompoundCommand command = null; IElementEditService provider = ElementEditServiceUtils.getCommandProvider(association); if(provider != null) { command = new CompoundCommand(); for(SetRequest request : setRequests) { ICommand createGMFCommand = provider.getEditCommand(request); command.append(new GMFtoEMFCommandWrapper(createGMFCommand)); } } currentValue = isNavigable; return command; } return UnexecutableCommand.INSTANCE; } public AggregatedObservable aggregate(IObservable observable) { try { return new AggregatedPapyrusObservableValue(domain, this, observable); } catch (IllegalArgumentException ex) { return null; //The observable cannot be aggregated } } public boolean hasDifferentValues() { return false; } }