/***************************************************************************** * Copyright (c) 2011 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.infra.emf.databinding; import org.eclipse.core.databinding.observable.value.AbstractObservableValue; import org.eclipse.emf.common.command.AbstractCommand; import org.eclipse.emf.common.command.Command; import org.eclipse.emf.common.command.CompoundCommand; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EModelElement; import org.eclipse.emf.ecore.EcoreFactory; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.edit.command.SetCommand; import org.eclipse.emf.edit.domain.EditingDomain; /** * An IObservableValue for editing EMF EAnnotations * * @author Camille Letavernier */ public class AnnotationObservableValue extends AbstractObservableValue { /** * The EModelElement to edit. */ protected EModelElement source; /** * The editing domain on which the commands will be executed */ protected EditingDomain domain; /** * The name of the annotation to use */ protected String annotationName; /** * The annotation key to edit */ protected String key; /** * Whether the EAnnotation should be removed from the source when its last * entry is removed (ie. value = null) */ protected boolean deleteWithLastEntry; /** * Constructor. * * Creates an IObservableValue for the annotation. The annotation doesn't * need to be created beforehand * * @param source * The EObject owning the annotation * @param domain * The editing domain on which the commands will be executed * @param annotationName * The name of the annotation * @param key * The name of annotation's property to edit */ public AnnotationObservableValue(EModelElement source, EditingDomain domain, String annotationName, String key) { this(source, domain, annotationName, key, false); } /** * Constructor. * * Creates an IObservableValue for the annotation. The annotation doesn't * need to be created beforehand * * @param source * The EObject owning the annotation * @param domain * The editing domain on which the commands will be executed * @param annotationName * The name of the annotation * @param key * The name of annotation's property to edit * @param deleteWithLastEntry * Whether the EAnnotation should be removed from the source when its * last entry is removed (ie. value = null) */ public AnnotationObservableValue(EModelElement source, EditingDomain domain, String annotationName, String key, boolean deleteWithLastEntry) { this.source = source; this.domain = domain; this.annotationName = annotationName; this.key = key; this.deleteWithLastEntry = deleteWithLastEntry; } /** * {@inheritDoc} */ public Object getValueType() { return String.class; } /** * {@inheritDoc} */ @Override protected Object doGetValue() { EAnnotation annotation = getEAnnotation(); if(annotation == null) { return null; } return annotation.getDetails().get(key); } /** * @return the observed EAnnotation */ protected EAnnotation getEAnnotation() { return source.getEAnnotation(annotationName); } /** * {@inheritDoc} */ @Override protected void doSetValue(Object value) { Command emfCommand = getCommand(value); if(emfCommand != null) { domain.getCommandStack().execute(emfCommand); } } /** * Returns the command used to edit the observed annotation, which the * given value * * @param value * @return */ protected Command getCommand(Object value) { EAnnotation annotation = getEAnnotation(); if(value == null) { //No change : the key is not defined ; we cannot remove it if(annotation == null || !annotation.getDetails().containsKey(key)) { return null; } } else { if(!(value instanceof String)) { return null; } } CompoundCommand emfCommand = new CompoundCommand("Set " + key) { @Override public boolean prepare() { if(this.isEmpty()) { return false; } return commandList.get(0).canExecute(); } }; if(annotation == null) { annotation = EcoreFactory.eINSTANCE.createEAnnotation(); SetCommand attachToSourceCommand = new SetCommand(domain, annotation, EcorePackage.eINSTANCE.getEAnnotation_EModelElement(), source); attachToSourceCommand.setLabel("Attach to source"); emfCommand.append(attachToSourceCommand); SetCommand nameCommand = new SetCommand(domain, annotation, EcorePackage.eINSTANCE.getEAnnotation_Source(), annotationName); nameCommand.setLabel("Set name"); emfCommand.append(nameCommand); } if(value == null) { if(annotation.getDetails().size() == 1 && annotation.getDetails().containsKey(key) && deleteWithLastEntry) { //We removed the last key : delete the annotation SetCommand deleteAnnotationCommand = new SetCommand(domain, annotation, EcorePackage.eINSTANCE.getEAnnotation_EModelElement(), null); deleteAnnotationCommand.setLabel("Delete EAnnotation"); emfCommand.append(deleteAnnotationCommand); } else { Command removeEntryCommand = new RemoveEntryCommand(annotation, key); emfCommand.append(removeEntryCommand); } } else { Command addEntryCommand = new AddEntryCommand(annotation, key, (String)value); emfCommand.append(addEntryCommand); } return emfCommand; } /** * A Command to remove an entry from an EAnnotation * * @author Camille Letavernier * */ protected class RemoveEntryCommand extends AbstractCommand { private EAnnotation annotation; private String key; private String previousValue; private boolean undo = false; /** * Constructor * * @param annotation * The EAnnotation to edit * @param key * The EAnnotation's key to edit */ public RemoveEntryCommand(EAnnotation annotation, String key) { this.annotation = annotation; this.key = key; } public void execute() { undo = annotation.getDetails().containsKey(key); if(undo) { previousValue = annotation.getDetails().get(key); annotation.getDetails().remove(key); } } public void redo() { execute(); } @Override public boolean prepare() { return true; } @Override public void undo() { if(undo) { annotation.getDetails().put(key, previousValue); } } } /** * A Command to set an EAnnotation's entry * * @author Camille Letavernier */ protected class AddEntryCommand extends AbstractCommand { private EAnnotation annotation; private String key; private String value; /** * * * @param annotation * The EAnnotation to edit * @param key * The EAnnotation's key to edit * @param value * The value to set */ public AddEntryCommand(EAnnotation annotation, String key, String value) { this.annotation = annotation; this.key = key; this.value = value; } public void execute() { annotation.getDetails().put(key, value); } public void redo() { execute(); } @Override public void undo() { annotation.getDetails().remove(key); } @Override public boolean prepare() { return true; } } }