/*****************************************************************************
* Copyright (c) 2009 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:
* Remi Schnekenburger (CEA LIST) remi.schnekenburger@cea.fr - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.diagram.common.service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gmf.runtime.diagram.core.edithelpers.CreateElementRequestAdapter;
import org.eclipse.gmf.runtime.diagram.core.listener.DiagramEventBroker;
import org.eclipse.gmf.runtime.diagram.core.listener.NotificationListener;
import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramCommandStack;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateUnspecifiedTypeRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewAndElementRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewAndElementRequest.ViewAndElementDescriptor;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest.ViewDescriptor;
import org.eclipse.gmf.runtime.diagram.ui.tools.UnspecifiedTypeCreationTool;
import org.eclipse.gmf.runtime.diagram.ui.util.INotationType;
import org.eclipse.gmf.runtime.emf.type.core.IElementType;
import org.eclipse.gmf.runtime.emf.type.core.IHintedType;
import org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.infra.core.services.ServiceException;
import org.eclipse.papyrus.infra.core.utils.EditorUtils;
import org.eclipse.papyrus.uml.diagram.common.Activator;
import org.eclipse.papyrus.uml.diagram.common.service.palette.AspectToolService;
import org.eclipse.papyrus.uml.diagram.common.service.palette.IAspectAction;
import org.eclipse.papyrus.uml.diagram.common.service.palette.IAspectActionProvider;
import org.eclipse.papyrus.uml.diagram.common.service.palette.IFeatureSetterAspectAction;
import org.w3c.dom.NodeList;
/**
* Creation tool that adds stereotype application after creation actions.
*/
public class AspectUnspecifiedTypeCreationTool extends UnspecifiedTypeCreationTool {
/**
* List of element types of which one will be created (of type <code>IElementType</code>).
*/
protected List<IElementType> elementTypes;
/** post action list */
protected List<IAspectAction> postActions = new ArrayList<IAspectAction>();
private static String ID_ASPECT_ACTION = "palette_aspect_actions" ;
/**
* Creates an AspectUnspecifiedTypeCreationTool
*
* @param elementTypes
* List of element types of which one will be created (of type <code>IElementType</code>).
*/
public AspectUnspecifiedTypeCreationTool(List<IElementType> elementTypes) {
super(elementTypes);
this.elementTypes = elementTypes;
}
/**
* {@inheritDoc}
*/
@Override
protected void performCreation(int button) {
antiScroll = true;
boolean requiresPostAction = requiresPostAction();
// EObject to listen
View eObject = (View)getTargetEditPart().getAdapter(View.class);
DiagramEventBroker eventBroker = null;
NotificationListener listener = null;
if(requiresPostAction) {
// register a listener to have information about element creation
// retrieves editing domain
TransactionalEditingDomain domain;
try {
domain = EditorUtils.getServiceRegistry().getService(TransactionalEditingDomain.class);
eventBroker = DiagramEventBroker.getInstance(domain);
if(eventBroker == null) {
return;
}
listener = new NotificationListener() {
public void notifyChanged(Notification notification) {
Object newValue = notification.getNewValue();
EditPartViewer viewer = getCurrentViewer();
if(viewer == null) {
viewer = (getTargetEditPart() != null) ? getTargetEditPart().getViewer() : null;
}
if(viewer != null) {
EditPart editPart = (EditPart)getCurrentViewer().getEditPartRegistry().get(newValue);
for(IAspectAction action : postActions) {
action.run(editPart);
}
} else {
Activator.log.error("Impossible to find the current viewer", null);
}
}
};
eventBroker.addNotificationListener(eObject, listener);
} catch (ServiceException e) {
Activator.log.error(e);
}
}
EditPartViewer viewer = getCurrentViewer();
Command c = getCurrentCommand();
executeCurrentCommand();
if(requiresPostAction) {
if(eventBroker != null) {
eventBroker.removeNotificationListener(eObject, listener);
}
}
selectAddedObject(viewer, DiagramCommandStack.getReturnValues(c));
antiScroll = false;
}
/**
* checks if this tool realizes post actions
*
* @return <code>true</code> if post actions must be executed
*/
protected boolean requiresPostAction() {
return postActions.size() > 0;
}
/**
* {@inheritDoc}
*/
@Override
protected void applyProperty(Object key, Object value) {
if(IPapyrusPaletteConstant.ASPECT_ACTION_KEY.equals(key)) {
// initialize the pre and post actions
// the value should be a NodeList
if(value instanceof NodeList) {
NodeList nodeList = ((NodeList)value);
for(int i = 0; i < nodeList.getLength(); i++) {
org.w3c.dom.Node childNode = nodeList.item(i);
String childName = childNode.getNodeName();
if(IPapyrusPaletteConstant.POST_ACTION.equals(childName)) {
// node is a post action => retrieve the id of the
// factory in charge of this configuration
// node is a post action => retrieve the id of the
// provider in charge of this configuration
IAspectActionProvider provider = AspectToolService.getInstance().getProvider(AspectToolService.getProviderId(childNode));
if(provider != null) {
IAspectAction action = provider.createAction(childNode);
postActions.add(action);
} else {
Activator.log.error("impossible to find factory with id: " + AspectToolService.getProviderId(childNode), null);
}
} else if(IPapyrusPaletteConstant.PRE_ACTION.equals(childName)) {
// no implementation yet
}
}
}
return;
}
super.applyProperty(key, value);
}
/**
* Returns the list of element types
*
* @return the list of element types
*/
public List<IElementType> getElementTypes() {
return elementTypes;
}
/**
* {@inheritDoc}
*/
@Override
protected Request createTargetRequest() {
CreateAspectUnspecifiedTypeRequest request = new CreateAspectUnspecifiedTypeRequest(getElementTypes(), getPreferencesHint());
request.getExtendedData().put(ID_ASPECT_ACTION, postActions);
return request ;
}
@SuppressWarnings("unchecked")
public static List<IAspectAction> getAspectActions(Request request)
{
return (List<IAspectAction>) (request == null ? Collections.emptyList() : getAspectActions(request.getExtendedData()));
}
@SuppressWarnings("unchecked")
public static List<IAspectAction> getAspectActions(Map map)
{
return (List<IAspectAction>) (map == null ? Collections.emptyList() : map.get(ID_ASPECT_ACTION));
}
public String createPrePostActionRepresentation ()
{
StringBuffer buffer = new StringBuffer();
boolean flag = false ;
for (IAspectAction post : postActions)
{
if (post instanceof IFeatureSetterAspectAction) {
IFeatureSetterAspectAction featureSetter = (IFeatureSetterAspectAction) post;
if (flag)
{
buffer.append("|");
for (EStructuralFeature f : featureSetter.getAllImpactedFeatures()) {
EClass eClass = f.eClass();
buffer.append(eClass.getEPackage().getNsURI());
buffer.append(",");
buffer.append(eClass.getName());
buffer.append(",");
buffer.append(f.getName());
}
}
flag = true ;
}
}
return buffer.toString();
}
public class CreateAspectUnspecifiedTypeRequest extends CreateUnspecifiedTypeRequest {
/**
* Constructor.
*
* @param elementTypes
* @param preferencesHint
*/
public CreateAspectUnspecifiedTypeRequest(List<IElementType> elementTypes, PreferencesHint preferencesHint) {
super(elementTypes, preferencesHint);
}
/**
* Creates a <code>CreateViewRequest</code> or <code>CreateViewAndElementRequest</code> for each creation hint and
* adds it to the map of requests.
*/
@Override
protected void createRequests() {
for(Iterator<IElementType> iter = elementTypes.iterator(); iter.hasNext();) {
IElementType elementType = iter.next();
Request request = null;
if(elementType instanceof INotationType) {
ViewDescriptor viewDescriptor = new ViewDescriptor(null, Node.class, ((INotationType)elementType).getSemanticHint(), getPreferencesHint());
request = new CreateViewRequest(viewDescriptor);
} else if(elementType instanceof IHintedType) {
ViewAndElementDescriptor viewDescriptor = new ViewAndElementDescriptor(new CreateElementRequestAdapter(new CreateElementRequest(elementType)), Node.class, getGraphicalHint((IHintedType)elementType), getPreferencesHint());
request = new CreateViewAndElementRequest(viewDescriptor);
request.setExtendedData(getExtendedData());
} else {
ViewAndElementDescriptor viewDescriptor = new ViewAndElementDescriptor(new CreateElementRequestAdapter(new CreateElementRequest(elementType)), Node.class, getPreferencesHint());
request = new CreateViewAndElementRequest(viewDescriptor);
request.setExtendedData(getExtendedData());
}
request.setType(getType());
requests.put(elementType, request);
}
}
/**
* Returns the semantic hint for the given type. In case of extended
* type, it returns the hint of the super type
*
* @param elementType
* the hinted element type from which hint is retrieved
* @return
*/
protected String getGraphicalHint(IHintedType elementType) {
String hint = elementType.getSemanticHint();
return hint;
}
}
}